I am new to pygame and I am making a side scrolling game that uses a bird as the character and it flies but I am trying to get it to move up and down on the screen but I can't figure out how.
import pygame
from pygame.locals import *
import os
import sys
import time
pygame.init()
class Fly:
def __init__(self):
self.last_update = time.clock()
self.screen = pygame.display.set_mode((700, 400), 0, 32)
#Load bird
self.bird_state = 1
self.bird_frames = []
for r in xrange(1, 5):
self.bird_frames.append(pygame.image.load('bird%s.png' % r))
self.bg = pygame.image.load('bg.png').convert()
self.Loop()
def eventLoop(self):
'Take and process input from perephirals'
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
def Update(self):
self.bird_state += 1
if self.bird_state > 4:
self.bird_state = 1
def Draw(self):
self.screen.blit(self.bg, [0, 0])
self.screen.blit(self.bird_frames[self.bird_state - 1], (150, 150))
def Loop(self):
while 1:
self.eventLoop()
if time.clock() - self.last_update > 0.15:
self.Update()
self.last_update = time.clock()
self.Draw()
pygame.display.update()
Fly()
import pygame
from pygame.locals import *
import os
import sys
import time
pygame.init()
class Fly:
def __init__(self):
self.last_update = time.clock()
self.screen = pygame.display.set_mode((700, 400), 0, 32)
#Load bird
self.bird_state = 1
self.bird_frames = []
for r in xrange(1, 5):
self.bird_frames.append(pygame.image.load('bird%s.png' % r))
self.bg = pygame.image.load('bg.png').convert()
self.Loop()
def eventLoop(self):
'Take and process input from perephirals'
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
def Update(self):
self.bird_state += 1
if self.bird_state > 4:
self.bird_state = 1
def Draw(self):
self.screen.blit(self.bg, [0, 0])
self.screen.blit(self.bird_frames[self.bird_state - 1], (150, 150))
def Loop(self):
while 1:
self.eventLoop()
k = pygame.key.get_pressed()
if k[K_DOWN]:
# Do something with your bird
if k[K_UP]:
# Do something with your bird
if time.clock() - self.last_update > 0.15:
self.Update()
self.last_update = time.clock()
self.Draw()
pygame.display.update()
Fly()
The pygame.key.get_pressed will check if you pressed a button. Check the reference for what kind of options you have there. http://www.pygame.org/docs/ref/key.html
Place this in your loop because then its "realtime".
k = pygame.key.get_pressed()
if k[K_DOWN]:
# Do somthing with your bird
if k[K_UP]:
# Do somthing with your bird
If you think of your Player as a rectangle (this could apply to all of your sprites in your game) then all you have to do is set up two parameters for your rectangle called self.speedx and self.speedy. Since you you're looking for only up and down movement, speedx would not change, but you would adjust speedy depending on what button is pressed. Here's a snippet of code from one of my games. It is part of the update def for my player class. Unfortunately, in this game I just wanted lateral (left and right) movement, but you'll get the idea. If you need anymore help, let me know. Here's the code:
def update(self):
# Ensures default motion is 0
self.speedx = 0
self.speedy = 0
# This checks to see what key's are pressed
keystate = pygame.key.get_pressed()
# This gives control for movement (Can use WASD or arrow keys)
if keystate[pygame.K_a] or keystate[pygame.K_LEFT]:
self.speedx = -5
if keystate[pygame.K_d] or keystate[pygame.K_RIGHT]:
self.speedx = 5
if keystate[pygame.K_SPACE]:
self.shoot(bullet_img)
# Gives movement based on keys that are pressed
self.rect.x += self.speedx
self.rect.y += self.speedy
Related
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()
I had a problem with creating camera in pygame, I assumed code below should work but our player is moving faster than camera and is going out of the window. Somebody know what's the issue?
import pygame, sys
class Player(pygame.sprite.Sprite):
def __init__(self, pos, group):
super().__init__(group)
self.image = pygame.image.load('./chatacters/players/player_one.png').convert_alpha()
self.rect = self.image.get_rect(center=(640, 360))
self.direction = pygame.math.Vector2()
self.speed = 5
# key inputs
def input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
self.direction.y = -1
elif keys[pygame.K_DOWN]:
self.direction.y = 1
else:
self.direction.y = 0
if keys[pygame.K_LEFT]:
self.direction.x = -1
elif keys[pygame.K_RIGHT]:
self.direction.x = 1
else:
self.direction.x = 0
# Moving using inputs
def move(self, speed):
if self.direction.magnitude() != 0:
self.direction = self.direction.normalize()
self.rect.center += self.direction * speed
# updating drawing
def update(self):
self.input()
self.move(self.speed)
class Camera(pygame.sprite.Group):
def __init__(self):
super().__init__()
self.display_surface = pygame.display.get_surface()
self.offset = pygame.math.Vector2()
self.half_w = self.display_surface.get_size()[0] // 2
self.half_h = self.display_surface.get_size()[1] // 2
self.map = pygame.image.load('./map/level_data/level.png').convert_alpha()
self.rect = self.map.get_rect(topleft=(0, 0))
def custom_draw(self, player):
self.offset.x = player.rect.centerx - self.half_w
self.offset.y = player.rect.centery - self.half_h
ground_offset = self.rect.topleft - self.offset
self.display_surface.blit(self.map, ground_offset)
class Game():
def __init__(self):
# Settings
self.WIDTH = 1280
self.HEIGHT = 720
self.FPS = 60
pygame.init()
pygame.display.set_caption('BetterFortinite')
self.screen = pygame.display.set_mode((self.WIDTH, self.HEIGHT))
self.clock = pygame.time.Clock()
self.camera_group = Camera()
self.player = Player((100, 200), self.camera_group)
def game(self):
while True:
self.clock.tick(self.FPS)
self.screen.fill('black')
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# self.screen.fill("WHITE")
self.camera_group.custom_draw(self.player)
self.player.move(5)
self.player.update()
self.camera_group.draw(self.screen)
# self.camera_group.update()
pygame.display.update()
if __name__ in '__main__':
game = Game()
game.game()
I'm taking the center position of player rect minus half of the width size. Same with height and setting with it my offset. Then I'm setting my ground_offset as cords of topleft screen rect minus offset. What is wrong with this formula?
The problem is not with your formula, but with the code itsself. In the main game loop, you have:
self.player.move(5)
self.player.update()
While Player.update contains:
def update(self):
self.input()
self.move(self.speed)
As you can see, player.move is called twice. This means that the player is moved twice as much as intended and thus twice as fast as the camera, causing both to move at a different speed.
The solution to this problem would be to remove one of the calls of Player.move. I would remove the one in the main game loop as it uses a hardcoded value rather than the Player.speed constant, but it doesn't really matter which one you remove.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import pygame
import sys
import datetime
import time
class TextPicture(pygame.sprite.Sprite):
def __init__(self, speed, location):
pygame.sprite.Sprite.__init__(self)
now = datetime.datetime.now()
text = now.strftime("%H:%M:%S")
font = pygame.font.Font(None, 40)
time_text = font.render(text, 1, [0, 0, 0]) # show now time
self.image = time_text
self.speed = speed
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
def move(self):
self.rect = self.rect.move(self.speed)
if self.rect.left < 0 or self.rect.left > screen.get_width() - self.image.get_width():
self.speed[0] = -self.speed[0]
if self.rect.top < 0 or self.rect.top > screen.get_height() - self.image.get_height():
self.speed[1] = -self.speed[1]
pygame.init()
screen = pygame.display.set_mode([640, 480])
my_time_picture = TextPicture([1, 1], [50, 50])
while 1:
screen.fill([255, 255, 255])
my_time_picture.move()
screen.blit(my_time_picture.image, my_time_picture.rect)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
I am designing a clock which can move in the screen. But what my code can do now is to show a invariant time. I want to clicking and count the time.
My invariable clock picture
And I want to make my clock more beautiful, but don't know how. I will be super grateful if anyone can make any suggestions.
You could do it by using pygame.time.set_timer() to make "tick events" be generated which cause the clock's image to be updated when encountered in the event processing loop.
To make implementing this easier, an update() method could be added to the DigitalClock class (which is what I renamed your generic TextPicture class) which only updates the image, but leaving the current location alone:
import datetime
import sys
import time
import pygame
class DigitalClock(pygame.sprite.Sprite):
def __init__(self, speed, location):
pygame.sprite.Sprite.__init__(self)
self.speed = speed
self.font = pygame.font.Font(None, 40)
self.rect = pygame.Rect(location, (0, 0)) # placeholder
self.update()
def update(self):
location = self.rect.left, self.rect.top # save position
time_text = datetime.datetime.now().strftime("%H:%M:%S")
self.image = self.font.render(time_text, 1, [0, 0, 0])
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location # restore position
def move(self):
self.rect = self.rect.move(self.speed)
if (self.rect.left < 0
or self.rect.left > screen.get_width()-self.image.get_width()):
self.speed[0] = -self.speed[0]
if (self.rect.top < 0
or self.rect.top > screen.get_height()-self.image.get_height()):
self.speed[1] = -self.speed[1]
Following that, you'd need to modify the processing to be something along these lines:
pygame.init()
framerate_clock = pygame.time.Clock()
screen = pygame.display.set_mode([640, 480])
my_digital_clock = DigitalClock([1, 1], [50, 50])
TICK_EVENT = pygame.USEREVENT + 1
pygame.time.set_timer(TICK_EVENT, 1000) # periodically create TICK_EVENT
while True:
for event in pygame.event.get():
if event.type == TICK_EVENT:
my_digital_clock.update() # call new method
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill([255, 255, 255])
my_digital_clock.move()
screen.blit(my_digital_clock.image, my_digital_clock.rect)
framerate_clock.tick(60) # limit framerate
pygame.display.flip()
You could make it more beautiful by using a different font and color. Generally anything that made it look more realistic would be an improvement. It might be cool to make the colons between the digit characters blink on and off (using a similar technique).
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 :)