I'm totally new to pygame. I'm trying to reproduce a flappy bird in order to experiment this library.
My issue is this one. I have methods within a Bird class.
But when I use the moveBird method, the sprite is visible, but not when I use the BirdDown method and I'm not sure why. I first thought it was because it wasn't updating the sprite inside the loop so I try to blit inside it but still nothing. Some explanation would be appreciate thank you.
import pygame
from pygame.locals import *
WIDTH = 640
HEIGHT = 480
class Bird:
def __init__(self, y, window):
self.sprite = pygame.image.load('bird.png').convert()
self.velocity = 1
self.position = y
self.window = window
def getPosition(self):
return self.position
def getSpeed(self):
return self.speed
def moveBird(self):
self.position += self.velocity
def birdUpdate(self):
self.window.blit(self.sprite, (0, self.position))
def BirdDown(self):
while self.position != HEIGHT:
self.birdUpdate()
self.position += self.velocity
and this is the main of the project
import pygame
from pygame.locals import *
import sys
from bird import Bird, WIDTH, HEIGHT
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Flappy Bird Clone")
te = Bird(0, screen)
def redraw():
te.moveBird()
#te.BirdDown()
te.birdUpdate()
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
redraw()
Why is there loop in the BirdDown method? What do you expect?
You have to use the application loop. Remove the loop from Bird.birdDown:
class Bird:
# [...]
def birdDown(self):
self.position += self.velocity
Call te.birdDown() in the application loop:
def redraw():
screen.fill(0)
te.birdUpdate()
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygme.K_SPACE:
te.moveBird()
te.birdDown()
redraw()
Related
im trying to get my image (bird) to move up and down on the screen but i cant figure out how to do it here is what i tried im sure its way off but im trying to figure it out if anyone can help that would be great!
import pygame
import os
screen = pygame.display.set_mode((640, 400))
running = 1
while running:
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = 0
screen.fill([255, 255, 255])
clock = pygame.time.Clock()
clock.tick(0.5)
pygame.display.flip()
bird = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
screen.blit( bird, ( 0, 0 ) )
pygame.display.update()
class game(object):
def move(self, x, y):
self.player.center[0] += x
self.player.center[1] += y
if event.key == K_UP:
player.move(0,5)
if event.key == K_DOWN:
player.move(0,-5)
game()
im trying to get it to move down on the down button press and up on the UP key press
As stated by ecline6, bird is the least of your worries at this point.
Consider reading this book..
For now, First let's clean up your code...
import pygame
import os
# let's address the class a little later..
pygame.init()
screen = pygame.display.set_mode((640, 400))
# you only need to call the following once,so pull them out of the while loop.
bird = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
clock = pygame.time.Clock()
running = True
while running:
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = False
screen.fill((255, 255, 255)) # fill the screen
screen.blit(bird, (0, 0)) # then blit the bird
pygame.display.update() # Just do one thing, update/flip.
clock.tick(40) # This call will regulate your FPS (to be 40 or less)
Now the reason that your "bird" is not moving is:
When you blit the image, ie: screen.blit(bird, (0, 0)),
The (0,0) is constant, so it won't move.
Here's the final code, with the output you want (try it) and read the comments:
import pygame
import os
# it is better to have an extra variable, than an extremely long line.
img_path = os.path.join('C:\Python27', 'player.png')
class Bird(object): # represents the bird, not the game
def __init__(self):
""" The constructor of the class """
self.image = pygame.image.load(img_path)
# the bird's position
self.x = 0
self.y = 0
def handle_keys(self):
""" Handles Keys """
key = pygame.key.get_pressed()
dist = 1 # distance moved in 1 frame, try changing it to 5
if key[pygame.K_DOWN]: # down key
self.y += dist # move down
elif key[pygame.K_UP]: # up key
self.y -= dist # move up
if key[pygame.K_RIGHT]: # right key
self.x += dist # move right
elif key[pygame.K_LEFT]: # left key
self.x -= dist # move left
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
pygame.init()
screen = pygame.display.set_mode((640, 400))
bird = Bird() # create an instance
clock = pygame.time.Clock()
running = True
while running:
# handle every event since the last frame.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # quit the screen
running = False
bird.handle_keys() # handle the keys
screen.fill((255,255,255)) # fill the screen with white
bird.draw(screen) # draw the bird to the screen
pygame.display.update() # update the screen
clock.tick(40)
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action or a step-by-step movement.
If you want to achieve a continuously movement, you have to use pygame.key.get_pressed(). pygame.key.get_pressed() returns a list with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.
See also Key and Keyboard event and How can I make a sprite move when key is held down.
Minimal example:
import pygame
import os
class Bird(object):
def __init__(self):
self.image = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
self.center = [100, 200]
def move(self, x, y):
self.center[0] += x
self.center[1] += y
def draw(self, surf):
surf.blit(self.image, self.center)
class game(object):
def __init__(self):
self.screen = pygame.display.set_mode((640, 400))
self.clock = pygame.time.Clock()
self.player = Bird()
def run(self):
running = 1
while running:
self.clock.tick(60)
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = 0
keys = pygame.key.get_pressed()
move_x = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]
move_y = keys[pygame.K_DOWN] - keys[pygame.K_UP]
self.player.move(move_x * 5, move_y * 5)
self.screen.fill([255, 255, 255])
self.player.draw(self.screen)
pygame.display.update()
g = game()
g.run()
Below I have a fighting game, where once a player has been pushed off the screen the game ends and has the option to restart. My problem is that after the restart takes place, wherever the winner was standing a clone (or stamp, or image, or ghost, or blit) remains permanently (even after multiple rounds/deaths). What do I need to fix so that the background is correctly refilled over the old locations? I've tried adding screen.fill() in several places to no avail.
class Game:
def __init__(self):
self.all_sprites = pg.sprite.Group()
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
self.playing = True
def new(self):
# RESET PLAYERS
self.player1 = Player(self, 2, FLOOR, RED)
self.player2 = Player(self, 7, FLOOR, BLUE)
return z.run()
def run(self):
# LOOP
while self.playing:
self.events()
self.update()
self.draw()
def events(self):
# INPUT
for event in pg.event.get():
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
pg.quit()
sys.exit()
# MOVE
if event.key == pg.K_a:
self.player1.move(dx=-1)
if event.key == pg.K_RIGHT:
self.player2.move(dx=1)
# DIE
if z.player1.x < 0:
return z.encore()
def update(self):
# CHANGE INTERNAL PLAYER DATA
self.all_sprites.update()
def draw(self):
# CHANGE PLAYER PHENOMENA
z.screen.fill(BACKGROUND)
z.all_sprites.draw(z.screen)
pg.display.flip()
def encore(self):
# PLAY AGAIN?
curtain = True
while curtain:
z.screen.fill(RED)
for event in pg.event.get():
if event.type == pg.KEYDOWN:
return z.new()
z = Game()
z.new()
And here below my Player class:
class Player(pg.sprite.Sprite):
def __init__(self, game, x, y, color):
self.groups = game.all_sprites
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.image = pg.Surface((TILESIZE, TILESIZE))
self.image.fill(color)
self.rect = self.image.get_rect()
self.x = x
self.y = y
def move(self, dx=0):
self.x += dx
def update(self):
self.rect.x = int(self.x * TILESIZE)
self.rect.y = int(self.y * TILESIZE)
New to programming; hopefully this wasn't overkill to include all of this code; believe it or not this actually took me a long time to reduce it under 100 lines.. Thank you for your time!
This occurs because the all_sprites variable is not being reset after each game instance. Because of this, the previous game's sprites are still being drawn, even though they are not connected to a Player. This can be solved with the Group.empty() function, such as:
def encore(self):
# PLAY AGAIN?
curtain = True
while curtain:
z.screen.fill(RED)
for event in pg.event.get():
if event.type == pg.KEYDOWN:
self.all_sprites.empty()
return z.new()
Additionally, it appears that the z.screen.fill(RED) has no effect because the display isn't updated during the loop. This can be solved by adding pg.display.flip() after.
import pygame
import random
import math
import sys
screenWidth = 1200
screenHeight = 600
class Hero:
def __init__(self, pos):
self.pos = pos
self.width = 30
self.height = 30
self.color = (0, 0, 0)
self.dirX = 0
self.dirY = 0
def move(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.dirX = 1
elif event.key == pygame.K_LEFT:
self.dirX = -1
def draw(self, display):
x = self.pos[0]
y = self.pos[1]
pygame.draw.rect(display, self.color, (x + self.dirX, y + self.dirY, self.width, self.height))
print(self.pos, self.dirX, self.dirY)
def jump(self):
pass
def die(self):
pass
class Enemy:
pass
class Background:
pass
class Obstacles:
pass
class Camera:
pass
def score():
pass
def create(w, h):
display = pygame.display.set_mode((w, h))
display.fill((255, 255, 255))
#create background
#create Obstacles
#create Hero
heroOne = Hero([150, 450])
heroOne.move()
heroOne.draw(display)
#create Enemy
pygame.display.update()
def main():
pygame.init()
clock = pygame.time.Clock()
running = True
while running:
clock.tick(300)
create(screenWidth, screenHeight)
main()
Hi, I am making an OOP Game using Pygame in which a square would be controlled by the user and move along a floor, jump over obstacles and other enemy squares.
The way I want it to work:
When I press K_LEFT, dirX = 1 it will add to the x-coordinate of the pos and hence the x-position of the square will be updated and the square will begin to slide towards the right. When I press dir = -1and square will move to the left.
The way it is working:
No
I think the problem is the pos of the main cube does not seem to update and the dirX updates from 0 to 1 and goes back to 0.
I guess changing the values of the variables under the __init__() function is done as I am doing it or perhaps it is completely wrong.
Is this any way to make my code work the way I am trying to do it or is it completely a wrong way and there is some other way?
I am learning OOP and python, any additional advice or links regarding the best practices, relating to this code, would be highly appreciated.
Thank you.
First of all you've to invoke move in the main application loop:
def main():
pygame.init()
display = pygame.display.set_mode((screenWidth, screenHeight))
clock = pygame.time.Clock()
heroOne = Hero([150, 450])
running = True
while running:
clock.tick(300)
display.fill((255, 255, 255))
heroOne.move()
heroOne.draw(display)
pygame.display.update()
You have to change the position of the player by self.dirX and self.dirY, in every frame:
class Hero:
# [...]
def move(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.dirX = 1
elif event.key == pygame.K_LEFT:
self.dirX = -1
new_x = self.pos[0] + self.dirX
new_y = self.pos[1] + self.dirY
self.pos = [new_x , new_y]
def draw(self, display):
pygame.draw.rect(display, self.color, (*self.pos, self.width, self.height))
If you wan to move the rectangle, just when a key is pressed, then I recommend to use pygame.key.get_pressed rather than the KEYDOWN event:
class Hero:
# [...]
def move(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.pos[0] -= 1
if keys[pygame.K_RIGHT]:
self.pos[0] += 1
if keys[pygame.K_UP]:
self.pos[1] -= 1
if keys[pygame.K_DOWN]:
self.pos[1] += 1
Complete code:
import pygame
import random
import math
import sys
screenWidth = 1200
screenHeight = 600
class Hero:
def __init__(self, pos):
self.pos = pos
self.width = 30
self.height = 30
self.color = (0, 0, 0)
self.dirX = 0
self.dirY = 0
def move(self, events):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.pos[0] -= 1
if keys[pygame.K_RIGHT]:
self.pos[0] += 1
if keys[pygame.K_UP]:
self.pos[1] -= 1
if keys[pygame.K_DOWN]:
self.pos[1] += 1
def draw(self, display):
pygame.draw.rect(display, self.color, (*self.pos, self.width, self.height))
def jump(self):
pass
def die(self):
pass
class Enemy:
pass
class Background:
pass
class Obstacles:
pass
class Camera:
pass
def score():
pass
def main():
pygame.init()
display = pygame.display.set_mode((screenWidth, screenHeight))
clock = pygame.time.Clock()
heroOne = Hero([150, 450])
running = True
while running:
clock.tick(300)
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
heroOne.move(events)
display.fill((255, 255, 255))
heroOne.draw(display)
pygame.display.update()
main()
In your create function you are creating new instance of the Hero each time its being called.
Instead, init heroOne in the main, and pass it as an argument so you can use it:
def main():
pygame.init()
heroOne = Hero([150, 450])
clock = pygame.time.Clock()
running = True
while running:
clock.tick(30)
create(screenWidth, screenHeight, heroOne)
Also add increment in the move method:
self.dirX += 1
and:
self.dirX -= 1
Now the object will move by one on each keypress.
And if you want continuous movement you should put some flag, e.g. if it is True +=1 and "False" -=1 and key presses will change the flag state.
I'm trying to recreate Agar.io in Python using pygame. So far I've been able to somewhat simulate the player movement, but then I tried to generate some "food cells" at a given interval using the pygame.time.set_timer() method, but even though the rest of the game elements are being drawn, such as the screen and the player, these food cells are only drawn (and added to the "food_list" list) when I drag the game window around. I think this might be an issue of me not really knowing how to deal with the event queue.
main.py, which is where the game loop is located:
import sys, pygame
from player import Player
from food import Food
import random
pygame.init()
SCREEN_SIZE = [1024, 768]
WHITE = (255, 255 , 255)
generate_food = pygame.USEREVENT + 1
screen = pygame.display.set_mode(SCREEN_SIZE)
screen.fill(WHITE)
player = Player()
food_list = []
## TODO: Make a separate GameScreen class.
## TODO: Make a list of constants
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == generate_food:
food_x = random.randrange(0, 760)
food_y = random.randrange(0, 1000)
food_list.append(Food(food_x, food_y))
pygame.time.set_timer(generate_food, 200)
screen.fill(WHITE)
for f in food_list:
f.draw(screen)
player.update()
player.draw(screen)
pygame.display.flip()
food.py:
import pygame
import random
from cell import Cell
DARK_GREEN = (0, 102, 0)
class Food(Cell):
def __init__(self, x, y):
super().__init__()
self.size = 2
self.image = pygame.Surface([2, 2])
self.image.fill(DARK_GREEN)
self.rect = self.image.get_rect()
self.x = x
self.y = y
def draw(self, screen):
pygame.draw.circle(screen, DARK_GREEN, (self.x, self.y), self.size, 0)
def getX(self):
return self.x
def getY(self):
return self.y
Actually the timer is restarted continuously in the application loop. However pygame.time.set_timer() crates a timer that repeatedly create a USEREVENT in the event queue. Hence it is sufficient to start the timer once before the application loop:
pygame.time.set_timer(generate_food, 200) # <--- ADD
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == generate_food:
food_x = random.randrange(0, 760)
food_y = random.randrange(0, 1000)
food_list.append(Food(food_x, food_y))
# pygame.time.set_timer(generate_food, 200) <--- DELTE
im trying to get my image (bird) to move up and down on the screen but i cant figure out how to do it here is what i tried im sure its way off but im trying to figure it out if anyone can help that would be great!
import pygame
import os
screen = pygame.display.set_mode((640, 400))
running = 1
while running:
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = 0
screen.fill([255, 255, 255])
clock = pygame.time.Clock()
clock.tick(0.5)
pygame.display.flip()
bird = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
screen.blit( bird, ( 0, 0 ) )
pygame.display.update()
class game(object):
def move(self, x, y):
self.player.center[0] += x
self.player.center[1] += y
if event.key == K_UP:
player.move(0,5)
if event.key == K_DOWN:
player.move(0,-5)
game()
im trying to get it to move down on the down button press and up on the UP key press
As stated by ecline6, bird is the least of your worries at this point.
Consider reading this book..
For now, First let's clean up your code...
import pygame
import os
# let's address the class a little later..
pygame.init()
screen = pygame.display.set_mode((640, 400))
# you only need to call the following once,so pull them out of the while loop.
bird = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
clock = pygame.time.Clock()
running = True
while running:
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = False
screen.fill((255, 255, 255)) # fill the screen
screen.blit(bird, (0, 0)) # then blit the bird
pygame.display.update() # Just do one thing, update/flip.
clock.tick(40) # This call will regulate your FPS (to be 40 or less)
Now the reason that your "bird" is not moving is:
When you blit the image, ie: screen.blit(bird, (0, 0)),
The (0,0) is constant, so it won't move.
Here's the final code, with the output you want (try it) and read the comments:
import pygame
import os
# it is better to have an extra variable, than an extremely long line.
img_path = os.path.join('C:\Python27', 'player.png')
class Bird(object): # represents the bird, not the game
def __init__(self):
""" The constructor of the class """
self.image = pygame.image.load(img_path)
# the bird's position
self.x = 0
self.y = 0
def handle_keys(self):
""" Handles Keys """
key = pygame.key.get_pressed()
dist = 1 # distance moved in 1 frame, try changing it to 5
if key[pygame.K_DOWN]: # down key
self.y += dist # move down
elif key[pygame.K_UP]: # up key
self.y -= dist # move up
if key[pygame.K_RIGHT]: # right key
self.x += dist # move right
elif key[pygame.K_LEFT]: # left key
self.x -= dist # move left
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
pygame.init()
screen = pygame.display.set_mode((640, 400))
bird = Bird() # create an instance
clock = pygame.time.Clock()
running = True
while running:
# handle every event since the last frame.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # quit the screen
running = False
bird.handle_keys() # handle the keys
screen.fill((255,255,255)) # fill the screen with white
bird.draw(screen) # draw the bird to the screen
pygame.display.update() # update the screen
clock.tick(40)
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action or a step-by-step movement.
If you want to achieve a continuously movement, you have to use pygame.key.get_pressed(). pygame.key.get_pressed() returns a list with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.
See also Key and Keyboard event and How can I make a sprite move when key is held down.
Minimal example:
import pygame
import os
class Bird(object):
def __init__(self):
self.image = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
self.center = [100, 200]
def move(self, x, y):
self.center[0] += x
self.center[1] += y
def draw(self, surf):
surf.blit(self.image, self.center)
class game(object):
def __init__(self):
self.screen = pygame.display.set_mode((640, 400))
self.clock = pygame.time.Clock()
self.player = Bird()
def run(self):
running = 1
while running:
self.clock.tick(60)
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = 0
keys = pygame.key.get_pressed()
move_x = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]
move_y = keys[pygame.K_DOWN] - keys[pygame.K_UP]
self.player.move(move_x * 5, move_y * 5)
self.screen.fill([255, 255, 255])
self.player.draw(self.screen)
pygame.display.update()
g = game()
g.run()