Related
I have a Pygame program which has a 'Home' screen that has 5 buttons which when pressed calls a new function which opens up a different screen for every different button. For every of those screens I have added a small 'Home' button at the top right so that the user can go back to the 'Home' screen from any of the called screens.
import pygame
window = pygame.display.set_mode((1500, 800), pygame.RESIZABLE)
def common_screen():
button("Home", 1400, 0, 100, 50, (0,200,0), (255,255,210), home_intro) **#Problem at this point**
*#do something else too*
def text_objects(text, font):
textSurface = font.render(text, True, (0,0,0))
return textSurface, textSurface.get_rect()
def button(msg, x, y, w, h, ic, ac, action):
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(window, ac, (x, y, w, h))
if click[0] == 1:
action()
else:
pygame.draw.rect(window, ic, (x, y, w, h))
smallText = pygame.font.SysFont(None, 20)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ((x+(w/2)), (y+(h/2)))
window.blit(textSurf, textRect)
def home_intro():
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.blit(image, (0,0))
pygame.display.set_caption("PROGRAM")
button("Start", 150, 450, 100, 50, (0,200,0), (255,255,210), start)
button("Screen 1", 150, 450, 100, 50, (0,200,0), (255,255,210), screen1)
button("Screen 2", 150, 450, 100, 50, (0,200,0), (255,255,210), screen2)
button("Stop", 550, 450, 100, 50, (0,200,0), (255,255,210), stop)
if game_state == 'screen1':
common_screen()
pygame.display.flip()
home_intro()
pygame.quit()
quit()
The common_screen() function creates a 'Home' button at the top right but if I use home_intro() as the last argument in the button() function inside it, it causes a recursion error. It seems wrong to call the main function every time to go back to the main page. There is no point in creating a new function because it would be the same as the home_intro() function.
Do not call home_intro recursively, but add and call a function that changes the game_state variable:
def home():
global game_state
game_state = "home"
def common_screen():
button("Home", 1400, 0, 100, 50, (0,200,0), (255,255,210), home)
def home_intro():
global game_state
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.blit(image, (0,0))
pygame.display.set_caption("PROGRAM")
button("Start", 150, 450, 100, 50, (0,200,0), (255,255,210), start)
button("Screen 1", 150, 450, 100, 50, (0,200,0), (255,255,210), screen1)
button("Screen 2", 150, 450, 100, 50, (0,200,0), (255,255,210), screen2)
button("Stop", 550, 450, 100, 50, (0,200,0), (255,255,210), stop)
if game_state == 'screen1':
common_screen()
pygame.display.flip()
so I have a game intro here and I was wonder how can I make it so when my ***mouse clicks on the start game button to disable the the game_intro? its currently not doing anything and vid
like how could I make a function for start button when I click it, it should remove the game_intro or disable it and load my main game
this is my game intro right now
#---------------------------------------------------
def button(msg,x,y,w,h,ic,ac):
mouse = pygame.mouse.get_pos()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, ac,(x,y,w,h))
else:
pygame.draw.rect(gameDisplay, ic,(x,y,w,h))
if clikc[0] == 1 and action != None:
action()
else:
pygame.draw.rect(window,ic,(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)) )
gameDisplay.blit(textSurf, textRect)
#------------------------------------------------------
def text_objects(text, font):
textSurface = font.render(text, True, black)
return textSurface, textSurface.get_rect()
def game_intro():
red = (200,0,0)
green = (0,200,0)
bright_red = (255,0,0)
bright_green = (0,255,0)
intro = True
while intro:
for event in pygame.event.get():
#print(event)
if event.type == pygame.QUIT:
pygame.quit()
quit()
window.fill((255,255,255))
largeText = pygame.font.Font('BLOODY.ttf',115)
TextSurf, TextRect = text_objects("Stolen Hearts!", largeText)
TextRect.center = ((800/2), (800/2))
window.blit(TextSurf, TextRect)
# make the square brighter if collideded with the buttons
mouse = pygame.mouse.get_pos()
if 150+120 > mouse[0] > 150 and 450+50 > mouse[1] > 450:
pygame.draw.rect(window, bright_green,(150,450,120,50))
else:
pygame.draw.rect(window, green,(150,450,120,50))
if 550+110 > mouse[0] > 550 and 450+50 > mouse[1] > 450:
pygame.draw.rect(window, bright_red,(550,450,110,50))
else:
pygame.draw.rect(window, red,(550,450,110,50))
# ---------------------------------------------------------------------
smallText = pygame.font.Font("freesansbold.ttf",20)
textSurf, textRect = text_objects("Start Game", smallText)
textRect.center = ( (150+(120/2)), (450+(50/2)) )
window.blit(textSurf, textRect)
smallText = pygame.font.Font("freesansbold.ttf",20)
textSurf, textRect = text_objects("Quit Game", smallText)
textRect.center = ( (150+(910/2)), (450+(50/2)) )
window.blit(textSurf, textRect)
pygame.display.update()
clock.tick(15)
#----------------------------------------------------------
my full code script
You have to remove mistakes in button() and you have to use button() in game_intro()
There is too many to explain so I only show minimal working code.
Buttons works but they still are not ideal. It will have problem if new scene will have buttons in the same place - it will click it automatically - but it would need totally different code. More on GitHub
import pygame
# --- constants --- (UPPER_CASE_NAMES)
RED = (200, 0, 0)
GREEN = (0, 200, 0)
BRIGHT_RED = (255, 0, 0)
BRIGHT_GREEN = (0, 255, 0)
BLACK = (0, 0, 0)
# --- all classes --- (CamelCaseNames)
class Player:
pass
# ... code ...
class Platform:
pass
# ... code ...
# etc.
# --- all functions --- (lower_case_names)
def text_objects(text, font):
image = font.render(text, True, BLACK)
rect = image.get_rect()
return image, rect
def button(window, 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(window, ac,(x,y,w,h))
if click[0] == 1 and action != None:
action()
else:
pygame.draw.rect(window, ic,(x,y,w,h))
image = small_font.render(msg, True, BLACK)
rect = image.get_rect()
rect.center = (x+(w/2), y+(h/2))
window.blit(image, rect)
def game_intro():
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
window.fill((255,255,255))
image, rect = text_objects("Stolen Hearts!", large_font)
rect.center = (400, 400)
window.blit(image, rect)
button(window, "Start Game", 150, 450, 120, 50, GREEN, BRIGHT_GREEN, main_game)
button(window, "Quit Game", 350, 450, 120, 50, RED, BRIGHT_RED, quit_game)
pygame.display.update()
clock.tick(15)
def main_game():
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
window.fill((255,255,255))
image, rect = text_objects("Main Game", large_font)
rect.center = (400, 400)
window.blit(image, rect)
button(window, "Intro", 550, 450, 120, 50, GREEN, BRIGHT_GREEN, game_intro)
button(window, "Quit Game", 350, 450, 120, 50, RED, BRIGHT_RED, quit_game)
pygame.display.update()
clock.tick(15)
def quit_game():
print("You quit game")
pygame.quit()
quit()
# --- main ---
pygame.init()
window = pygame.display.set_mode((800, 800))
# it has to be after `pygame.init()`
#small_font = pygame.font.Font("freesansbold.ttf", 20)
#large_font = pygame.font.Font('BLOODY.ttf', 115)
small_font = pygame.font.Font(None, 20)
large_font = pygame.font.Font(None, 115)
clock = pygame.time.Clock()
game_intro()
BTW: I also organize code in different way
all constants values in one place directly after imports and they use UPPER_CASE_NAMES (PEP8) and
all classes in one place - directly after constants and before pygame.init() - and they use CamelCaseNames (PEP8)
all functions in one place - after classes and before pygame.init() - and they uselower_case_names (PEP8)
See: PEP 8 -- Style Guide for Python Code
I have a variable clickCounter that increases when the mouse button is clicked (when clicked on a button) and held. How do I stop the value from increasing when the button is held and only when it is clicked?
Button function (would it be easier to convert it to a class?):
def button(message, x, y, w, h, activeRGB, inactiveRGB, action=None): #example of color param for line 61/63
mouse = pygame.mouse.get_pos() #get location of mouse recorded by pygame
click = pygame.mouse.get_pressed()
global clickCounter
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, activeRGB, (x, y, w, h))
if click[0] ==1 and action != None:
if action == "countUP":
clickCounter+= 1
print(str(clickCounter))
pygame.display.update()
else:
pygame.draw.rect(gameDisplay, inactiveRGB, (x, y, w, h))
smallText = pygame.font.Font("freesansbold.ttf", 20) # constant has been declared, try deleting line when done w/ proj
textSurf, textRect = textBox(message, smallText)
textRect.center = ( (x + (w/2)), y+(h/2))
gameDisplay.blit(textSurf, textRect)
main loop
closeGame = False
while not closeGame: # this keeps the window from shutting down
for thing in pygame.event.get():
if thing.type == pygame.QUIT:
closeGame = True
print(thing)
gameDisplay.fill(white)
button("Click me!", 300, 300, 100, 100, blue, brightBlue, "countUP")
textObject(str(clickCounter), black, mediumText, 200, 200)
pygame.display.update()
clock.tick(20)
All code:
import pygame
pygame.init()
displayWidth = 700
displayHeight = displayWidth
gameDisplay = pygame.display.set_mode((700,700))
clock = pygame.time.Clock()
black = (0, 0, 0)
brightBlue = (0, 0, 225)
blue = (0, 0, 255)
white = (255, 255, 255) #predef colors to make temp rgb value coding easier
closeGame = False
mediumText = pygame.font.Font("freesansbold.ttf", 70) #initalize font
clickCounter = 0
#def fontSize (pxsize):
#pygame.font.Font("freesandsbold.ttf", pxsize)
def textObject (text, color, font, x, y):
storedGenerate = font.render(text, 1, ((color)))
gameDisplay.blit(storedGenerate, (x,y))
def textBox(text, font): #purely for redturning rectangle around font// used for btn function only, tObject for displaying text
textSurface = font.render(text, True, black) #swap black for rgb later
return textSurface, textSurface.get_rect()
def button(message, x, y, w, h, activeRGB, inactiveRGB, action=None): #example of color param for line 61/63
mouse = pygame.mouse.get_pos() #get location of mouse recorded by pygame
click = pygame.mouse.get_pressed()
global clickCounter
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, activeRGB, (x, y, w, h))
if click[0] ==1 and action != None:
if action == "countUP":
clickCounter+= 1
print(str(clickCounter))
pygame.display.update()
else:
pygame.draw.rect(gameDisplay, inactiveRGB, (x, y, w, h))
smallText = pygame.font.Font("freesansbold.ttf", 20) # constant has been declared, try deleting line when done w/ proj
textSurf, textRect = textBox(message, smallText)
textRect.center = ( (x + (w/2)), y+(h/2))
gameDisplay.blit(textSurf, textRect)
closeGame = False
while not closeGame: # this keeps the window from shutting down
for thing in pygame.event.get():
if thing.type == pygame.QUIT:
closeGame = True
print(thing)
gameDisplay.fill(white)
button("Click me!", 300, 300, 100, 100, blue, brightBlue, "countUP")
textObject(str(clickCounter), black, mediumText, 200, 200)
pygame.display.update()
clock.tick(20)
gameDisplay.fill(white)
pygame.display.update()
#logicloop()
pygame.quit()
quit()
My inital thought was to not use pygame.mouse.get_pressed() and instead use mousebutton down but was unable to get it to function properly. Any help is appreciated.
Evaluate the MOUSEBUTTONDOWN event instead of pygame.mouse.get_pressed. The event occurs a single time, when the mouse button is pressed.
Store the mouse button which was pressed to a variable mousebutton:
while not closeGame: # this keeps the window from shutting down
mousebutton = 0
for thing in pygame.event.get():
if thing.type == pygame.QUIT:
closeGame = True
elif thing.type == pygame.MOUSEBUTTONDOWN:
mousebutton = thing.button
Pass the variable to the function button:
button(mousebutton, "Click me!", 300, 300, 100, 100, blue, brightBlue, "countUP")
Evaluate if the left button was pressed in the fucntion:
def button(mousebutton, message, x, y, w, h, activeRGB, inactiveRGB, action=None):
mouse = pygame.mouse.get_pos() #get location of mouse recorded by pygame
global clickCounter
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, activeRGB, (x, y, w, h))
if mousebutton == 1 and action != None:
if action == "countUP":
clickCounter+= 1
print(str(clickCounter))
pygame.display.update()
else:
pygame.draw.rect(gameDisplay, inactiveRGB, (x, y, w, h))
# [...]
The .button attribute of the MOUSEBUTTONDOWN event returns 1 for the left button, 2 for the middle button, 3 fro the right button respectively 4 when the mouse wheel is rolled up, and 5 when the mouse wheel is rolled down.
I have some code that creates a button and code creating some text that is displayed on-screen. The goal is to have the button when clicked add 1 to the variable and have the changed reflected on screen (ie button is clicked the value on screen goes from 0 to 1 and then 1 to 2 and so on).
The button function:
def button(message, x, y, w, h, activeRGB, inactiveRGB, action=None): #example of color param for line 61/63
mouse = pygame.mouse.get_pos() #get location of mouse recorded by pygame
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, activeRGB, (x, y, w, h))
if click[0] ==1 and action != None:
if action == "countUP":
clickCounter+= 1
print(str(clickCounter)) # print to check that the button actually changes the value
pygame.display.update()
else:
pygame.draw.rect(gameDisplay, inactiveRGB, (x, y, w, h))
smallText = pygame.font.Font("freesansbold.ttf", 20)
textSurf, textRect = textBox(message, mediumText)
textRect.center = ( (x + (w/2)), y+(h/2))
gameDisplay.blit(textSurf, textRect)
The logic I have so far
gameDisplay.fill(white)
pygame.display.update()
clickCounter = str(clickCounter)
textObject(clickCounter, black, mediumText, 200, 200)
closeGame = False
while not closeGame: # this keeps the window from shutting down
for thing in pygame.event.get():
if thing.type == pygame.QUIT:
closeGame = True
print(thing)
button("Click me!", 300, 300, 100, 100, blue, brightBlue, "countUP")
pygame.display.update()
clock.tick(20)
gameDisplay.fill(white)
pygame.display.update()
#logicloop()
The button function does appear to be changing the value of clickCounter but it is not reflected on screen. My guess was that there is a missing blit command or screen update, though nothing i've tried has worked.
For whatever reason when I had this block of code set up as a function that is then called, it ran without the gameDisplay.fill(white) or any of the other on screen elements appearing, how would I go about setting it up as a function to make adding more to the logic easier?
All of the code:
import pygame
pygame.init()
displayWidth = 700
displayHeight = displayWidth
gameDisplay = pygame.display.set_mode((700,700))
clock = pygame.time.Clock()
black = (0, 0, 0)
brightBlue = (0, 0, 225)
blue = (0, 0, 255)
white = (255, 255, 255) #predef colors to make temp rgb value coding easier
closeGame = False
mediumText = pygame.font.Font("freesansbold.ttf", 70) #initalize font
clickCounter = 0
#def fontSize (pxsize):
#pygame.font.Font("freesandsbold.ttf", pxsize)
def textObject (text, color, font, x, y):
storedGenerate = font.render(text, 1, ((color)))
gameDisplay.blit(storedGenerate, (x,y))
def textBox(text, font): #purely for returning rectangle around font// used for btn function only, tObject for displaying text
textSurface = font.render(text, True, black) #swap black for rgb later
return textSurface, textSurface.get_rect()
def button(message, x, y, w, h, activeRGB, inactiveRGB, action=None): #example of color param for line 61/63
mouse = pygame.mouse.get_pos() #get location of mouse recorded by pygame
click = pygame.mouse.get_pressed()
global clickCounter
clickCounter = 0
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, activeRGB, (x, y, w, h))
if click[0] ==1 and action != None:
if action == "countUP":
clickCounter+= 1
print(str(clickCounter))
pygame.display.update()
else:
pygame.draw.rect(gameDisplay, inactiveRGB, (x, y, w, h))
#smallText = pygame.font.Font("freesansbold.ttf", 20) # constant has been declared, try deleting line when done w/ proj
smallText = pygame.font.SysFont('Times New Roman', 20)
textSurf, textRect = textBox(message, smallText)
textRect.center = ( (x + (w/2)), y+(h/2))
gameDisplay.blit(textSurf, textRect)
gameDisplay.fill(white)
pygame.display.update()
clickCounter = str(clickCounter)
textObject(clickCounter, black, mediumText, 200, 200)
closeGame = False
while not closeGame: # this keeps the window from shutting down
for thing in pygame.event.get():
if thing.type == pygame.QUIT:
closeGame = True
print(thing)
button("Click me!", 300, 300, 100, 100, blue, brightBlue, "countUP")
pygame.display.update()
clock.tick(20)
gameDisplay.fill(white)
pygame.display.update()
#logicloop()
pygame.quit()
quit()
The first issue is, that the number value stored in clickCounter is converted to a string.
Delete:
lickCounter = str(clickCounter)
In the function button, the value of clickCounter is continuously set 0. Delete this, too:
def button(message, x, y, w, h, activeRGB, inactiveRGB, action=None):
mouse = pygame.mouse.get_pos() #get location of mouse recorded by pygame
click = pygame.mouse.get_pressed()
global clickCounter
# clickCounter = 0 <------ delete
# [...]
You missed to draw the changed text in the main loop. Before the text is drawn the "old" text has to be cleared. Continuously redraw the entire scene in the main loop of the application.
This means the display has to be filled by the background color and the text and the button have to be redrawn:
while not closeGame: # this keeps the window from shutting down
for thing in pygame.event.get():
if thing.type == pygame.QUIT:
closeGame = True
print(thing)
gameDisplay.fill(white)
button("Click me!", 300, 300, 100, 100, blue, brightBlue, "countUP")
textObject(str(clickCounter), black, mediumText, 200, 200)
pygame.display.update()
clock.tick(20)
I've recently started learning Python3 and I was trying to make a game with Python3 by importing pygame. I tried to make a menu and I am having some struggles with it. I just tried to make it seem like its a button by letting the rectangle change color when you hover over it but its not working. I already tried some things but its not working. Anyhow here is the full code: hastebin link.
This is the part where I tried to make a button:
def game_intro():
intro = True
gameDisplay.fill(white)
largeText = pygame.font.Font('freesansbold.ttf', 90)
TextSurf, TextRect = text_objects("Run Abush Run!", largeText)
TextRect.center = ((display_width / 2), (display_height / 2))
gameDisplay.blit(TextSurf, TextRect)
mouse = pygame.mouse.get_pos()
if 150+100 > mouse[0] > 150 and 430+50 > mouse[1] > 430:
pygame.draw.rect(gameDisplay, bright_green, (150,430,100,50))
else:
pygame.draw.rect(gameDisplay, green, (150, 430, 100, 50))
smallText = pygame.font.Font('freesansbold.ttf' ,20)
textSurf, textRect = text_objects("START!", smallText)
textRect.center = ( (150+(100/2)), (450+(430/2)) )
gameDisplay.blit(textSurf, textRect)
pygame.draw.rect(gameDisplay, red, (550, 430, 100, 50))
pygame.display.update()
clock.tick(15)
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
The problem here is that you're only doing your mouseover test once, at the start of the function. If the mouse later moves into your rectangle, it won't matter, because you never do the test again.
What you want to do is move it into the event loop. One tricky bit in PyGame event loops is which code you want to run once per event (the inner for event in… loop), and which you only want to run once per batch (the outer while intro loop). Here, I'm going to assume you want to do this once per event. So:
def game_intro():
intro = True
# ... other setup stuff
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
mouse = pygame.mouse.get_pos()
if 150+100 > mouse[0] > 150 and 430+50 > mouse[1] > 430:
pygame.draw.rect(gameDisplay, bright_green, (150,430,100,50))
else:
pygame.draw.rect(gameDisplay, green, (150, 430, 100, 50))
It looks like some of the other stuff you do only once also belongs inside the loop, so your game may still have some problems. But this should get you past the hurdle you're stuck on, and show you how to get started on those other problems.
Here is a button that should suit your needs:
class Button(object):
global screen_width,screen_height,screen
def __init__(self,x,y,width,height,text_color,background_color,text):
self.rect=pygame.Rect(x,y,width,height)
self.x=x
self.y=y
self.width=width
self.height=height
self.text=text
self.text_color=text_color
self.background_color=background_color
def check(self):
return self.rect.collidepoint(pygame.mouse.get_pos())
def draw(self):
pygame.draw.rect(screen, self.background_color,(self.rect),0)
drawTextcenter(self.text,font,screen,self.x+self.width/2,self.y+self.height/2,self.text_color)
pygame.draw.rect(screen,self.text_color,self.rect,3)
Use the draw function to draw your button, and the check function to see if the button is being pressed.
Implemented into a main loop:
button=Button(x,y,width,height,text_color,background_color,text)
while not done:
for event in pygame.event.get():
if event.type==QUIT:
terminate()
elif event.type==pygame.MOUSEBUTTONDOWN:
if button.check():
#what to do when button is pressed
#fill screen with background
screen.fill(background)
button.draw()
pygame.display.flip()
clock.tick(fps)
This is what i did and it works now:
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
# print(event)
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(white)
largeText = pygame.font.Font('freesansbold.ttf', 90)
TextSurf, TextRect = text_objects("Run Abush Run!", largeText)
TextRect.center = ((display_width / 2), (display_height / 2))
gameDisplay.blit(TextSurf, TextRect)
mouse = pygame.mouse.get_pos()
# print(mouse)
if 150 + 100 > mouse[0] > 150 and 450 + 50 > mouse[1] > 450:
pygame.draw.rect(gameDisplay, bright_green, (150, 450, 100, 50))
else:
pygame.draw.rect(gameDisplay, green, (150, 450, 100, 50))
pygame.draw.rect(gameDisplay, red, (550, 450, 100, 50))
pygame.display.update()
clock.tick(15)
Thank you for the help #abarnert