pipes spawning too fast in flappy bird pygame - python-3.x

Im working on this flappy bird pygame tutorial and when I tested the code the pipes spawned in too fast. I'm using a tutorial since I'm fairly new to python and would appreciate any help. Thanks. Here is the link to the tutorial website: https://github.com/clear-code- projects/FlappyBird_Python/blob/master/flappy.py
Here is the code I have so far.
import pygame
import sys
import os
from random import randint
def draw_floor():
screen.blit(floor_surface,(floor_x_pos,750))
screen.blit(floor_surface,(floor_x_pos + 576,750))
def create_pipe():
new_pipe = pipe_surface.get_rect(midtop = (288,375))
return new_pipe
def move_pipes(pipes):
for pipe in pipes:
pipe.centerx -= 5
return pipes
def draw_pipes(pipes):
for pipe in pipes:
if pipe.bottom >= 750:
screen.blit(pipe_surface,pipe)
pygame.init()
screen = pygame.display.set_mode((576,855))
clock = pygame.time.Clock()
# Game variables
gravity = 0.25
bird_movement = 0
bg_surface = pygame.transform.scale2x(pygame.image.load(os.path.join('imgs','bg.png')).convert_alpha())
floor_surface = pygame.transform.scale2x(pygame.image.load(os.path.join('imgs','base.png')).convert_alpha())
floor_x_pos = 0
bird_surface = pygame.transform.scale2x(pygame.image.load(os.path.join('imgs','bird2.png')).convert_alpha())
bird_rect = bird_surface.get_rect(center = (100,427))
pipe_surface = pygame.transform.scale2x(pygame.image.load(os.path.join('imgs','pipe.png')))
pipe_list = []
SPAWNPIPE = pygame.USEREVENT
pygame.time.set_timer(SPAWNPIPE,5000)
pipe_height = [300,500,700]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bird_movement = 0
bird_movement -= 12
if event.type == SPAWNPIPE:
pipe_list.extend(create_pipe())
# bird
screen.blit(bg_surface,(0,0))
bird_movement += gravity
bird_rect.centery += int(bird_movement)
screen.blit(bird_surface,bird_rect)
# pipes
pipe_list = move_pipes(pipe_list)
draw_pipes(pipe_list)
floor_x_pos -= 1
draw_floor()
if floor_x_pos <= -576:
floor_x_pos = 0
pygame.display.update()
clock.tick(120)`

Indent the SPAWNPIPE check:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bird_movement = 0
bird_movement -= 12
if event.type == SPAWNPIPE: # indent this
pipe_list.extend(create_pipe())

The issue is that once you get the first SPAWNPIPE event, the event.type condition for adding a new pipe becomes True.
However, due to improper indentation, that condition is repeatedly checked every frame until the next event is received. This means the code is continually spawning pipes every frame during this time.
Fix the indentation, to bring the pipe-event check back inside the event for-loop:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bird_movement = 0
bird_movement -= 12
if event.type == SPAWNPIPE: # <<-- HERE
pipe_list.extend(create_pipe()) # <<-- AND HERE
Which makes the SPAWNPIPE check be performed only when the event is actually received.

Related

How do you break out of while loop by pressing a gamepad button (User Input)

I am using pygame just so that I can use the xbox controller on my script. My goal is to press a button to start a repeating task, and then be able to press another button to break out of the repeating task. I should then be able to press the original button to resume the task.
Before I even post the code, I know the crux of my problem is this part here: (something wrong with my indentation but the code works).
while True:
schedule.run_pending()
time.sleep(1)
How do I break out of this while loop so that I can use the next button JOYHATMOTION: Basically I would be using JOYHATMOTION to pause the job function.
Here is the code. It prints "Hello World" every five seconds for 200 seconds.
import schedule
from datetime import datetime, timedelta, time
import time
import sys
import pygame
from pygame.locals import *
pygame.init()
def job():
print('Hello World')
pygame.joystick.init()
joysticks = [pygame.joystick.Joystick(i) for i in range(pygame.joystick.get_count())]
for joystick in joysticks:
print(joystick.get_name())
while True:
for event in pygame.event.get():
if event.type == JOYBUTTONDOWN:
print(event)
if event.button == 8:
schedule.every(5).seconds.until(timedelta(seconds=200)).do(job)
while True:
schedule.run_pending()
time.sleep(1)
if event.type == JOYHATMOTION:
if event.value[0] == 1:
print(event)
if event.value[0] == -1:
print(event)
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
I have tried:
while True:
if event.type == JOYHATMOTION:
if event.value[0] == 1:
break
else:
schedule.run_pending()
time.sleep(1)
but this dosent seem to work. Thank You in advance.
Never try to control the application with a loop inside the application loop. Use the application loop. The application loop is continuously executed. Use a game_state variable that indicates the current state of the application. Execute the code in the application depending on the state of the variable.
With this approach, you can easily change the state back when another key is pressed.
game_state = ""
run = True
while run:
for event in pygame.event.get():
if event.type == QUIT:
run = False
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
run = False
if event.type == JOYBUTTONDOWN:
print(event)
if event.button == 8:
if game_state == "schedule":
game_state = "" # schedule off
else:
game_state = "schedule" # schedule on
schedule.every(5).seconds.until(timedelta(seconds=200)).do(job)
if event.type == JOYHATMOTION:
if event.value[0] == 1:
print(event)
if event.value[0] == -1:
print(event)
if game_state == "schedule":
schedule.run_pending()
# [...]
pygame.quit()
sys.exit()

Why does pygame.time.wait kick in before display update?

I have written a code for a game where you slide 15 tiles to set them in order. At the end of the game, I want the screen to just wait for 5 seconds before closing (also want to give a message but that later).
When the game ends, it first pauses and then shows the last move and then closes out. Is there a lag in the display. How do I make it complete the display, and then wait. I tried reading similar posts, but couldn't quite understand.
Here is the relevant code.
> def run_game(self):
"""Start the main loop for the game"""
self._shuffle_grid()
self._show_board()
game_over = False
while True:
change = self._check_events()
if change:
self._show_board()
game_over = self.end_of_game()
if game_over:
pygame.time.wait(5000)
sys.exit()
def _check_events(self):
# Watch for keyboard and mouse events
change = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
key = "U"
elif event.key == pygame.K_DOWN:
key = "D"
elif event.key == pygame.K_LEFT:
key = "L"
elif event.key == pygame.K_RIGHT:
key = "R"
if key == "U" or "D" or "L" or "R":
change = self.key_check(key)
return(change)
I actually tried this and it worked. I still don't know how to show a message and then wait 5 seconds. Working on it.
def celebrate(self):
""" does end of game thing"""
game_clock = pygame.time.Clock()
time_passed = pygame.time.get_ticks()
self._show_board()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
sys.exit()
if pygame.time.get_ticks() > time_passed + 5000:
sys.exit()
def run_game(self):
"""Start the main loop for the game"""
self._shuffle_grid()
self._show_board()
game_over = False
while True:
change = self._check_events()
if change:
game_over = self.end_of_game()
if not game_over:
self._show_board()
else:
self.celebrate()

Can't import any pygame functions (E1101)

When I run the following code, a white screen appears and then quickly disappears. I installed pygame on the VSCode terminal with pip3 (I am on mac) and now that I finally got it to import pygame, I get multiple errors for every function called such as "clock" or "pygame.KEYDOWN". They say "Module 'pygame' has no 'KEYDOWN' member" [E1101]. I also get an error with the "init" member.
I've seen other posts that tell me to copy and paste something into the json settings, but when I tried that I got even more errors.
#Game
#By Robert Smith
#Initialize python
import pygame
pygame.init()
#Set the screen
screen = pygame.display.set_mode((640, 480))
background = pygame.Surface(screen.get_size())
background.fill((255,255,255))
background = background.convert()
screen.blit(background, (0 , 0))
#Make the window exitable
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainloop == False #close the window
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
mainloop = False
#Set the framerate
milliseconds = clock.tick(60)#DO NOT GO FASTER THAN THIS FRAMERATE
Try this:
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainloop == False #close the window
elif event.type == keys[pygame.K_DOWN]:
if event.key == keys[pygame.K_ESCAPE]:
mainloop = False
And this:
milliseconds = pygame.time.Clock.tick(60)

How can I make the character moving when I press a key?

I know it has been asked before but I couldn't get it to work, I'm using idle 3.6 and PyGame.
Here is the code.(I just started I have been watching some tutorials but apart from that I'm new to PyGame)
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
location += 1
You can use a boolean flag to keep track of which key was pressed and released. Something like:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
pressedRight = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
pressedRight = False
# Now in your game loop
if pressedRight:
location += 1
Basically, this code emulates a way to check if the key is pressed at the current time or not, allowing you to use continuous movement.

"video system not initialized" While closing pygame window

I have two similar code snippets. Both run fine but One displays the error When i close the pygame window
Traceback (most recent call last):
File "/home/nabeel/Devalopment/Python/aaa.py", line 92, in <module>
pygame.display.flip()
pygame.error: video system not initialized
Here is the piece of code which throws error
import pygame
pygame.init()
done = False
screen = pygame.display.set_mode([640,480])
pygame.display.set_caption("my_game")
while not done:
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.quit()
pygame.display.flip()
pygame.quit()
and here's the one which does not
import pygame
done = False
pygame.init()
screen_size = [320,240]
white = [255,255,255]
black = [0,0,0]
paddle_x = 0
paddle_y = 0
vel_x = 0
vel_y = 0
gutter = 10
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption("mygame")
while not done:
screen.fill(black)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if pygame.key.get_pressed()[pygame.K_DOWN]:
vel_y += 2
if pygame.key.get_pressed()[pygame.K_UP]:
vel_y -= 2
if pygame.key.get_pressed()[pygame.K_LEFT]:
vel_x -= 2
if pygame.key.get_pressed()[pygame.K_RIGHT]:
vel_x += 2
paddle_x += vel_x
paddle_y += vel_y
pygame.draw.line(screen,white,(gutter,0),(gutter,screen_size[1]))
pygame.draw.line(screen,white,(screen_size[0]-gutter,0),(screen_size[0]-gutter,screen_size[1]))
pygame.draw.rect(screen,white,[screen_size[0]/2,screen_size[1]/2,10,10],0)
pygame.draw.line(screen,white,[paddle_x+5,paddle_y],[paddle_x+5,paddle_y+30],gutter)
pygame.display.flip()
pygame.quit()
While these two do not do any thing harful I was just curious to what is causing all this
Try to remove the pygame.quit() in this block:
if event.type == pygame.QUIT:
done = True
pygame.quit()
The idea is that when pygame.quit() is called, the whole module is uninitialized and hence if more method calls of the module are found (like pygame.display.flip()) they will throw an error :)
If you wish to keep the pygame.quit() method call in the above conditional if statement, what you could do is import the sys module and below pygame.quit() add a sys.exit().
Both ways should work pretty well :)
Hope that helped,
Cheers! Alex

Resources