I'm trying to make a flappy bird AI using OOP, so far everything seem to be working fine except for two problems. First my bird is flapping way to quickly. I created a user event and in the timer I put 200 milliseconds:
birdflap = pygame.USEREVENT
pygame.time.set_timer(birdflap, 200)
but for some reason, the wings are still flapping like crazy and I can't seem to understand what's causing it to do so. Secondly I had a problem with the bird rotating when it falls down. I made a function in my bird class called 'move' that creates gravity for the bird and causes it to turn using rotozoom in pygame to make it turn as it falls down.
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.bird_rect.centery += self.bird_movement
pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
The problem is that once the game starts, it falls but doesn't turn. I honestly don't know where to start with solving both of these issues. My full code is down below if anybody wanted to see what I have so far.
import pygame
import neat
import time
import os
import random
import sys
pygame.init()
clock = pygame.time.Clock()
# VARIABLES THAT DEFINE SCREEN SIZE
screen_width = 500
screen_height = 800
# CLOCK TO SET FRAME RATE
clock = pygame.time.Clock()
# VARIABLES THAT CONTAIN GAME IMAGES
bird_imgs = [pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'yellowbird-upflap.png'))), pygame.transform.scale2x(pygame.image.load(
os.path.join('assets', 'yellowbird-midflap.png'))), pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'yellowbird-downflap.png')))]
bg_img = pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'background-day.png' )))
# TIMER FOR BIRD FLAP IMAGES
birdflap = pygame.USEREVENT
pygame.time.set_timer(birdflap, 200)
class Bird:
img = bird_imgs
gravity = 0.25
def __init__(self, x, y):
self.x = x
self.y = y
self.bird_movement = 0
self.bird_index = 0
self.bird_rect = self.img[self.bird_index].get_rect(center = (self.x, self.y))
def bird_animation(self, win):
if self.bird_index < 2:
self.bird_index += 1
else:
self.bird_index = 0
win.blit(self.img[self.bird_index], self.bird_rect)
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.bird_rect.centery += self.bird_movement
pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
# FUNCTION TO DRAW THE WINDOW
def draw_window(win, bird):
win.blit(bg_img, (0,0))
bird.bird_animation(win)
pygame.display.update()
# MAIN FUNCTION OF OUR GAME
def main():
win = pygame.display.set_mode((screen_width, screen_height))
bird = Bird(200, 200)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == birdflap:
bird.bird_animation(win)
bird.move()
draw_window(win, bird)
clock.tick(60)
pygame.quit()
sys.exit()
main()
I tried using other modules in pygame, but that doesn't seem to solve my issue either. Right now I'm really lost.
The 1st problem is that bird_animation is called in draw_window so the bird is animated all over the time. The 2nd problem is that pygame.transform.rotozoom returns a new but rotated surface (see How do I rotate an image around its center using PyGame?). The method move has to create an image, that is used in an draw method:
class Bird:
img = bird_imgs
gravity = 0.25
def __init__(self, x, y):
self.x = x
self.y = y
self.bird_movement = 0
self.bird_index = 0
self.image = self.img[self.bird_index]
self.rect = self.image.get_rect(center = (self.x, self.y))
def bird_animation(self):
if self.bird_index < 2:
self.bird_index += 1
else:
self.bird_index = 0
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.y += self.bird_movement
self.image = pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
self.rect = self.image.get_rect(center = (self.x, self.y))
def draw(self, win)
win.blit(self.img[self.bird_index], self.bird_rect)
# FUNCTION TO DRAW THE WINDOW
def draw_window(win, bird):
win.blit(bg_img, (0,0))
bird.draw(win)
pygame.display.update()
def main():
win = pygame.display.set_mode((screen_width, screen_height))
bird = Bird(200, 200)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == birdflap:
bird.bird_animation()
bird.move()
draw_window(win, bird)
clock.tick(60)
pygame.quit()
sys.exit()
main()
Related
This question already has answers here:
Pygame doesn't let me use float for rect.move, but I need it
(2 answers)
Closed 1 year ago.
Hello Stackoverflow Community,
could someone help me with my problem.
When I move to the left I am quite fast but when I want to go to the right it takes way to lang. I deleted the dt from my move function and the went the same speed. I changed the buttons but the problem seems only to occure when I use the +=. Does one of you dealt with the problem before and could help me?
import pygame
import time
import random
#0 = Menu, 1 = Game, 2 = Quit
game_state = 1
WHITE = (255, 255, 255)
class Player(pygame.sprite.Sprite):
speed = 100
def __init__(self, WIDTH):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("player.png")
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, 480)
def move(self, keys, dt):
if(keys[0]):
self.rect.x += self.speed * dt
print(self.speed)
print(dt)
print(self.rect.x)
if(keys[1]):
print(self.speed)
print(dt)
self.rect.x -= self.speed * dt
print(self.rect.x)
class Main():
prev_time = time.time()
dt = 0
#initalizing menu or game depending on variables
def __init__(self):
global game_state
while game_state !=2:
WIDTH, HEIGHT = 800, 600
screen = self.initialize_pygame("Alien Slaughter", WIDTH, HEIGHT)
self.all_sprites = pygame.sprite.Group()
self.player = Player(WIDTH)
self.all_sprites.add(self.player)
if(game_state == 1):
self.prev_time = time.time()
self.game(screen, WIDTH, HEIGHT)
#calculating deltatime
def calc_deltatime(self):
self.now = time.time()
self.dt = self.now - self.prev_time
self.prev_time = self.now
#initializing pygame and create window
def initialize_pygame(self, title, width, height):
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption(title)
icon = pygame.image.load("icon.png")
pygame.display.set_icon(icon)
pygame.init()
return screen
def handle_inputs(self, keys, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
keys[0] = True
if event.key == pygame.K_a:
keys[1] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_d:
keys[0] = False
if event.key == pygame.K_a:
keys[1] = False
def game(self, screen, width, height):
global game_state
BLACK = (100, 100, 100)
keys = [False, False]
#Game loop
while game_state == 1:
#Process input (events)
for event in pygame.event.get():
#Check for Closing windows
if event.type == pygame.QUIT:
game_state = 2
self.handle_inputs(keys, event)
self.calc_deltatime()
self.player.move(keys, self.dt)
#Update
self.all_sprites.update()
#Draw / render
screen.fill(BLACK)
self.all_sprites.draw(screen)
pygame.display.update()
game = Main()
Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect object can only store integral data.
The coordinates for Rect objects are all integers. [...]
The fraction part of the coordinates gets lost when the movement is added to the coordinates of the Rect object. If this is done every frame, the position error will accumulate over time.
If you want to store object positions with floating point accuracy, you have to store the location of the object in separate variables respectively attributes and to synchronize the pygame.Rect object. round the coordinate and assign it to the location of the rectangle:
class Player(pygame.sprite.Sprite):
speed = 100
def __init__(self, WIDTH):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("player.png")
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, 480)
self.x = self.rect.x
def move(self, keys, dt):
if keys[0]:
self.x += self.speed * dt
if keys[1]:
self.x -= self.speed * dt
self.rect.x = round(self.x)
This is the image Okay so I am not able to figure out how to delete the previous render of the object every frame from screen so as to not leave a trail behind, in other words I want the object to have the appearance of Movement rather than leaving a bunch of red squares behind it. Image has been inserted for understanding what I mean by "leaving a trail" The following is my code:-
import pygame
import random
WIDTH = 1000
ROWS = 25
WIN = pygame.display.set_mode((WIDTH,WIDTH))
pygame.display.set_caption("Particle Physics")
clock = pygame.time.Clock()
RED = (255, 0, 0)
GRAVITY = 2
wid = 5
class Square:
def __init__(self,x,y,width,color,vel_x,vel_y):
self.x = x
self.y = y
self.width = width
self.color = color
self.velx = vel_x
self.vely = vel_y
def draw(self):
pygame.draw.rect(WIN, self.color, (self.x, self.y, self.width, self.width))
def move(self):
self.x += self.velx
self.y += self.vely
self.vely += GRAVITY[enter image description here][1]
def particles():
pass
def main():
run = True
a,b = 500,300
c = random.randint(-20,20)
d = random.randint(-50,0)
square = Square(a,b,wid, RED, c, d)
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
square.move()
square.draw()
pygame.display.update()
pygame.time.delay(100)
#clock.tick(60)
pygame.quit()
main()
In the main function add the set background color at the start so as to delete the previous frames.
def main()
...
while run
....
screen.fill((255,255,255))
...
Unable to move player in pygame
So, I was trying to create a simple physics system in pygame. My main goal was to add a Y gravity function that would move the player when activated. I have tried several times to make it work, but I guess I am missing something.
Here is the code:
class Physic:
def __init__(self, color, master, type, sizeX, sizeY, pos=[0,0]):
self.master = master
self.color = color
self.type = type
self.sizeX = sizeX
self.sizeY = sizeY
self.x = pos[0]
self.y = pos[1]
self.moveX = 0
self.moveY = 0
self.create_Object()
def create_Object(self):
if self.type == 'rect':
self.rect()
def rect(self):
return pygame.draw.rect(self.master, self.color, (self.x, self.y, self.sizeX, self.sizeY))
def drag(self):
for event in pygame.event.get():
if event.type == pygame.mouse.get_pressed()[0]:
self.x = pygame.mouse.get_pos()
def add_gravity(self):
self.moveY += 3.2
self.update_pos()
def update_pos(self):
self.y += self.moveY
self.x += self.moveX
In the main script I put this:
def game():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(WHITE)
player = object.Physic(BLUE, screen, 'rect', 50, 50, [POS[0], POS[1]])
player.add_gravity()
# platform = object.rect(screen, RED, [30, 30], 100, 30)
# physics.add_collider(player, platform, POS[0])
pygame.display.update()
game()
Do you know what I am missing?
Your big problem is that you are recreating the player every pass inside the main loop and so it looks like it is frozen in place.
You also need to have a limit on the frame rate so that you control the speed of the game and therefor can properly set the acceleration per frame.
There are a some other minor things that needed to be fixed to run this. I tried to change the minimum possible to run it, since the point was to fix the error rather than rewrite it on you. Obviously I had to add some wrapper code around it
Try this slightly adjusted version:
#!/usr/bin/env python
import traceback
import pygame
import sys
FRAME_RATE = 60
GRAVITY = 32
SCREEN_SIZE = (600, 800)
WHITE = pygame.Color("white")
BLUE = pygame.Color("blue")
POS = (100, 600)
class Physic:
def __init__(self, color, master, type, sizeX, sizeY, pos=(0,0)):
self.master = master
self.color = color
self.type = type
self.sizeX = sizeX
self.sizeY = sizeY
self.x = pos[0]
self.y = pos[1]
self.moveX = 0
self.moveY = 0
self.create_Object()
def create_Object(self):
if self.type == 'rect':
self.draw()
def draw(self):
return pygame.draw.rect(self.master, self.color, (self.x, self.y, self.sizeX, self.sizeY))
def drag(self):
for event in pygame.event.get():
#if event.type == pygame.mouse.get_pressed()[0]: <--- remove this
if event.type == pygame.MOUSEBUTTONDOWN:
self.x = pygame.mouse.get_pos()
def add_gravity(self):
self.moveY += GRAVITY / FRAME_RATE
self.update_pos()
def update_pos(self):
self.y += self.moveY
self.x += self.moveX
def game():
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
clock = pygame.time.Clock()
player = Physic(BLUE, screen, 'rect', 50, 50, POS)
# I added this to illustrate the gravity better ... going up and down
player.moveY = -25
player.moveX = 2
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
screen.fill(WHITE)
player.add_gravity()
player.draw()
# platform = object.rect(screen, RED, [30, 30], 100, 30)
# physics.add_collider(player, platform, POS[0])
pygame.display.update()
clock.tick(FRAME_RATE)
def main():
try:
game()
except Exception as ex:
print(traceback.format_exc())
raise
finally:
# game exit cleanup stuff
pygame.quit()
if __name__ == '__main__':
main()
An issue that I want to point out though it is not affecting this code here. You should not use an immutable object (like a list) as an default when defining an optional/named argument in a method. I.e. in the Physic __init__() I changed pos=[0,0] to pos=(0,0). Not a big deal here, but can cause really odd bugs if you had assigned it to a var, then tried to change it. It will have effects on other instances of the object because they actually share the default initialization object and if it gets modified by one of them it happens in all of them!
i'm making a game about a car trying not to collide with pedestrian car.
I'm trying to add a collision to the user_car(aka Player class) with enemy(aka pedestrian_cars class), but i'm not exactly sure where(while loop?) and how to do it. Some variables maybe be bad but I will fix them later.
My program:
import pygame, random, math, sys
from pygame.locals import *
class Player(pygame.sprite.Sprite):
def __init__(self, starty):
pygame.sprite.Sprite.__init__(self)
# Images
self.aliveImage = pygame.image.load("playercar.png").convert_alpha()
#self.deadImage = pygame.image.load("data/PlayerExplode.png").convert_alpha()
self.image = self.aliveImage
self.rect = self.image.get_rect()
self.rect.x = 200
self.rect.y = starty - self.rect.height
self.speed = 7
self.dead = False
# Explode if you get hit, lose a life
def explode(self):
if not self.dead:
self.dead = True
self.image = self.deadImage
pygame.mixer.stop()
self.channel = self.explodeSound.play()
game.playerShots.empty()
game.enemyShots.empty()
game.wave.mship.empty()
game.lives.update(-1)
class pedestrian_cars(pygame.sprite.Sprite):
def __init__(self, starty,startx):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("pedcar.png").convert_alpha()
self.rect = self.image.get_rect()
self.rect.y = starty - self.rect.height
self.rect.x = startx - self.rect.width
self.delta_y = 5 # 5
self.gravity = .5 #.5
self.has_spawned = False
def update(self):
self.rect.y += self.delta_y
def spawn(self):
if self.rect.y == 480 or self.has_spawned == False:
self.has_spawned = True
self.rect.x = random.randint(60,300)
self.rect.y = -10
def main():
""" Set up the game and run the main game loop """
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.init() # prepare the pygame module for use
surfaceSz = 480 # Desired physical surface size, in pixels.
# Create surface of (width, height), and its window.
main_surface = pygame.display.set_mode((surfaceSz, surfaceSz))
#SPRITES###############################################################
user_car = Player(450)
enemy = pedestrian_cars(10,200)
#SPRITES################################################################
background_image = pygame.image.load("background2.png")
all_sprites = pygame.sprite.Group()
user_car.add(all_sprites)
enemy.add(all_sprites)
clock = pygame.time.Clock()
b1 = "background2.png"
back = pygame.image.load(b1).convert()
back2 = pygame.image.load(b1).convert()
y = 0
screenWidth = 600
screenHeight = 480
#Sound/Music#####################################
pygame.mixer.music.load("stilldre.wav")
pygame.mixer.music.play(-1)
#-################################################
while True:
ev = pygame.event.poll() # look for any event
if ev.type == pygame.QUIT: # window close button clicked?
break # ... leave game loop
sys.exit()
if not user_car.dead:
# Move the player
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
user_car.rect.x = max(user_car.rect.x - user_car.speed, 116-user_car.rect.width)
elif keys[pygame.K_RIGHT]:
user_car.rect.x = min(user_car.rect.x + user_car.speed, 395-user_car.rect.width)
else:
# Go back to playing after the explosion sound finishes
if not self.channel.get_busy():
self.image = self.aliveImage
self.dead = False
self.rect.x = 200
# Update your game objects and data structures here...
all_sprites.update()
enemy.spawn()
main_surface.fill((0,200,255))
main_surface.blit(background_image, (0, 0))
main_surface.blit(back, (0,y))
main_surface.blit(back2,(0,y-screenHeight))
y = y + 8
if y == screenWidth:
y = 0
## if enemy.alive.x ==
## msElapsed = clock.tick(100)
## pygame.display.flip()
all_sprites.draw(main_surface)
# Now the surface is ready, tell pygame to display it!
pygame.display.flip()
clock.tick(200)
msElapsed = clock.tick(100)
pygame.quit() # once we leave the loop, close the window.
main()
You can simply check if the rects of your objects overlap with colliderect:
while True:
...
if user_car.rect.colliderect(enemy.rect):
do_something()
...
I am building a football game (american) that has a Player class move an image by the keyboard in one program:
import pygame
import os
import random
black = (0,0,0)
white = (255,255,255)
red = (255, 0, 0)
green = (0, 100, 0)
# This class represents the bar at the bottom that the player controls
class Player(object):
def __init__(self):
self.image = pygame.image.load("player_one.png").convert()
self.image.set_colorkey(white)
self.width = 15
self.height = 15
self.x = 940
self.y = 240
def handle_keys(self):
key = pygame.key.get_pressed()
if key[pygame.K_DOWN]:
if self.y < 470:
self.y += self.height
elif key[pygame.K_UP]:
if self.y > 0:
self.y -= self.height
if key[pygame.K_RIGHT]:
if self.x < 940:
self.x += self.width
elif key[pygame.K_LEFT]:
if self.x > 0:
self.x -= self.width
def draw(self, surface):
surface.blit(self.image, (self.x, self.y))
pygame.init()
screen = pygame.display.set_mode((1000, 500))
player = Player()
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
player.handle_keys()
screen.fill(green)
for x in range(60,940,35):
pygame.draw.line(screen, white, [x, 0], [x, 500], 1)
player.draw(screen)
pygame.display.update()
clock.tick(20)
And another program that displays the enemy randomly on a background image when any key is pressed they change position:
import random
import pygame
WHITE = (255,255,255)
BLACK = (0 ,0 ,0 )
#----------------------------------------------------------------------
class Enemy():
def __init__(self, image, x=0, y=0):
self.image = pygame.image.load(image).convert()
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
#------------
def draw(self, screen):
screen.blit(self.image, self.rect)
#------------
def update(self):
# here change randomly positon
self.rect.topleft = random.randint(60,220+1), random.randint( 0, 475+1)
#----------------------------------------------------------------------
class Game():
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((1400,500))
self.background = pygame.image.load("GameField1.png").convert()
self.multi_enemies = []
self.players = []
# create 3 enemies 0...2
for i in range(0,3):
enemy = Enemy("enemy_"+str(i)+".png")
enemy.update() # set random position on start
self.multi_enemies.append(enemy)
#------------
def run(self):
clock = pygame.time.Clock()
RUNNING = True
while RUNNING:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
RUNNING = False
# changes position when key is pressed
for enemy in self.multi_enemies:
enemy.update()
for player in self.players:
player.handle_keys()
# --- updates ----
# place for updates
# --- draws ---
self.screen.fill(BLACK)
self.screen.blit(self.background, self.background.get_rect())
for enemy in self.multi_enemies:
enemy.draw(self.screen)
pygame.display.update()
pygame.display.flip()
# --- FPS ---
clock.tick(20)
# --- quit ---
pygame.quit()
#----------------------------------------------------------------------
Game().run()
First - Thank you for the people who helped me get this far. Second - I need to combine the Player class to the second program. I need to add collision detection so that if the player makes it to the left end zone his Score increases +7 and he goes back to the start. Also, if the player runs into an Enemy then he goes back to the start. I want the game to be on a 2 min timer so the goal is to score as much within the timeframe before the game ends.
I know a lot of people are going to recommend Sprites and I expect that but could you please provide code/explanation. Attached are my images.
I split code into 3 files Player.py, Enemy.py and Game.py
Player.py
I add restart() to set start position at new game and game restart
In handle_event I use event (to check keys) so I could check mouse events and other events if I have to - it is more universal.
handle_event return True/False if player was moved or not.
.
import pygame
#----------------------------------------------------------------------
class Player(object):
def __init__(self, surface_rect):
self.surface_rect = surface_rect
self.image = pygame.image.load("player_one.png").convert()
self.image.set_colorkey( (255,255,255) )
self.rect = self.image.get_rect() # you get image width, height
self.move_x = 15
self.move_y = 15
self.restart()
#------------
def restart(self):
self.rect.x = 940
self.rect.y = 240
#------------
def handle_events(self, event):
player_moves = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
if self.rect.bottom < self.surface_rect.bottom: #470
self.rect.y += self.move_y
player_moves = True
elif event.key == pygame.K_UP:
if self.rect.top > self.surface_rect.top:
self.rect.y -= self.move_y
player_moves = True
elif event.key == pygame.K_RIGHT:
if self.rect.right < self.surface_rect.right:
self.rect.x += self.move_x
player_moves = True
elif event.key == pygame.K_LEFT:
if self.rect.left > self.surface_rect.left:
self.rect.x -= self.move_x
player_moves = True
print "(debug): player: x, y:", self.rect.x, self.rect.y
return player_moves
#------------
def draw(self, surface):
surface.blit(self.image, self.rect)
#----------------------------------------------------------------------
Enemy.py
nothing is changed
import pygame
import random
#----------------------------------------------------------------------
class Enemy():
def __init__(self, image, x=0, y=0):
self.image = pygame.image.load(image).convert()
self.image.set_colorkey( (255,255,255) )
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
#------------
def draw(self, screen):
screen.blit(self.image, self.rect)
#------------
def update(self):
# here change randomly positon
self.rect.topleft = random.randint(60, 220+1), random.randint(0, 475+1)
#----------------------------------------------------------------------
Game.py
best part :) try to figure out what is going on in code ;)
collision detect - it could be use pygame.sprite.Sprite, pygame.sprite.Group, etc.
score for player and enemies
time counting
game over - backspace restart game after game over
.
import random
import pygame
from Player import *
from Enemy import *
WHITE = (255,255,255)
BLACK = (0 ,0 ,0 )
RED = (255,0 ,0 )
#----------------------------------------------------------------------
class Game():
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((1400,500))
self.background = pygame.image.load("GameField1.png").convert()
self.enemies = []
#self.players = []
self.player = Player(self.screen.get_rect())
# create 3 enemies 0...2
for i in range(3):
enemy = Enemy("enemy_"+str(i)+".png")
enemy.update() # set random position on start
self.enemies.append(enemy)
self.font = pygame.font.SysFont("", 32)
self.gameover_text = self.font.render("GAME OVER", -1, RED)
self.gameover_rect = self.gameover_text.get_rect(center=self.screen.get_rect().center)
self.restart()
#------------
def restart(self):
self.player_score = 0
self.enemies_score = 0
#self.play_time = 2*60 # 2minutes * 60 seconds
self.play_time = 30 # 30 seconds for fast test
self.change_time = pygame.time.get_ticks() + 1000 # 1s
self.player.restart()
#------------
def update_time(self):
print "(debug): time:", self.change_time, pygame.time.get_ticks()
if pygame.time.get_ticks() >= self.change_time:
self.change_time += 1000 # 1s
self.play_time -= 1
return self.play_time <= 0 # GAME OVER ?
#------------
def draw_score(self, surface):
surface_rect = surface.get_rect()
self.player_score_text = self.font.render(str(self.player_score) + " :Player", -1, WHITE)
self.player_score_rect = self.player_score_text.get_rect(right=surface_rect.right-10, top=10)
surface.blit(self.player_score_text, self.player_score_rect)
self.enemies_score_text = self.font.render("Enemy: " + str(self.enemies_score), -1, WHITE)
self.enemies_score_rect = self.enemies_score_text.get_rect(left=surface_rect.left+10, top=10)
surface.blit(self.enemies_score_text, self.enemies_score_rect)
print "(debug): render scores:", self.player_score, self.player_score_rect, self.enemies_score, self.enemies_score_rect
#------------
def draw_time(self, surface):
surface_rect = surface.get_rect()
time_str = "%02d:%02d" % (self.play_time/60, self.play_time%60)
self.time_text = self.font.render(time_str, -1, RED )
self.time_rect = self.time_text.get_rect(centerx=surface_rect.centerx, top=10)
surface.blit(self.time_text, self.time_rect)
print "(debug): render time:", self.play_time, self.time_rect, (self.play_time/60, self.play_time%60), time_str
#------------
def run(self):
clock = pygame.time.Clock()
RUNNING = True
GAME_OVER = False
while RUNNING:
# --- events ---
PLAYER_MOVES = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
RUNNING = False
if event.key == pygame.K_BACKSPACE:
if GAME_OVER:
GAME_OVER = False
self.restart()
# player moves
if not GAME_OVER:
PLAYER_MOVES = self.player.handle_events(event)
# --- updates ----
if PLAYER_MOVES and not GAME_OVER:
# changes position when key is pressed
for enemy in self.enemies:
enemy.update()
# check collisions
collision = False
for enemy in self.enemies:
if pygame.sprite.collide_rect(self.player, enemy):
collision = True
break # first collision and I don't check rest enemies
if collision:
self.enemies_score += 7
print "(debug): game: collision:", self.player_score, self.enemies_score
self.player.restart()
# check touchdown
if self.player.rect.left <= 100:
self.player_score += 7
print "(debug): game: touchdown:", self.player_score, self.enemies_score
self.player.restart()
if not GAME_OVER:
GAME_OVER = self.update_time()
# --- draws ---
self.screen.fill(BLACK)
self.screen.blit(self.background, self.background.get_rect())
self.player.draw(self.screen)
for enemy in self.enemies:
enemy.draw(self.screen)
self.draw_time(self.screen)
self.draw_score(self.screen)
if GAME_OVER:
self.screen.blit(self.gameover_text, self.gameover_rect)
pygame.display.update()
# --- FPS ---
clock.tick(20)
#----------------------------------------------------------------------
Game().run()
I'm a little confused as to what you are asking, I hope this will answer all your questions:
First of all wouldn't the enemies "teleport" to random locations each time they update? I'm not sure what you are trying to achieve but it should be better if you randomize their location on init (where you set their x and y to 0 ) and on the update you should create some Artificial Intelligence (like following the hero? )
class Enemy():
def __init__(self, image):
self.image = pygame.image.load(image).convert()
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
self.rect.centerx = random.randint(60,220+1)
self.rect.centery = random.randint( 0, 475+1)
#------------
def draw(self, screen):
screen.blit(self.image, self.rect)
#------------
def update(self, heroX, heroY):
#Make enemies follow hero (for example)
if heroX > self.rect.centerx
self.rect.centerx += 10; #10 is example value, set the one you like!
else if heroX < self.rect.centerx
self.rect.centerx -= 10;
#Do the same for y
#------------
def reset(self): #This is called when hero scores, or enemies touch hero (and you want to reset hero to starting point and enemies)
self.rect.centerx = random.randint(60,220+1)
self.rect.centery = random.randint( 0, 475+1)
Just make sure to pass player's x and y when you update the enemy.
About collision, there is a simple algorithm that goes like that: If you have objectA and objectB they only collide if objectA.right > objectB.left && objectA.left < objectB.right , combine top and bottoms the same way and you are done
if (player.right > enemy.left && player.left < enemy.right && player.bottom > enemy.top && player.top < enemy.bottom)
player.reset()
enemy.reset()
apply this algorithm once for each enemy (and hero, if there are more than one)
About the timer, you already have a timer to limit frames, you can use that to count seconds inside the game and create limits (use your imagination!)
I would recommend sprites! I'm not going to tell you everything because figuring game programming out is half the fun!
First of all, you could set pygame groups up, like
player_list = pygame.sprite.Group()
player_list.add(player)
for player and enemy, and test a collision between them both using pygame.sprite.spritecollide and maybe something similar for your left zone of the pitch..
Then as furas mentioned, just copy or import player class. :)
Also, I would suggest pygame.time.get_ticks() for your timer, although you can do it other ways..
The rest is down to you! I hope this helped in some way, ask any questions if you don't understand!
I have done this on a phone so if someone wants to edit it for all the codey bits that'd be great :)