Pygame - why my game repeats instead of closing? - python

First of all, sorry for my noob question.
So I'm trying to learn pygame, and to do so I created a """game""' that is supposed to quit whenever someone clicks the close button ("x" button") in the top corner of the window, but instead the whole game restarts itself.
I use "Game = False" to point that the game needs to close, since everything that the game does is located in a loop that only starts with "Game = True", and at the end of the script (after the loop ends) there is a "pygame.quit()" and a "sys.exit()". This was was working fine, but recenlty I added the following lines:
if x < 0 or x > display_width - spacecore_width:
game_over()
Those are supposed to call a "game_over" function, that resets the game by calling the another function that covers the whole game (the loop is located inside of this function). But this is not supposed to happen when someone clicks the "x" button to quit the game, and I have no idea of why this also happens when such thing is done (besides working as intended, by only repeating the game if "x < 0 or x > display_width - spacecore_width".
I already know how to avoid it (I just need to replace "Game = False" with those quit commands) but I would like to know why the problem happens in the first place.
Here's the full code:
import pygame, sys, time
pygame.init()
display_width = 800
display_height = 600
DISPLAY = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("Não enconste nas bordas da tela")
WHITE = (255,255,255)
RED = (255,0,0)
SPACECORE = pygame.image.load("spacecore.png")
spacecore_width = 100
clock = pygame.time.Clock()
def text_and_rect(text,font):
text_surface = font.render(text,True,RED)
return text_surface, text_surface.get_rect()
def message_display(text):
font = pygame.font.Font("freesansbold.ttf",50)
text_surf, text_rect = text_and_rect(text,font)
text_rect.center = ((display_width/2),(display_height/2))
DISPLAY.blit(text_surf,text_rect)
pygame.display.update()
time.sleep(2)
def game_over():
message_display("Você morreu de morte morrida")
game_loop()
def player(x,y):
DISPLAY.blit(SPACECORE,(x,y))
def game_loop():
Game = True
x = display_width * 0.5
y = display_height * 0.8
mod_x = mod_y = 0
while Game == True:
pygame.display.update()
DISPLAY.fill(WHITE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
Game = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
mod_x = -5
if event.key == pygame.K_RIGHT:
mod_x = 5
if event.key == pygame.K_UP:
mod_y = -5
if event.key == pygame.K_DOWN:
mod_y = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
mod_x = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
mod_y = 0
x += mod_x
y += mod_y
clock.tick(60)
player(x,y)
if x < 0 or x > display_width - spacecore_width:
game_over()
game_loop()
pygame.quit()
sys.exit()

Make sure you're breaking out of the loop and then calling the loop function again:
while Game == True:
# some here code
if x < 0 or x > display_width - spacecore_width:
break # leave while loop
# proceed elsewhere
game_over()
Or alternatively cut the flow back to game_loop in game_over:
def game_over():
message_display("Você morreu de morte morrida")
# game_loop() # removed
Currently you're never breaking out of loops when game is over - you're just calling other functions (which in turn active another loop) in a mutually-recursive manner, effectively this never ends any game.
Also, if you receive a quit event you may want to break out of the for loop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Game = False
break

Related

Pygame dinosaur image keeps duplicating

I'm trying to make a dinosaur game in python (like the offline dino game in chrome).
I want the dino to jump when space is pressed but when I press it,not only the image of dino is duped but it also doesn't come back.
import pygame
import time
pygame.init()
displayWidth = 700
displayHeight = 350
gameDisplay = pygame.display.set_mode((displayWidth,displayHeight))
pygame.display.set_caption("Dino-Run")
black = (0,0,0)
white = (255,255,255)
clock = pygame.time.Clock()
dinoimg = pygame.image.load("dino.png")
def dino(x,y):
gameDisplay.blit(dinoimg,(x,y))
def gameloop():
gameExit = False
x = (displayWidth * 0.005)
y = (displayHeight * 0.75)
y_change = 0
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
y_change = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
y_change = 0
y += y_change
dino(x,y)
pygame.display.update()
clock.tick(60)
Could someone please tell me how can I prevent the dino to dupe each time space is pressed and for the dino to come back to the ground.
You have to override everything before drawing new things to the screen.
Add this at the beginning of your loop:
gameDisplay.fill(color)

How do you make your sprite not replicate itself in the screen? How do you make your sprite go away or start again, once the text appears?

So, I got stuck again, but I use this as a last resort when nothing's working after extensive research. Please don't roast me for this, I am a newbie. So, basically I am trying to make my sprite move (yoyo), but the frames keep replicating as the yoyo moves up and down. So, I don't know how to fix that. If the yoyo touches the borders of the game window, it collides and it's supposed to display a text and then the game starts over again. However, when the yoyo collides with the window border, it restarts, but the yoyo that got stuck is still being displayed and a new yoyo appears. The text is displayed but doesn't go away after 2 seconds.
import pygame
import time
pygame.init()
width = 900
height = 900
red = (255,0,0)
text = "game over"
screem = pygame.display.set_mode((width,height))
pygame.display.set_caption("yoyo")
clock = pygame.time.Clock()
background = pygame.image.load("room.png").convert()
win.blit(background, [0,0])
yoyo= pygame.image.load("yoyo.png").convert()
def Yoyo (x,y):
win.blit(yoyo, [x,y])
def mainloop():
x = 87
y = 90
yc = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Exit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
Yoyo(x,y)
y += yc
if y > 23 or y < -90:
pygame.display.update()
clock.tick(60)
mainloop()
pygame.quit()
quit()
Redraw the entire scene in every frame. This means you've to draw the background in every frame, too.
Draw (blit) the background in the main loop, before anything else is drawn:
while not Exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Exit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
y_change = -5
elif event.key == pygame. K_DOWN:
y_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_change = 0
y += y_change
if y > 405 or y < -200:
collision()
GameLoop()
win.blit(bg, [0,0]) # <----- draw background
Bee(x,y) # <----- draw the bee on the background
# [...] all further drawing has to be done here
pygame.display.update()
clock.tick(60)

Python game over screen won't accept input

I'm trying to make it so when the game over screen shows the user can press space to get back into the game. Currently, when a game over happens, it displays the game over screen but accepts no input or at least doesn't do anything with the input. For some context, the game is basically about moving left and right to avoid obstacles. Currently, I only have one obstacle, but I just have not gotten to that yet. Thanks!
import pygame
import random
import math
pygame.init()
screenWidth = 700
screenHeight = 800
x = screenWidth / 2
y = (screenHeight / 4) * 3
width = 50
height = 50
win = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Test Game")
bg = pygame.image.load("background.png").convert()
gameover = pygame.image.load("gameover.png").convert()
bgx = (screenWidth / 6) * 2
bgy = 0
clock = pygame.time.Clock()
class enemy():
def __init__(self,c,y,width,height):
self.c = c
self.y = y
self.width = width
self.height = height
self.vel = 5
def draw(self, win):
if self.c == 1:
self.x = 250
#250
elif self.c == 2:
self.x = 350
#350
else:
self.x = 450
#450
self.y += self.vel
pygame.draw.rect(win, (0,0,255), (self.x,self.y,self.width,self.height))
evil = enemy(random.randint(1,3),0,50,50)
#def redrawGameWindow():
# evil.draw(win)
# pygame.display.update()
running = True
gameOver = False
while running:
clock.tick(60)
while gameOver:
win.blit(gameover, (0,0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
if pygame.event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
gameOver = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
x+=100
if event.key == pygame.K_LEFT:
x-=100
win.fill((0,0,0))
win.blit(bg, (bgx, bgy))
evil.draw(win)
dist = math.hypot(evil.x - x, evil.y - y)
if dist <= 50:
print("Game Over!")
running = False
gameOver = True
pygame.draw.rect(win, (255,0,0), (x,y,width,height))
pygame.display.update()
#redrawGameWindow()
while gameOver:
win.blit(gameover, (0,0))
pygame.display.update()
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
gameOver = False
pygame.quit()
The main problem is that your game over scene is the loop behind the main while running: loop and there's no way to go back to the first loop when you reach it. When you touch the evil object, you set running = False, leave the main and enter the while gameOver: loop.
In this loop you also need to call pygame.event.pump(), otherwise the pygame.key.get_pressed() function doesn't work correctly and the window freezes after a while because the events are not handled. If you want to restart the game, you should rather use only the nested while gameOver loop. Actually, I would recommend that you restructure the scenes even more and use a finite state machine instead (here's an answer in which I use functions as scenes but check out the link in the comment below as well).
Here's a working version of your code. I've changed a few things and added comments to explain the changes.
while running:
# -----The game over scene.-----
while gameOver:
for event in pygame.event.get():
if event.type == pygame.QUIT:
# pygame.quit only uninitializes the pygame modules and
# doesn't quit the program.
pygame.quit()
# This will quit the whole program. You need to import sys.
sys.exit()
elif event.type == pygame.KEYUP: # event.type not pygame.event.type
if event.key == pygame.K_SPACE:
# Change it to False to break out of the loop.
gameOver = False
# Reset the game. You could reset the position of the
# `evil` object or instantiate a new one.
evil.x = 350
evil.y = 0
win.blit(gameover, (0,0))
pygame.display.update()
clock.tick(60) # You need to call tick in this loop as well.
# ------------------------------
# -----The main scene.-----
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
x += 100
elif event.key == pygame.K_LEFT:
x -= 100
win.fill((0,0,0))
win.blit(bg, (bgx, bgy))
evil.draw(win)
dist = math.hypot(evil.x - x, evil.y - y)
if dist <= 50:
print("Game Over!")
# running = False # This would stop the main loop.
gameOver = True
pygame.draw.rect(win, (255,0,0), (x,y,width,height))
pygame.display.update()
clock.tick(60)
# The other while loop was removed.
pygame.quit()

python pygame doesn't recognize keyboard event

I want to make a program where I move a rectangle via the keyboard, but it doesn't move like it doesn't understand the event commands. I can't find what's wrong. I think the problem is the sequence of commands, but as a beginner, I can't find it. Can anyone help me? Thanks!
import pygame
import sys
from pygame.locals import *
fps = 30
fpsclock = pygame.time.Clock()
w = 640
h = 420
blue = (0, 0, 255)
white = (255, 255, 255)
x = w / 3
y = 350
boxa = 20
movex = 0
def drawwindow():
global screen
pygame.init()
screen = pygame.display.set_mode((w, h))
screen.fill(blue)
def drawbox(box):
if box.right > (w - boxa):
box.right = (w - boxa)
if box.left < 0:
box.left = 0
pygame.draw.rect(screen, white, box)
def main():
global x
global movex
drawwindow()
box1 = pygame.Rect(x, y, boxa, boxa)
drawbox(box1)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_RIGHT:
movex = +4
if event.key == K_LEFT:
movex = -4
if event.type == KEYUP:
if event.key == K_RIGHT:
movex = 0
if event.key == K_LEFT:
movex = 0
x += movex
pygame.display.update()
fpsclock.tick(fps)
if __name__ == '__main__':
main()
Keyboard events are being accepted properly. That can be verified by sticking a print statement inside one of the if event.key == ... blocks.
One of the problems is you are never redrawing the box after initially drawing it. Every iteration of the game loop should redraw the background (ideally only the area that changes, but that's for later) and the box in its new position. Something like this:
while True:
# [event handling code omitted for brevity]
x += movex
drawwindow()
drawbox(box1)
pygame.display.update()
fpsclock.tick(fps)
However there's another problem. Changing x or movex has no effect on anything, because they are not used anywhere once the main loop is entered. Rather than x += movex, the box would move if its x attribute was changed, as in the following code:
while True:
# [event handling code omitted for brevity]
box1.x += movex # this line changed
drawwindow() # this line added
drawbox(box1) # this line added
pygame.display.update()
fpsclock.tick(fps)
Running your code with the changes above, the box now moves.

I am unable to make an object move from point A to point B without user input using python 2.7 with pygame

I am attempting to make a game where the 'player' (who spawns as the moon furthest to the right) can move around using the 'WASD' keys and enemies fall from the top of the screen in order to hit the player and end the game. I am currently doing this for an assignment and i have set up a test to see whether it is possible for me to do this and so far i have been able to create a 'player' object that is controllable by the 'WASD' keys and make a screen which requires players to press 'SPACE' to play the game. I am having trouble though with being able to have the enemies fall on the 'Y' axis down the screen smoothly. The picture moves down the screen only when the user presses or releases a key, this creates a jagged movement or when the user moves the mouse over the pygame screen, creating a very smooth movement.
#import necessary modules and pygame.
import pygame, sys, random
from pygame.locals import *
#set global variables
pygame.init()
WINDOWWIDTH = 800
WINDOWHEIGHT = 800
BACKGROUNDCOLOUR = (255,255,255)
TEXTCOLOUR = (0,0,0)
FPS = 30
ENEMYMINSIZE = 10
BOMBSAWAY = -1
ENEMYMAXSIZE = 40
ENEMYMINSPEED = 1
ENEMYMAXSPEED = 10
ADDNEWENEMYRATE = 5
PLAYERMOVERATE = 5
FSIZE = 48
BLUE = (0,0,255)
global PLAY
PLAY = False
global fpsClock
fpsClock = pygame.time.Clock()
# set up pygame and GUI
MainClock = pygame.time.Clock()
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
windowSurface.fill(BACKGROUNDCOLOUR)
pygame.display.set_caption('Bubble Dash')
enemy = pygame.image.load('player.jpg')
char = pygame.image.load('player.jpg')
# set up fonts
basicFont = pygame.font.SysFont(None, 48)
# set up the text
text = basicFont.render('Press any key to play!', True, (255,255,0))
textRect = text.get_rect()
textRect.centerx = windowSurface.get_rect().centerx
textRect.centery = windowSurface.get_rect().centery
# draw the text onto the surface
# set up x and y coordinates
# music
windowSurface.blit(text, textRect)
def playgame(PLAY):
x,y = 0,0
movex,movey = 0,0
charx=300
chary=200
direction = 'down'
enemyx= 10
enemyy=10
while PLAY:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == ord('m'):
pygame.mixer.music.stop()
if event.key == ord('n'):
pygame.mixer.music.play()
if event.key == ord('a'):
movex = -0.5
if event.key == ord('d'):
movex = 0.5
if event.key == ord('w'):
movey = -0.5
if event.key == ord('s'):
movey = 0.5
if event.type ==KEYUP:
if event.key == ord('a'):
movex = 0
if event.key == ord('d'):
movex = 0
if event.key == ord('w'):
movey = 0
if event.key == ord('s'):
movey = 0
if direction == 'down':
enemyy += 7
windowSurface.fill(BLUE)
windowSurface.blit(char, (charx, chary))
windowSurface.blit(enemy, (enemyx, enemyy))
pygame.display.update()
charx+=movex
chary+=movey
def playertopresskey(PLAY):
while True: # main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_SPACE:
PLAY = True
if PLAY == True:
playgame(PLAY)
pygame.display.update()
playertopresskey(PLAY)
I would like for the 'enemy' object to be able to fall from the top without the user either needing to keypress or to key up or to have to move the mouse on the screen, rather the 'enemy' would just fall from the top as soon as the subroutine is called.
You may need to tweak it a bit because it is set up for me at the moment but i deleted a few things that would give you bother. Hopefully someone can help me. Thanks.
The below is link to a picture similar to mine which you can download and replace in the code for both the 'char' and the 'enemy' variables to view this yourself for i cannot access the courses at the present time.
http://www.roleplaygateway.com/roleplay/the-five-elements/characters/miss-joy/image
I found your error, you would have caught it yourself if you would have divided your code into some functions. Here is the problem:
for event in pygame.event.get():
if event.type == QUIT:
...
if event.type == KEYDOWN:
...
if event.type == KEYUP:
...
if direction == 'down':
enemyy += 7
your code moving the enemy is called only when an event is waiting in the queue. Move it out of the loop, and you will be good to go.
You have to change indention for:
if direction == 'down':
enemyy += 7
Now it is inside for event in pygame.event.get():

Categories

Resources