I am trying to write a Space Invaders game in pygame, but I cannot get the player to move right. Moving left works fine however.
My code for the Sprite and Player classes are:
class Sprite(pygame.sprite.Sprite):
def __init__(self, x, y, image = None):
pygame.sprite.Sprite.__init__(self)
if image is None:
self.image = pygame.Surface((25, 25))
self.image.fill((0, 255, 0))
else:
self.image = image
self.rect = self.image.get_rect()
self.rect.x, self.rect.y = x, y
self.speed = 0.5
def moveLeft(self):
self.rect.x -= self.speed
def moveRight(self):
self.rect.x += self.speed
def draw(self):
screen.blit(self.image, (self.rect.x, self.rect.y))
class Player(Sprite):
def __init__(self, startpos):
try:
image = pygame.image.load(PLAYER_SPRITE_LOCATION)
except: image = None
Sprite.__init__(self, startpos[0], startpos[1], image)
print("Player class initialized at %a with sprite %s" % (self.rect, self.image))
self.score = 0
And the rest of the code is:
RESOLUTION = (224, 256)
PLAYERPOS = [112, 220]
pygame.init()
screen = pygame.display.set_mode(RESOLUTION)
player = Player(PLAYERPOS)
end = False
fps = 60
clock = pygame.time.Clock()
printString = ""
PRINTFPS, time = pygame.USEREVENT+1, 1000
pygame.time.set_timer(PRINTFPS, time)
curr_fps = 0
invaders = pygame.sprite.Group()
bullets = pygame.sprite.Group()
fullscreen = False
while not end:
for event in pygame.event.get():
if event.type == pygame.QUIT:
end = True
if event.type == PRINTFPS:
curr_fps = clock.get_fps()
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT] or pressed[pygame.K_a]:
player.moveLeft()
if pressed[pygame.K_RIGHT] or pressed[pygame.K_d]:
player.moveRight()
if pressed[pygame.K_SPACE] or pressed[pygame.K_s] or pressed[pygame.K_UP]:
player.score += 1
if pressed[pygame.K_F11]:
if not fullscreen:
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
fullscreen = True
else:
screen = pygame.display.set_mode(RESOLUTION)
fullscreen = False
# Print game data
prevPrintString = printString
printString = "\rPlayer: (%s, %s)" % (str("%.3f" % player.rect.x).zfill(7),
str("%.3f" % player.rect.y).zfill(7))
printString += "; Score: %i" % player.score
printString += "; FPS: %s" % (str("%.2f" % curr_fps).zfill(5))
if printString != prevPrintString:
print(printString, end = "")
# Background (not really needed)
screen.fill((0, 0, 255)) # Blue screen!
# Update sprites, e.g. invaders moving and bullets flying
invaders.update()
bullets.update()
# Drawing sprites
invaders.draw(screen)
bullets.draw(screen)
player.draw()
# Update screen and maintain constant FPS
clock.tick(fps)
pygame.display.flip()
The problem is not that the input isn't working: I can tell that it does. I think the problem is with the moveRight function itself, and that somehow it maybe doesn't work with addition? But I don't know.
Thank you in advanced!
All of the fields stored in a pygame Rect are integers, but you are adding or substracting a fraction (0.5). My best guess is that when you subtract 0.5 from the x coordinate, it goes from (say) 112 to 111.5 and gets truncated to 111, so you move left one pixel. But if you add 0.5, it goes from 112 to 112.5 and gets truncated back to 112, so you don't move at all. I would suggest using whole numbers only.
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)
I'm making a "duck hunt" game in pygame. I have everything working, my sprites move and respawn when needed, cursor is a crosshair with sound when clicked etc. The issue I'm having is trying to add points when the mouse is click on a duck. Any idea how I would do this? Posted all of the code, its a bit of a mess until I get thank working, check the main loop specifically. Thanks.
import pygame
import random
import duck_code
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
DUCK_BACK = (59, 202, 255)
class Player(pygame.sprite.Sprite):
""" The class is the player-controlled sprite. """
# -- Methods
def __init__(self, x, y, filename):
"""Constructor function"""
# Call the parent's constructor
super().__init__()
# Set height, width
self.image = pygame.Surface([15, 15])
self.image.fill(BLACK)
self.image = pygame.image.load(filename).convert()
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# -- Attributes
# Set speed vector
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
""" Change the speed of the player"""
self.change_x += x
self.change_y += y
def update(self):
""" Find a new position for the player"""
self.rect.x += self.change_x
self.rect.y += self.change_y
# boarders for walls, reset player, play bump sound
if self.rect.x in range(1060, 1085):
self.rect.x -= 25
if self.rect.x in range(-5, 0):
self.rect.x += 25
if self.rect.y in range(-5, 0):
self.rect.y += 25
if self.rect.y in range(480, 505):
self.rect.y -= 25
# Initialize Pygame
# Loading sounds
pygame.init()
game_background = pygame.image.load("game_background.jpg")
duck_hit = pygame.mixer.Sound("duck_hit.wav")
player_click = pygame.mixer.Sound("shot_gun.ogg")
# Set the height and width of the screen
screen_width = 1280
screen_height = 1024
screen = pygame.display.set_mode([screen_width, screen_height])
# Starting score and font settings
font = pygame.font.Font(None, 36)
score = 0
# This is a list of every sprite.
all_sprites_list = pygame.sprite.Group()
duck_list = pygame.sprite.Group()
duck_hit_list = pygame.sprite.Group()
"""DUCKS"""
for i in range(5):
# This represents a block
ducks = duck_code.Duck("duck1.png")
ducks.rect.x = random.randrange(screen_width)
ducks.rect.y = random.randrange(50, 350)
# Add the block to the list of objects
duck_list.add(ducks)
all_sprites_list.add(ducks)
"""PLAYER"""
player_image = pygame.image.load("crosshair.png")
player_image.set_colorkey(WHITE)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
score = 0
# Hide the mouse cursor
pygame.mouse.set_visible(0)
# -------- Main Program Loop -----------
while not done:
mouse = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
blocks_hit_list = pygame.sprite.spritecollide(mouse, duck_list, True)
score += 100
print(score)
player_click.play()
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.blit(game_background, [0, 0])
player_position = pygame.mouse.get_pos()
x = player_position[0]
y = player_position[1]
screen.blit(player_image, [x, y])
pos = pygame.mouse.get_pos()
pressed1, pressed2, pressed3 = pygame.mouse.get_pressed()
# Check if the rect collided with the mouse pos
# and if the left mouse button was pressed.
all_sprites_list.draw(screen)
duck_list.update()
# Showing scoreboard
text = font.render("Score: " + str(score), True, WHITE)
screen.blit(text, [10, 10])
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
pygame.quit()
pygame.sprite.spritecollide only works with a sprite as the first argument and a sprite group as the second argument. To check if the mouse collides with a duck, you can iterate over the duck_list with a for loop and call the collidepoint method of the current duck's rect:
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
for duck in duck_list:
if duck.rect.collidepoint(event.pos): # event.pos is the mouse position.
score += 100
I'm in the process of making a snake game, it mostly went well so far, but it displayed a block of the snake at the top left that I can't get rid of.
I checked that I didn't draw the surface there(0,0). I'm stuck. Please help me out, thanks!!
BTW it's my first time asking a question so any suggestion on that is also appreciated.
Edit: I found that using a regular class instead of sprite solved the problem, but I need the collide and other functions in sprite.
import pygame
class snake(pygame.sprite.Sprite):
speed=5
init_length=10
direction=0
x=[]
y=[]
updateCountMax = 2
updateCount = 0
length=10
# image=pygame.Surface((11,11)).convert().fill((0,128,255))
def __init__(self,init_x,init_y,image,screen):
pygame.sprite.Sprite.__init__(self)
for i in range(0,self.init_length):
self.x.append(init_x)
self.y.append(init_y)
# for i in range(0,self.length):
# print(f"{self.x[i]},{self.y[i]}")
for x in self.x:
print(x)
for y in self.y:
print(y)
self.image=image
self.screen=screen
self.rect=self.image.get_rect()
# self.rect.center=(self.x,self.y)
def move_R(self):
# self.x+=self.speed
self.direction=0
def move_L(self):
# self.x-=self.speed
self.direction=1
def move_U(self):
# self.y-=self.speed
self.direction=2
def move_D(self):
# self.y+=self.speed
self.direction=3
def update(self):
# self.updateCount = self.updateCount + 1
# if self.updateCount < self.updateCountMax:
for i in range(self.length-1,0,-1):
# print("self.x[" + str(i) + "] = self.x[" + str(i-1) + "]")
self.x[i] = self.x[i-1]
self.y[i] = self.y[i-1]
if(self.direction==0):
self.x[0]+=self.speed
elif(self.direction==1):
self.x[0]-=self.speed
elif(self.direction==2):
self.y[0]-=self.speed
elif(self.direction==3):
self.y[0]+=self.speed
# self.rect.center=(self.x,self.y)
# self.updateCount = 0
# for i in range(0,self.length):
# print(f"{self.x[i]},{self.y[i]}")
self.draw()
def draw(self):
for i in range(0,self.length):
self.screen.blit(self.image,(self.x[i],self.y[i]))
# print(f"rendered at {self.x[i]},{self.y[i]}")
# self.rect.center=(self.x[i],self.y[i])
class app:
width=1200
height=900
title="Snake"
done=False
def __init__(self):
pygame.init()
self.image=pygame.Surface((11,11))
self.image.fill((0,128,255))
pygame.display.set_caption(self.title)
self.screen = pygame.display.set_mode((self.width, self.height))
self.screen.fill((0,0,0))
self.clock=pygame.time.Clock()
self.snakes=pygame.sprite.Group()
self.player1=snake(500,10,self.image,self.screen)
self.snakes.add(self.player1)
self.background = pygame.Surface(self.screen.get_size())
self.background = self.background.convert()
self.background.fill((255,255,255))
def loop(self):
while(not self.done):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.done = True
pygame.event.pump()
keys = pygame.key.get_pressed()
if (keys[pygame.K_RIGHT]):
self.player1.move_R()
if (keys[pygame.K_LEFT]):
self.player1.move_L()
if (keys[pygame.K_UP]):
self.player1.move_U()
if (keys[pygame.K_DOWN]):
self.player1.move_D()
if (keys[pygame.K_ESCAPE]):
self.done = True
self.screen.blit(self.background,(0,0))
self.screen.fill((0,0,0))
self.player1.update()
self.snakes.draw(self.screen)
pygame.display.update()
self.clock.tick(60)
pygame.quit()
if __name__ == "__main__" :
theApp = app()
theApp.loop()
You add player1 to the snakes sprite group and draw that with self.snakes.draw(self.screen). However, you also draw the player in self.player1.update(), in the last line.
Remove self.snakes.draw(self.screen) to get rid of the phantom snake.
BTW: you create and set a self.background but you immediately overwrite it with self.screen.fill((0,0,0)), so you don't need a background at all.
What you see in the top left corner is the self.image of the player1 sprite. The draw method of sprite groups blits the images at the rect.topleft coordinates of the sprites and since you never move the player1.rect, the image will be blitted at the default (0, 0) coordinates. So just remove the line self.snakes.draw(self.screen) to fix this.
I also suggest that you use pygame.Rects instead of the self.x and self.y lists. You can create rect instances with the init_x and init_y coords as the topleft attribute and put them into a self.rects list. That allows you to simplify the update and draw methods, and the rects can also be used for the collision detection. I've already refactored your code (it kind of became a mini code review):
import pygame
class Snake(pygame.sprite.Sprite): # Use upper camelcase names for classes (see PEP 8).
def __init__(self, init_x, init_y, image,screen):
pygame.sprite.Sprite.__init__(self)
# These are instance attributes now (use class attributes if
# the values should be shared between the instances).
self.speed = 5
self.init_length = 10
self.direction = 0
self.updateCountMax = 2
self.updateCount = 0
self.length = 10
# The body parts are rects now.
self.rects = []
for i in range(self.init_length):
# Append pygame.Rect instances.
self.rects.append(pygame.Rect(init_x, init_y, 11, 11))
self.image = image
self.screen = screen
self.rect = self.rects[0] # I use the first rect as the self.rect.
def update(self):
for i in range(self.length-1, 0, -1):
# Update the topleft (x, y) positions of the rects.
self.rects[i].topleft = self.rects[i-1].topleft
if self.direction == 0:
self.rects[0].x += self.speed
elif self.direction == 1:
self.rects[0].x -= self.speed
elif self.direction == 2:
self.rects[0].y -= self.speed
elif self.direction == 3:
self.rects[0].y += self.speed
def draw(self):
# Iterate over the rects to blit them (I draw the outlines as well).
for rect in self.rects:
self.screen.blit(self.image, rect)
pygame.draw.rect(self.screen, (0, 255, 0), rect, 1)
class App:
width = 1200
height = 900
title = "Snake"
done = False
def __init__(self):
pygame.init()
self.image = pygame.Surface((11, 11))
self.image.fill((0, 128, 255))
pygame.display.set_caption(self.title)
self.screen = pygame.display.set_mode((self.width, self.height))
self.clock = pygame.time.Clock()
self.snakes = pygame.sprite.Group()
self.player1 = Snake(500, 10, self.image, self.screen)
self.snakes.add(self.player1)
def loop(self):
while not self.done:
# Handle the events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.done = True
keys = pygame.key.get_pressed()
# In Python we simply set the values of the
# attributes directly instead of using getter
# and setter methods.
if keys[pygame.K_RIGHT]:
self.player1.direction = 0
if keys[pygame.K_LEFT]:
self.player1.direction = 1
if keys[pygame.K_UP]:
self.player1.direction = 2
if keys[pygame.K_DOWN]:
self.player1.direction = 3
if keys[pygame.K_ESCAPE]:
self.done = True
# Update the game.
self.player1.update()
# Draw everything.
self.screen.fill((0, 0, 0))
self.player1.draw()
pygame.draw.rect(self.screen, (255, 0, 0), self.player1.rect, 1)
pygame.display.update()
self.clock.tick(60)
pygame.quit()
if __name__ == "__main__" :
the_app = App()
the_app.loop()
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 :)