Related
I made an endscreen when ever my player health reaches -1 it loads the end screen but here is the problem Video it wont restart the game and I have to hold the start game to show my main game
my end screen def my point is how could I make it restart my game to the start not just blit the game where I was
#------------------------------------------------------
def text_objects(text, font):
textSurface = font.render(text, True, black)
return textSurface, textSurface.get_rect()
def endScreen():
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',81)
TextSurf, TextRect = text_objects("You Have Died Fool", largeText)
TextRect.center = ((800/2), (800/2))
window.blit(TextSurf, TextRect)
button("Start Game",150,450,100,50,green,bright_green,game_loop)
# 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)
#----------------------------------------------------------
here is what I did in my main loop
when my player health reaches 0 it shows the end screen
def game_loop():
# coin scoring
font = pygame.font.Font('times.ttf',29)
score = 0
text = font.render("Hearts = " + str(score), True, (255,255,255))
textRect = text.get_rect()
textRect.center = ((80,70))
shootsright = []
bullets = []
bulls = []
bullss = []
bullsss = []
bullssss = []
runninggame = True
while runninggame:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
runninggame = False
if playerman.health < -5:
endScreen()
The problem is that all of your game loop variables have been saved so when you restart you still have all the variables set to what they when you died.
So what you will need to do is put everything in one giant while loop. For example:
import ...
quit = False
while not quit:
# all of your code goes here
But once you do this you must change the pygame.QUIT if statement in your game loop as follows:
if event.type == pygame.QUIT:
runninggame = False
|
V
if event.type == pygame.QUIT:
sys.exit()
and the same goes for the pygame.QUIT at the top of your endScreen function.
Change 1: The next thing that must be changed is exiting the game loop function. This can be done by modifying one of the button functions to return a bool stating whether or not the restart button was clicked. From there that value can be passed onto the game loop function and if the button is pressed the while loop in the function will be broken out of causing everything in the while loop to rerun.
Explanation: Currently, the problem is that you never exit the loop meaning when you click the retry button you just start right back from where you let off. Instead, you need to redefine all your variables which is why all the code needs to be in a while loop (you can actually leave out the functions all that needs to be in the while loop are the global variables, but it is not necessary to move the functions out).
Change 2 (minor changes): Sys needs to be imported at the top of the script and the pygame.quit() function at the end of the script needs to be deleted.
Explanation: Sys is imported so that sys.exit can be run which allows the program to be terminated once the window is closed out. The pygame.quit() is deleted because running that will uninitialized pygame and that would prevent you from using any pygame functions after you have pressed the retry button. And this code is no longer necessary since sys.exit() pretty much just takes care of all that for you.
And a minor note: enemys should actually be enemies (it would look bad if you had the word enemies spelled incorrectly in your code and you put it up on GitHub) so I recommend just doing a quick replace all.
My first few buttons work fine but my CSTWindow one only works sometimes. I am reluctant to post as I am self taught and the code wont be flawless, any advice would be much appreciated on how to make this button work all the time and not just every 10ish clicks. Parts of my code is below. Again I am self taught it is not perfect!
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(gameDisplay, ac, (x,y,w,h))
if click[0] == 1 and action != None:
action()
else:
pygame.draw.rect(gameDisplay, ic, (x,y,w,h))
smallText = pygame.font.SysFont("Ariel", 20)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ( (x+(w/2)), (y+(h/2)) )
gameDisplay.blit(textSurf, textRect)
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(white)
gameDisplay.blit(background, (x,y))
largeText = pygame.font.SysFont("Arial",45)
TextSurf, TextRect = text_objects("Crime Scene and Evidence Examination Game", largeText)
TextRect.center = ((display_width/2),(display_height/1.2))
gameDisplay.blit(TextSurf, TextRect)
button("Scene Selection",150,540,100,50,blue,bright_blue,game_loop)
button("Quit",550,540,100,50,red,bright_red,quitgame)
pygame.display.update()
def CSTWindow():
CSTWindow = True
while CSTWindow:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
print("Crime Scene")
def TutorialWindow():
tutorial = True
while tutorial:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
screen = pygame.display.set_mode((display_width,display_height))
screen.fill(white)
screen.blit(TutorialBG, (x,y))
button("Crime Scene",150,540,100,50,blue,bright_blue,CSTWindow)
pygame.display.update()
def game_loop():
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(blue)
button("Tutorial",(370), (100),100, 50, lightBlue, bright_blue,TutorialWindow)
pygame.display.update()
clock.tick(60)
Maybe it will work better with an image, this is what i wrote:
def button(x, y, w, h, inactive, active, action=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + w > mouse[0] > x and y + h > mouse[1] > y:
gameDisplay.blit(active, (x, y))
if click[0] == 1 and action is not None:
action()
else:
gameDisplay.blit(inactive, (x, y))
Btw, I watched the same tutorial as you but I used images instead.
I'm having some trouble while trying to quit from a function that I made. It just doesn't seem to break the loop. The game opens and I can play around but I can't quit, It just stays there without doing anything and the icon on the task bar goes full yellow.
Here's my code:
import pygame, os, sys, math
black = (0,0,0)
white = (255,255,255)
grey = (128, 128, 128)
gameDisplay = pygame.display.set_mode((800,600))
def game_menu():
os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()
pygame.display.set_caption(".")
menu = True
events = pygame.event.get()
while menu:
for event in events:
if event.type == pygame.QUIT:
menu = False
pygame.quit()
quit()
DISPLAYSURF = pygame.display.set_mode((800, 600))
DISPLAYSURF.fill(black)
font = pygame.font.Font('MATRIX.ttf',60)
TextSurf, TextRect = text_objects("MATRIX PASA PALABRA", font,white)
TextRect.center = ((600/2),(50))
gameDisplay.blit(TextSurf, TextRect)
#Jugar
button("Jugar",300,200,200,50,None)
button("Instrucciones",300,275,200,50,None)
button("Dificultad",300,350,200,50,None)
button("Salir",300,425,200,50,None)
pygame.display.update()
def text_objects(text, font,color):
textSurface = font.render(text, True, color)
return textSurface, textSurface.get_rect()
def button(msg,x,y,w,h,action=None):
mouse = pygame.mouse.get_pos()
events = pygame.event.get()
if x+w> mouse[0] > (x) and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay,grey,(x,y,w,h))
for event in events:
if event.type ==pygame.MOUSEBUTTONUP and msg=="Salir":
pygame.quit()
quit()
elif event.type==pygame.MOUSEBUTTONUP and msg=="Jugar":
None
else:
pygame.draw.rect(gameDisplay,white,(x,y,w,h))
smalltext= pygame.font.Font("MATRIX.ttf",30)
textsrf,textrct=text_objects(msg,smalltext,black)
textrct.center = ((x+(w/2)),(y+(h/2)))
gameDisplay.blit(textsrf,textrct)
if __name__ == "__main__":
game_menu()
Thanks and sorry for my bad english.
The reason why it doesn't work is that you call pygame.event.get multiple times per frame. The event queue will be emptied after the first call, so the events won't get processed correctly. There should be only one pygame.event.get call per frame.
To fix this problem, you can assign the list of events that pygame.event.get returns to a variable in the main while loop and then pass it to the button function.
while menu:
events = pygame.event.get()
for event in events:
# etc.
button("Jugar",300,200,200,50,events,None)
Add an events parameter to the button function:
def button(msg,x,y,w,h,events,action=None):
mouse = pygame.mouse.get_pos()
if x+w> mouse[0] > (x) and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay,grey,(x,y,w,h))
for event in events:
# etc.
BTW, this button function keeps popping up here again and again, probably because it's a really bad way to implement buttons. I'd recommend a solution similiar to one of these: https://stackoverflow.com/a/47664205/6220679 or search for pygame GUI toolkits (SGC is pretty good).
The others have already mentioned that the indentation in your example is wrong and that sys.exit is a better way to quit than the quit function.
Here's a fixed, complete example:
import pygame, os, sys, math
black = (0,0,0)
white = (255,255,255)
grey = (128, 128, 128)
gameDisplay = pygame.display.set_mode((800,600))
def game_menu():
os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()
pygame.display.set_caption(".")
DISPLAYSURF = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
menu = True
while menu:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
menu = False
pygame.quit()
sys.exit()
DISPLAYSURF.fill((30, 30, 30))
font = pygame.font.Font(None,60)
TextSurf, TextRect = text_objects("MATRIX PASA PALABRA", font,white)
TextRect.center = ((600/2),(50))
gameDisplay.blit(TextSurf, TextRect)
#Jugar
button("Jugar",300,200,200,50,events,None)
button("Instrucciones",300,275,200,50,events,None)
button("Dificultad",300,350,200,50,events,None)
button("Salir",300,425,200,50,events,None)
pygame.display.update()
clock.tick(60)
def text_objects(text, font,color):
textSurface = font.render(text, True, color)
return textSurface, textSurface.get_rect()
def button(msg,x,y,w,h,events,action=None):
mouse = pygame.mouse.get_pos()
if x+w> mouse[0] > (x) and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay,grey,(x,y,w,h))
for event in events:
if event.type ==pygame.MOUSEBUTTONUP and msg=="Salir":
pygame.quit()
sys.exit()
elif event.type==pygame.MOUSEBUTTONUP and msg=="Jugar":
print("jugar")
else:
pygame.draw.rect(gameDisplay,white,(x,y,w,h))
smalltext= pygame.font.Font(None,30)
textsrf,textrct=text_objects(msg,smalltext,black)
textrct.center = ((x+(w/2)),(y+(h/2)))
gameDisplay.blit(textsrf,textrct)
if __name__ == "__main__":
game_menu()
If you import sys then you can use that to exit your code.
import sys
def game_menu():
menu = True
while menu:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
Try adding pygame.display.quit() before the line pygame.quit(). This should close any open displays.
Edit:
The problem is that most of your program isn't inside the while loop. Most importantly, the events = pygame.event.get() isn't inside the while loop so the events are never updated.
Rearranging the code to something like this should work:
def game_menu():
os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()
pygame.display.set_caption(".")
menu = True
while menu:
events = pygame.event.get()
DISPLAYSURF = pygame.display.set_mode((800, 600))
DISPLAYSURF.fill(black)
font = pygame.font.Font('MATRIX.ttf',60)
TextSurf, TextRect = text_objects("MATRIX PASA PALABRA", font,white)
TextRect.center = ((600/2),(50))
gameDisplay.blit(TextSurf, TextRect)
#Jugar
button("Jugar",300,200,200,50,None)
button("Instrucciones",300,275,200,50,None)
button("Dificultad",300,350,200,50,None)
button("Salir",300,425,200,50,None)
pygame.display.update()
for event in events:
if event.type == pygame.QUIT:
menu = False
pygame.quit()
quit()
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
Edit: added a longer example code.
I'm having trouble with coding buttons in pygame. I'm a newbie to the pygame module, so be gentle.
Basically, the goal is to make a point-and-click telltale kind of game. The player gets presented with two choices each gameloop, ie "go left" or "go right". Accordingly, there are two buttons in each gameloop, all located at the same coordinates.
Here is the function:
import pygame
import os
import time
pygame.init()
display_width= 1280
display_height = 720
gameDisplay = pygame.display.set_mode((display_width, display_height))
clock = pygame.time.Clock()
def button(msg,x, y, w, h, ic, ac, action=None): #message, x y location, width, height, inactive and active colour
if action ==None:
pygame.display.update()
clock.tick(15)
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(gameDisplay, ac,(x,y,w,h))
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
pygame.display.update()
clock.tick(15)
if action == "left1":
game_loop("loop1-1.png",0,0,"left2","left2","","")
else:
pygame.draw.rect(gameDisplay, ic,(x,y,w,h))
smallText = pygame.font.SysFont('timesnewroman',20)
textSurf, textRect = text_objects(msg, smallText, silver)
textRect.center = ( (x+(w/2)), (y+(h/2)) )
gameDisplay.blit(textSurf, textRect)
def game_loop(pic,width,heigth,act1,act2,left,right):
intro = True
while intro:
for event in pygame.event.get():
print(event)
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(white)
gameDisplay.blit(get_image(pic), (0, 0)) #MAIN MENU PIC
button(left,440,450,width,heigth, dark_gray, gray, action=act1)#start nupp
button(right,740,450,width,heigth, dark_gray, gray, action=act2)#exit nupp
pygame.display.update()
clock.tick(15)
The problem occurs when I click the button carelessly, meaning if I don't purposefully click on the left mouse button as fast as I can. Once game_loop1 is called and if I click for a bit longer, the program will read the first click again in this game_loop1 and run the next game_loop and then the next etc. This means the player can accidentally skip through gameloops.
Is there a way to delay the program after the first click(however long it is)? Or maybe a way to include keyup in the function, so it won't count the click in the next gameloop?
Thanks!
I think your original code is a bit too convoluted to fix it and I'll rather show you some better ways to do what you want. You need a finite-state machine to transition between different states/scenes. You can find a simple example with functions as scenes here.
If the logic in your scenes is mostly the same, you could also try to just swap out the data for the scene, for example the background image. Each state/scene needs to know to which new states it can switch, so I put the data into a dictionary of dictionaries. The nested dicts contain the background image of the scene and the connected left and right scenes. When the user presses a button/rect I check if it was the left or right button and then switch to the corresponding scene (subdict) in the states dictionary.
import pygame
pygame.init()
display_width= 1280
display_height = 720
gameDisplay = pygame.display.set_mode((display_width, display_height))
clock = pygame.time.Clock()
# Use uppercase names for constants that should never be changed.
DARK_GRAY = pygame.Color('gray13')
BACKGROUND1 = pygame.Surface((display_width, display_height))
BACKGROUND1.fill((30, 150, 90))
BACKGROUND2 = pygame.Surface((display_width, display_height))
BACKGROUND2.fill((140, 50, 0))
BACKGROUND3 = pygame.Surface((display_width, display_height))
BACKGROUND3.fill((0, 80, 170))
states = {
'scene1': {'background': BACKGROUND1, 'left_scene': 'scene2', 'right_scene': 'scene3'},
'scene2': {'background': BACKGROUND2, 'left_scene': 'scene1', 'right_scene': 'scene3'},
'scene3': {'background': BACKGROUND3, 'left_scene': 'scene1', 'right_scene': 'scene2'},
}
def game_loop():
# The buttons are just pygame.Rects.
left_button = pygame.Rect(440, 450, 60, 40)
right_button = pygame.Rect(740, 450, 60, 40)
# The current_scene is a dictionary with the relevant data.
current_scene = states['scene1']
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.MOUSEBUTTONDOWN:
# If the left button is clicked we switch to the 'left_scene'
# in the `current_scene` dictionary.
if left_button.collidepoint(event.pos):
current_scene = states[current_scene['left_scene']]
print(current_scene)
# If the right button is clicked we switch to the 'right_scene'.
elif right_button.collidepoint(event.pos):
current_scene = states[current_scene['right_scene']]
print(current_scene)
# Blit the current background.
gameDisplay.blit(current_scene['background'], (0, 0))
# Always draw the button rects.
pygame.draw.rect(gameDisplay, DARK_GRAY, left_button)
pygame.draw.rect(gameDisplay, DARK_GRAY, right_button)
pygame.display.update()
clock.tick(30) # 30 FPS feels more responsive.
game_loop()
pygame.quit()