Pygame UI clearing and updating - python

At the request of Furas, below are the segments of code in a Pygame Project that I'm currently working on. What I'm trying to get to happen is essentially like clearing everything visible on the previous window so I can start fresh with a new UI. When the code is run, and the "Start Game" button is pressed on the startup screen, the background colour updates, but everything that was previously rendered (the title and all of the buttons) remain on the screen. If anyone could offer any general pointers - or advice based off the code below - that would a great help!
The game_loop function:
This first part is where I need the screen to be cleared/updated. The game_loop contains more game logic, which is irrelevant to the current question, and what is pasted below is the only part of the function that interacts with the window.
new_surface = pygame.Surface((1,1))
def game_loop():
global clicked_game
global game_running
clicked_game = True
game_running = True
if clicked_game == True:
screen.fill( (0,0,0) )
screen.blit(new_surface, (0,0))
pygame.display.update()
User Interface Initialisation and Functions:
These are the rest of the functions which follow later on from the actual game logic in game_loop:
def quit_game():
pygame.quit()
quit()
def update_options():
global clicked_options
clicked_options = True
def button(window, msg, x_coord, y_coord, width, height, initial_colour, highlight_colour, button_action):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x_coord + width > mouse[0] > x_coord and y_coord + height > mouse[1] > y_coord:
pygame.draw.rect(window, highlight_colour, (x_coord, y_coord, width, height))
if click[0] == 1:
button_action()
else:
pygame.draw.rect(window, initial_colour, (x_coord, y_coord, width, height))
button_Text = pygame.font.Font("freesansbold.ttf",20)
text_Surf, text_Rect = text_objects(msg, button_Text)
text_Rect.center = ((x_coord + (width / 2)), (y_coord + (height / 2)))
window.blit(text_Surf, text_Rect)
while play:
for event in pygame.event.get():
if event.type == pygame.QUIT:
play = False
button(screen, "Start Game", 231, 236, 250, 50, e_m_light, e_m_lighter, game_loop)
button(screen, "Options", 231, 336, 250, 50, e_m_light, e_m_lighter, update_options)
button(screen, "Exit", 231, 436, 250, 50, e_m_light, e_m_lighter, quit_game)
if clicked_options == True:
#update title colour for testing purposes
text_Surface = Font1.render('BlackJack Blast!', True, e_m_lighter)
else:
text_Surface = Font1.render('BlackJack Blast!', True, white)
screen.blit(textSurface,(106,100))
pygame.display.update()
Screenshots of the UI before and after pressing "Start Game":
User Interface - Before
User Interface - After
I'm still a bit of a pygame novice, so if you're unsure of how to fix this specific problem, but recognise something else that could do with improving, or if you need any more information to develop a solution, please let me know!

You blit all buttons all the times - in every loop - so why the shoud disaper ?
You can use variables like display_menu = True, display_game = True, display_options = False to control what elements display - silimiar to clicked_options.
But cleaner is to create separated while True loop for every scene - Menu, Game, Option.
You can use functions like in example: https://stackoverflow.com/a/47460947/1832058
It uses front_page(), menu() to run different while True loops for two different scenes.
Or you can create classes for differnt scenes/stages: stage-example
You can see this on image:

Related

Pygame window initiates frozen

I wrote a small code to try working with pygame for the first time, but I'm having trouble getting the game window to respond to any input at all including the exit button. No matter if I run the code through Sublime, VScode, or Python the window loads fine but the sprite takes no input (so fare I have only coded left) nor will the window close. If I want to close the window I have to close whatever editor/terminal I'm running the program through
import pygame
import os
pygame.display.set_caption("CyberPunk 3077")
WIDTH, HEIGHT = 900, 500
PLAYER, SIZE = 34, 34
WIN = pygame.display.set_mode((WIDTH,HEIGHT))
'''We have now created the window and it's size
Now lets create the background display'''
FPS = 60
VELOCITY = 3
WHITE = ((255, 255, 255))
MID_BORDER = pygame.Rect((WIDTH/2)-2.5, 0,5, HEIGHT) #this will place a solid line in the middle of the screen
Player_1 = pygame.transform.scale(pygame.image.load(os.path.join('skins', 'player.png')), (PLAYER,SIZE))
P1 = pygame.transform.rotate(Player_1, 270)
Player_2 = pygame.transform.scale(pygame.image.load(os.path.join('skins', 'enemy.png')), (PLAYER,SIZE))
P2 = pygame.transform.rotate(Player_2, 270)
SKY = pygame.transform.scale(pygame.image.load(os.path.join('skins', 'bg.png')), (WIDTH,HEIGHT))
#this will search our folder 'skins' for the file 'bg' to make our background
def draw(yellow, blue):
WIN.blit(SKY, (0,0))
pygame.draw.rect(WIN, WHITE, MID_BORDER)
WIN.blit(P1, (yellow.y, yellow.y))
WIN.blit(P2, (blue.x, blue.y))
#pygame starts tracking at the top left with 0,0
pygame.display.update()
def P1_moves(keys_pressed, yellow):
if keys_pressed[pygame.K_a] and yellow.x - VELOCITY > 0: #LEFT
yellow.x -= VELOCITY
'''this is the only instance of movement I have coded so far. Didn't want to continue if I can't even get 'left' to work '''
def main():
yellow = pygame.Rect(200, 250, 32, 32)
blue = pygame.Rect(650, 250, 32, 32)
run = True
clock = pygame.time.Clock()
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run == False
keys_pressed = pygame.key.get_pressed()
P1_moves(keys_pressed, yellow)
draw(yellow, blue)
pygame.quit()
if __name__ == "__main__":
main()
The keys_pressed[pygame.K_a] should be keys_pressed[pygame.K_A] (capital 'A').
Rabbid76 answered this problem in a comment.
run = False instead of run == False
WIN.blit(P1, (yellow.x, yellow.y)) instead of WIN.blit(P1, (yellow.y, yellow.y))
Rabbid76 Sep 15 at 18:18

How to go to a new line in python while using unicode? [duplicate]

This question already has answers here:
Rendering text with multiple lines in pygame
(10 answers)
Python/Pygame make text in Pygame wrap when in leaves the window
(1 answer)
Closed 1 year ago.
Thanks for opening to help, I am a beginner programmer for a school major work and decided to do a checkout application. It isnt anything too fancy, most aspects are hard coded with some pieces being read from editable txt files. I am currently making the main system of the application where the user is able to select the item where it adds to their cart as well as checks to see if it is already in the cart to modify the cart as I don't want double ups on a piece of clothing.
###Tasks I am stuck on
I am not able to get it to write to a new line (around 234) where it should accept \n, it doesn't work, rather it displays a box as if it doesn't understand the character. Possibly could be the character system I am using but I am not too sure.
If something is in the cart and another thing is added, It isn't able to go back and modify what's already in the cart. (I am able to do it when nothing else is added after as It just replaces the text).
my teacher / project supervisor also said to add an admin function where they are able to modify the Items, prices and pictures(if I add any) through a txt file.
I am also wanting the cart to be on a scrolling screen that updates in size when necessary but this is an optional feature that I am going to look for tutorials unless one kind person can explain.
The top rectangles are meant to take to another page with more options to chose from and I can't think of how to code this bit.
I also kind of want date and time to be printed on the bottom right but this is a minor piece
I know its a lot but I've got until late June to complete everything. Any advice is appreciated as it is still a big work in progress and I am only new to the language. Please let me know if you need any other information related.
Thanks Heaps!!!!! #Edit : added the picture Picture of the screen as is
# window ----------------------------------------
"""
This file is the executable file which calls all other files including the
full application.
"""
#The following imports are modules which have prewritten
#functions which I am able to use. They came predownloaded
#with python as well as downloading some from pygame.org
import pygame, sys
import tkinter as tk
from tkinter import Tk, Canvas, Frame, BOTH
from tkinter import ttk
from tkinter import *
from collections import Counter as count
from datetime import datetime
import time
import string
#import read
mainClock = pygame.time.Clock()
#setting window
from pygame.locals import *
#The following are Constants which are defined here for easier maintanence
click = bool
pygame.init()
pygame.display.set_caption('LeVOGUE')
clock = pygame.time.Clock()
screen = pygame.display.set_mode((1200, 800), 0, 32)
windowSurface = pygame.display.set_mode((1200, 650), pygame.DOUBLEBUF)
run = 2
font = pygame.font.SysFont(None, 35)
font2 = pygame.font.SysFont(None, 70)
font3 = pygame.font.SysFont(None, 25)
base_font = pygame.font.Font(None, 50)
base_font2 = pygame.font.Font(None, 160)
Item = ''
Item_rect = pygame.Rect(780, 33, 400, 547)
Colour = pygame.Color(0,0,0)
found =False
#key_text_num = 2
s = " "
fh =open("user_info.txt", "r")
keys = pygame.key.get_pressed()
click = pygame.MOUSEBUTTONDOWN
Volume = True
active = False
#tick_active = False
#This is responsible fo importing the mixer module
from pygame import mixer
#Load music file
mixer.music.load("MainMenuMusic.mp3")
#play music file
mixer.music.play()
sc1_num = 0
sc1_price = 0
sc2_num = 0
sc2_price = 0
def Main_sales():
#this area of the code was reused from a previous file
#which is an example of the RAD approach.
#~~~~~~~~~~~~~~~~~Start Code applied from previous programs~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
global click
global Item
global active
global bags
global current_time
global found
global count
global s
global fh
global i_a
global key_text_num
global Item_rect
global sc1_num
global sc1_price
global sc2_num
global sc2_price
#This checkbox is imported from a module found within the LeVOGUE folder
#The checkbox file is imported above and called with the function checkbox
while True:
#Defining Quit
for event in pygame.event.get():
if event.type == QUIT:
print("Quit")
pygame.quit()
sys.exit()
#~~~~~~~~~~~~~~~~~~~~~~~~End Code applied from tutorial~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#if key escape key is pressed, Quit
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
#if click, click is true
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
click = True
if click:
print(pygame.mouse.get_pos())
#Background colour
screen.fill((255, 255, 255))
text_surface = font3.render(Item, True, (0,0,0))
screen.blit(text_surface, (Item_rect.x+20 , Item_rect.y +100))
#mouse position
mx, my = pygame.mouse.get_pos()
#This section of code was applied from a tutorial which I followed
#It was used to allow me to create rectangular buttons although it was
#heavily modified to add functionality to different buttons
#~~~~~~~~~~~~~~Start code applied from tutorial ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
b_w = 180
b_h = 70
b2_x = 274
b2_y = 562
b2_w = 140
b2_h = 65
b3_x = 55
b3_y = 200
b4_x = 275
b4_y = 200
b5_x = 490
b5_y = 200
b6_x = 55
b6_y = 290
b7_x = 275
b7_y = 290
b8_x = 490
b8_y = 290
b9_x = 55
b9_y = 380
b10_x = 275
b10_y = 380
b11_x = 490
b11_y = 380
b12_x = 55
b12_y = 470
b13_x = 275
b13_y = 470
b14_x = 490
b14_y = 470
button_2 = pygame.Rect(b2_x, b2_y, b2_w, b2_h)
button_3 = pygame.Rect( b3_x, b3_y ,b_w, b_h)
button_4 = pygame.Rect( b4_x, b4_y ,b_w, b_h)
button_5 = pygame.Rect( b5_x, b5_y ,b_w, b_h)
button_6 = pygame.Rect( b6_x, b6_y ,b_w, b_h)
button_7 = pygame.Rect( b7_x, b7_y ,b_w, b_h)
button_8 = pygame.Rect( b8_x, b8_y ,b_w, b_h)
button_9 = pygame.Rect( b9_x, b9_y ,b_w, b_h)
button_10 = pygame.Rect( b10_x, b10_y ,b_w, b_h)
button_11 = pygame.Rect( b11_x, b11_y ,b_w, b_h)
button_12 = pygame.Rect( b12_x, b12_y ,b_w, b_h)
button_13 = pygame.Rect( b13_x, b13_y ,b_w, b_h)
button_14 = pygame.Rect( b14_x, b14_y ,b_w, b_h)
#What happens if the mouse click is over buttons listed above
if button_2.collidepoint(mx, my):
if click:
print("button2")
import MainMenu
if button_3.collidepoint(mx, my):
if click:
#while (sc_num < 10):
if (f"Scrunchie {sc1_num} ${sc1_price} ") in Item:
Item = Item[:-29]
sc1_num = sc1_num+1
sc1_price = sc1_price+15
Item = Item + (f"Scrunchie {sc1_num} ${sc1_price} \n")
print(" Button3")
if button_4.collidepoint(mx, my):
if click:
if (f"Scrunchie {sc2_num} ${sc2_price}") in Item:
Item = Item[:-39]
sc2_num = sc2_num+1
sc2_price = sc2_price+15
Item = Item + (f"Scrunchie2 {sc2_num} ${sc2_price}")
print(" Button4")
if button_5.collidepoint(mx, my):
if click:
print(" Button5")
if button_6.collidepoint(mx, my):
if click:
print(" Button6")
if button_7.collidepoint(mx, my):
if click:
print(" Button7")
if button_8.collidepoint(mx, my):
if click:
print(" Button8")
if button_9.collidepoint(mx, my):
if click:
print(" Button9")
if button_10.collidepoint(mx, my):
if click:
print(" Button10")
if button_11.collidepoint(mx, my):
if click:
print(" Button11")
if button_12.collidepoint(mx, my):
if click:
print(" Button12")
if button_13.collidepoint(mx, my):
if click:
print(" Button13")
if button_14.collidepoint(mx, my):
if click:
print(" Button14")
text_surface_Cart = font.render("Cart", True, (0,0,0))
text_surface_Item = font.render( "Item Qty Price", True, (0,0,0))
screen.blit(text_surface_Cart, (790,50))
screen.blit(text_surface_Item, (790, 100))
#for Button 2
text_surface_Enter = font2.render("Enter", True, (0,0,0))
screen.blit(text_surface_Enter, pygame.Rect((280, 565), (120, 70)))
#Cart
pygame.draw.rect(screen,Colour,pygame.Rect(780,30,400,550),2)
#button 2; Enter
pygame.draw.rect(screen, Colour , button_2, 2)
#Draw boxes for the number buttons
pygame.draw.rect(screen, Colour, button_3, 2)
pygame.draw.rect(screen, Colour, button_4, 2)
pygame.draw.rect(screen, Colour, button_5, 2)
pygame.draw.rect(screen, Colour, button_6, 2)
pygame.draw.rect(screen, Colour, button_7, 2)
pygame.draw.rect(screen, Colour, button_8, 2)
pygame.draw.rect(screen, Colour, button_9, 2)
pygame.draw.rect(screen, Colour, button_10, 2)
pygame.draw.rect(screen, Colour, button_11, 2)
pygame.draw.rect(screen, Colour, button_12, 2)
pygame.draw.rect(screen, Colour, button_13, 2)
pygame.draw.rect(screen, Colour, button_14, 2)
screen.blit((font3.render("Scrunchie1", True, (0,0,0))),(b3_x+20, b3_y+15))
screen.blit((font3.render("Scrunchie2", True, (0,0,0))),(b4_x+20, b4_y+15))
screen.blit((font3.render("Scrunchie3", True, (0,0,0))),(b5_x+20, b5_y+15))
screen.blit((font3.render("Scrunchie4", True, (0,0,0))),(b6_x+20, b6_y+15))
screen.blit((font3.render("Scrunchie5", True, (0,0,0))),(b7_x+20, b7_y+15))
screen.blit((font3.render("Shirt6", True, (0,0,0))),(b8_x+20, b8_y+15))
screen.blit((font3.render("Shirt7", True, (0,0,0))),(b9_x+20, b9_y+15))
screen.blit((font3.render("Shirt8", True, (0,0,0))),(b10_x+20, b10_y+15))
screen.blit((font3.render("Shirt9", True, (0,0,0))),(b11_x+20, b11_y+15))
screen.blit((font3.render("Pants10", True, (0,0,0))),(b12_x+20, b12_y+15))
screen.blit((font3.render("Pants11", True, (0,0,0))),(b13_x+20, b13_y+15))
screen.blit((font3.render("Pants11", True, (0,0,0))),(b14_x+20, b14_y+15))
#~~~~~~~~~~~~~~~~~~ End Code applied from tutorial~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ButtonBolt = pygame.image.load("LionsHEAD.png")
ButtonBolt = pygame.transform.scale(ButtonBolt, (120, 120))
screen.blit(ButtonBolt, (20,15))
text_surface_LeVOGUE = font2.render("LeVOGUE", True, (0,0,0))
screen.blit(text_surface_LeVOGUE, (140,55))
Key_Rect = pygame.Rect(260, 125, 230, 40)
pygame.draw.rect(screen, (0,0,0) , Key_Rect, 2)
Left_select_Rect = pygame.Rect(208, 125, 40, 40)
pygame.draw.rect(screen, (0,0,0), Left_select_Rect , 2)
text_surface_Left_select = font2.render("<", True, (0,0,0))
screen.blit(text_surface_Left_select, (215,118))
Right_select_Rect = pygame.Rect(502, 125, 40, 40)
pygame.draw.rect(screen, (0,0,0), Right_select_Rect , 2)
text_surface_Left_select = font2.render(">", True, (0,0,0))
screen.blit(text_surface_Left_select, (510,118))
#CART
pygame.draw.rect(screen,Colour,pygame.Rect(780,30,400,550),2)
click = False
#update screen
pygame.display.update()
pygame.display.flip()
mainClock.tick(60)
#The following code was derived from a tutorial which allows the application
#to quit without causing any error codes.
#~~~~~~~~~~~~Start code applied from tutorial~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def Quit():
running = True
while running:
pygame.quit()
quit()
#~~~~~~~~~~~ End Code applied from tutorial~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#run the main menu
Main_sales()
pygame.quit()
sys.exit()
In your line
text_surface = font3.render(Item, True, (0,0,0))
You're using the pygame font renderer. The pygame.font.Font/SysFont().render() does not support multiple line text.
This is stated in the documentation here.
The text can only be a single line: newline characters are not rendered.

Why text display for 2 seconds in pygame

Text wchich I display is displaying for only around 2 sec. I want that it will display while I click to other area
elif msg[0:7] == 'YOU WIN' and Message_id == '200':
print('You Win')
textSurface = font.render('You Win', True, (0, 0, 0))
largeText = pygame.font.Font('freesansbold.ttf', 115)
TextSurf = pygame.font.render('You Win', True, (0, 0, 0))
TextRect = textSurface.get_rect()
TextRect.center = ((600 / 2), (700 // 2))
surface.blit(TextSurf, TextRect)
grid.draw(surface)
pygame.display.flip()
break
If you want something to be drawn permanently, you need to draw it in the application loop. The typical PyGame application loop has to:
handle the events by either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by either pygame.display.update() or pygame.display.flip()
Create the text surface at initialization:
winTextSurf = font.render('You Win', True, (0, 0, 0))
winTextRect = winTextSurf.get_rect(topleft = (600 // 2, 700 // 2)
Add a variable that indicates the text needs to be drawn:
drawWinText = Fasle
Set the variable if the text needs to be drawn:
elif msg[0:7] == 'YOU WIN' and Message_id == '200':
drawWinText = True
break
When you no longer want the text to be drawn, you need to reset the value.
drawWinText = False
Draw the text in the main application loop depending on the status of drawWinText:
while run:
# [...]
if drawWinText:
surface.blit(winTextSurf, winTextRect)
pygame.display.flip()
See the answers to question Python - Pygame - rendering translucent text for how to draw transparent text.

Pygame buttons not working

I have created some sort of menu navigation system in my game. All the screens are blitted in. The "Play" and "Quit" and "Controls" button works just fine but when I try to press menu from the controls screen, nothing happens. On the controls screen, you can faintly see the first menu screen from before. That might be the problem. I think that as the return to menu button is over the previous controls page button, it somehow is pressing the controls button from before. The button and menu segment of my code will be pasted here and the full thing will be pasted in a pastebin.
def text_to_button(msg,color,buttonx,buttony,buttonwidth,buttonheight,size = "small"):
textSurf, textRect = text_objects(msg,color,size)
textRect.center = ((buttonx + buttonwidth/2)), buttony+(buttonheight/2)
gameDisplay.blit(textSurf, textRect)
def button(text,x,y,width,height,inactive_color,active_color,size = "small",action = None):
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
#print(click)
if x + width > cur[0] > x and y + height > cur[1] > y:
pygame.draw.rect(gameDisplay, active_color,(x,y,width,height))
if click[0] == 1 and action != None:
if action == "quit":
pygame.quit()
quit()
if action == "controls":
game_controls()
if action == "play":
gameLoop()
if action == "main":
game_intro()
else:
pygame.draw.rect(gameDisplay, inactive_color,(x,y,width,height))
text_to_button(text,black,x,y,width,height,size)
def game_controls():
gcont = True
while gcont:
gameDisplay.blit(cont,(0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("Main Menu",320,500,150,50,white,gray,"tiny", action = "main")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
def game_intro():
intro = True
while intro:
gameDisplay.blit(imggg,(0,0))
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("ControLs",320,500,150,50,white,gray,"tiny", action = "controls")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
intro = False
Full Code: https://pastebin.com/jrd82gkJ
You will have very hard time to debug your code in order to achieve the behavior you want for one simple reason:
The logic you use to switch between different screens providing different functionality is causing much trouble you can't directly see if you only run the game.
So you think: "oh ... how come the button doesn't work, there must be an issue with the button".
You are probably not aware of the fact that using functions having own while loops you go deeper and deeper into recursive calls with increasing recursion depth with each switch from one view to another - it is not how pygame is thought to be programmed.
I suggest you add some print() commands into your code to see in the console output that the code doesn't really do what you expect even if it appears to be OK at the first glance because it works.
Then I suggest you REWRITE your entire code so that you have one main while notGameExit: loop, and don't use any other looping in the helper functions. If you want use looping in your helper functions at least don't call from the helper functions another functions with own loops (and so on), but RETURN from them with an explicit return to avoid recursion.
If you leave the in the main loop called function with return your main loop will continue running and depending on some switches you can display in it different things on the screen and react differently to user actions.
Maybe looking at a minimal working pygame script showing "action" without usage of a loop you will gain better understanding and some deep "enlightenment" about how pygame works and then start a total rewrite of your game using another approach as this one you have used in the current code? Then come back with what you have achieved if you have further questions, but you won't probably have any, because it would be much easier to debug it yourself if the code will become more straightforward.
import pygame
pygame.init() # start PyGame (necessary because 'import pygame' doesn't start PyGame)
winDisplay = pygame.display.set_mode((1024, 768)) # set PyGame window size to 1024x768 pixel
pygame.display.set_caption("Minimal PyGame Test Script")
# Time in pygame is measured in milliseconds (1/1000 seconds) (defined by TIMER_RESOLUTION constant):
pygame.TIMER_RESOLUTION = 1000 # assure 1000 explicit, don't relay on default value
colorWhite = (255, 255, 255) # RGB color in Pygame format (valueRed=255, valueGreen=255, valueBlue=255)
colorRed = (255, 0, 0)
colorGreen = ( 0, 255, 0)
colorBlue = ( 0, 0, 255)
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorRed)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorGreen)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorBlue)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds

How to make buttons in python/pygame?

I'm making a game in pygame and on the first screen I want there to be buttons that you can press to (i) start the game, (ii) load a new screen with instructions, and (iii) exit the program.
I've found this code online for button making, but I don't really understand it (I'm not that good at object oriented programming). If I could get some explanation as to what it's doing that would be great. Also, when I use it and try to open a file on my computer using the file path, I get the error sh: filepath :Permission denied, which I don't know how to solve.
#load_image is used in most pygame programs for loading images
def load_image(name, colorkey=None):
fullname = os.path.join('data', name)
try:
image = pygame.image.load(fullname)
except pygame.error, message:
print 'Cannot load image:', fullname
raise SystemExit, message
image = image.convert()
if colorkey is not None:
if colorkey is -1:
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, RLEACCEL)
return image, image.get_rect()
class Button(pygame.sprite.Sprite):
"""Class used to create a button, use setCords to set
position of topleft corner. Method pressed() returns
a boolean and should be called inside the input loop."""
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_image('button.png', -1)
def setCords(self,x,y):
self.rect.topleft = x,y
def pressed(self,mouse):
if mouse[0] > self.rect.topleft[0]:
if mouse[1] > self.rect.topleft[1]:
if mouse[0] < self.rect.bottomright[0]:
if mouse[1] < self.rect.bottomright[1]:
return True
else: return False
else: return False
else: return False
else: return False
def main():
button = Button() #Button class is created
button.setCords(200,200) #Button is displayed at 200,200
while 1:
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
mouse = pygame.mouse.get_pos()
if button.pressed(mouse): #Button's pressed method is called
print ('button hit')
if __name__ == '__main__': main()
Thank you to anyone who can help me.
I don't have a code example for you, but how I would do it is to:
Make a Button class, with the text to go on the button as a constructor argument
Create a PyGame surface, either of an image or filled Rect
Render text on it with the Font.Render stuff in Pygame
Blit to game screen, save that rect.
Check, on mouse click, to see the mouse.get_pos() matches a coord in the rect that it returned by the blit of the button to the main surface.
That is similar to what your example is doing, although different still.
Another good way to create buttons on pygame (in Python) is by installing the package called pygame_widgets (pip3 install pygame_widgets).
# Importing modules
import pygame as pg
import pygame_widgets as pw
# Creating screen
pg.init()
screen = pg.display.set_mode((800, 600))
running = True
button = pw.Button(
screen, 100, 100, 300, 150, text='Hello',
fontSize=50, margin=20,
inactiveColour=(255, 0, 0),
pressedColour=(0, 255, 0), radius=20,
onClick=lambda: print('Click')
)
While running:
events = pg.event.get()
for event in events:
if event.type == pg.QUIT:
running = False
button.listen(events)
button.draw()
pg.display.update()
The 'code' you have found online is not that good. All you need to make a button is this. Put this near the beginning of your code:
def Buttonify(Picture, coords, surface):
image = pygame.image.load(Picture)
imagerect = image.get_rect()
imagerect.topright = coords
surface.blit(image,imagerect)
return (image,imagerect)
Put the following in your game loop. Also somewhere in your game loop:
Image = Buttonify('YOUR_PICTURE.png',THE_COORDS_OF_THE_BUTTONS_TOP_RIGHT_CORNER, THE_NAME_OF_THE_SURFACE)
Also put this in your game loop wherever you have done for event in pygame.event.get
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
mouse = pygame.mouse.get_pos
if Image[1].collidepoint(mouse):
#code if button is pressed goes here
So, buttonify loads the image that will be on the button. This image must be a .jpg file or any other PICTURE file in the same directory as the code. Picture is its name. The name must have .jpg or anything else after it and the name must be in quotation marks. The coords parameter in Buttonify is the top-right coordinate on your screen or window that opens from pygame. The surface is this thing:
blahblahblah = pygame.surface.set_mode((WindowSize))
/|\
|
Surface's Name
So it the function makes something called 'image' which is a pygame surface, it puts a rectangle around it called 'imagerect' (to set it at a location and for the second parameter when blitting,) and then it sets it's location, and blits it on the second to last last line.
The next bit of code makes 'Image' a tuple of both 'image' and 'imagerect.'
The last code has if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: which basically means if the left mouse button is pressed. This code MUST be in for event in pygame.event.get. The next line makes mouse a tuple of the mouses position. The last line checks if the mouse cursor is inside the area of Image[1], which as we know is 'imagerect.' The code follows that.
Tell me if I need to explain further.
So you have to make a function named button which receives 8 parameters. 1)Message of button
2)X position of left top corner of the button
3)Y position of left top corner of the button
4)Width of the button
5)Height of button
6)Inactive color(background color)
7)Active color(color when you hover)
8)Name of the action you want to perfom
def button (msg, x, y, w, h, ic, ac, action=None ):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if (x+w > mouse[0] > x) and (y+h > mouse[1] > y):
pygame.draw.rect(watercycle, CYAN, (x, y, w, h))
if (click[0] == 1 and action != None):
if (action == "Start"):
game_loop()
elif (action == "Load"):
##Function that makes the loading of the saved file##
elif (action == "Exit"):
pygame.quit()
else:
pygame.draw.rect(watercycle, BLUE, (x, y, w, h))
smallText = pygame.font.Font("freesansbold.ttf", 20)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ( (x+(w/2)), (y+(h/2)) )
watercycle.blit(textSurf, textRect)
So when you create your game loop and you call the button function:
button ("Start", 600, 120, 120, 25, BLUE, CYAN, "Start" )
Here is a class for a button I made ages ago:
https://www.dropbox.com/s/iq5djllnz0tncc1/button.py?dl=0
The button is windows 7 style as far as I can remember, and I havent been able to test it recently because I do not have pygame on the computer I am using. Hope this helps!
This is a modified version of a class that was posted by someone else that worked for me on a very similar (but closed) question.
class Button():
def __init__(self, color, x,y,width,height, text=''):
self.color = color
self.ogcol = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self,win,outline=None):
#Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x-2,self.y-2,self.width+4,self.height+4),0)
pygame.draw.rect(win, self.color, (self.x,self.y,self.width,self.height),0)
if self.text != '':
font = pygame.font.SysFont('Consolas', 24)
text = font.render(self.text, 1, (0,0,0))
win.blit(text, (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2)))
def isOver(self, pos):
global STATE
#Pos is the mouse position or a tuple of (x,y) coordinates
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
self.color = (128,128,128)
else:
self.color = self.ogcol
else:
self.color = self.ogcol
global ev
for event in ev:
if event.type == pygame.MOUSEBUTTONDOWN:
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
return True
The variable ev will be the events list (pygame.event.get()).
Some example syntax for it is
#class up here
btn = Button((255,0,0),100,100,200,50,text="print hi")
#do above before you start the loop
#all of the pygame init and loop
#Define screen as the window
btn.draw(screen)
if btn.isOver(pygame.mouse.get_pos()) == True:
print("hi")
pygame.display.update()

Categories

Resources