I am making the game Space Invaders with Pygame and I am trying to make the enemy shoot, firstly by pressing the TAB button. When I get this working I will let the enemy shoot randomly. At this moment I cannot see the BulletEnemy and when I press TAB it does not shoot anything. What am I doing wrong?
Thanks.
import pygame, sys
from pygame.locals import *
import random
screenWidth = 800
screenHeight = 600
FPS = 60
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Space Invaders")
clock = pygame.time.Clock()
shipWidth = 78
#colors
black=(0,0,0)
blue=(0,0, 255)
green=(0,128,0)
red=(255,0,0)
white=(255,255,255)
yellow=(255,255,0)
def app_quit():
pygame.quit()
sys.exit("System exit.")
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("spaceship7.png").convert()
self.image.set_colorkey(white)#make white transparant
self.rect = self.image.get_rect()
self.rect.centerx = screenWidth / 2
self.rect.bottom = screenHeight - 10
self.speedx = 0
def update(self):
self.speedx = 0
if event.type == KEYDOWN and event.key == K_LEFT:
self.speedx = -2
elif event.type == KEYDOWN and event.key == K_RIGHT:
self.speedx = 2
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.right = screenWidth
if self.rect.left < 0:
self.rect.left = 0
def shootPlayer(self):
bulletPlayer = BulletPlayer(self.rect.centerx, self.rect.top)
allSprites.add(bulletPlayer)
bulletsPlayer.add(bulletPlayer)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("enemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = random.randrange(0, 200)
self.speedx = random.randrange(1,2)
def update(self):
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.x = 50
self.rect.y = random.randrange(0, 250)
self.speedx = random.randrange(1,3)
if self.rect.x > screenWidth:
self.kill()
def shootEnemy(self):
bulletEnemy = BulletEnemy(self.rect.centerx, self.rect.bottom)
allSprites.add(bulletEnemy)
bulletsEnemy.add(bulletEnemy)
class BulletPlayer(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class BulletEnemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bulletenemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom > screenHeight:
self.kill()
class Wall(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("wall.png").convert()
self.rect = self.image.get_rect()
self.rect.center = 100, 300
allSprites = pygame.sprite.Group()
player = Player()
enemy = pygame.sprite.Group()
bulletsPlayer = pygame.sprite.Group()
bulletsEnemy = pygame.sprite.Group()
wall = Wall()
allSprites.add(player, enemy, bulletsPlayer, bulletsEnemy, wall)
for i in range(1):
e = Enemy()
allSprites.add(e)
enemy.add(e)
running = True
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
running = False
app_quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_TAB:
enemy.shootEnemy()
allSprites.update()
screen.fill(black)
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
Spaceship
Enemy
Wall
BulletPlayer
BulletEnemy
The problem is here:
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_TAB:
enemy.shootEnemy()
Once event.type == KEYDOWN one time, the second evaluation is ignored.
Try this
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
elif event.key == pygame.K_TAB:
enemy.shootEnemy()
This checks for a KEYDOWN event, then for the specific key that's pressed.
Related
I'm developing a basic game, where you can move around and shoot projectiles to kill randomly spawned enemies, but if I boot the game and I try to move before I do anything else, the game crashes. If I shoot a projectile first, however, the game runs perfectly and I can move around without any problems, but I can't seem to figure out why this is.
import pygame
import random
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
#Classes
class Player(pygame.sprite.Sprite):
def __init__(self, filename, x, y):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.change_x = 0
self.change_y = 0
self.walls = None
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.change_x > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.change_y
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.change_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(BLACK)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Enemy(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
class ProjectileUp(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 5
class ProjectileDown(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.y += 5
class ProjectileLeft(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.x -= 5
class ProjectileRight(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.x += 5
# --- Create the window
#Initialise pygame
pygame.init()
#Window dimensions
screen_width = 1080
screen_height = 607
screen = pygame.display.set_mode([screen_width, screen_height])
#Window display name
pygame.display.set_caption('Labyrinth')
#Sprite Lists
all_sprite_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
projectile_list = pygame.sprite.Group()
#Define game borders
wall = Wall(-32, 0, 10, 607)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(0 , -64, 1080, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(1100, 0, 10, 607)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(0 , 600, 1080, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
#Create player sprite
player = Player("Isaac.png", 420, 150)
all_sprite_list = pygame.sprite.Group()
all_sprite_list.add(player)
player.walls = wall_list
#Create enemies
for i in range(7):
block = Enemy("Judas.png")
block.rect.x = random.randrange(50, 950)
block.rect.y = random.randrange(50, 450)
block_list.add(block)
all_sprite_list.add(block)
#Manage screen updates
clock = pygame.time.Clock()
#Load background image
background_position = [0, 0]
background_image = pygame.image.load("Floor.png").convert()
#Loop until game_exit
done = False
#---------- MAIN PROGRAM LOOP ----------#
while not done:
# --- Event processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#Projectile spawn
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
projectile = ProjectileUp("LightningUp.png")
projectile.rect.x = player.rect.x+65
projectile.rect.y = player.rect.y
elif event.key == pygame.K_DOWN:
projectile = ProjectileDown("LightningDown.png")
projectile.rect.x = player.rect.x+65
projectile.rect.y = player.rect.y+100
elif event.key == pygame.K_LEFT:
projectile = ProjectileLeft("LightningLeft.png")
projectile.rect.x = player.rect.x+35
projectile.rect.y = player.rect.y+100
elif event.key == pygame.K_RIGHT:
projectile = ProjectileRight("LightningRight.png")
projectile.rect.x = player.rect.x+115
projectile.rect.y = player.rect.y+100
all_sprite_list.add(projectile)
projectile_list.add(projectile)
#Movement controls
if event.type == pygame.KEYDOWN:
if event.key == ord('a'):
player.changespeed(-7, 0)
elif event.key == ord('d'):
player.changespeed(7, 0)
elif event.key == ord('w'):
player.changespeed(0, -7)
elif event.key == ord('s'):
player.changespeed(0, 7)
elif event.type == pygame.KEYUP:
if event.key == ord('a'):
player.changespeed(7, 0)
elif event.key == ord('d'):
player.changespeed(-7, 0)
elif event.key == ord('w'):
player.changespeed(0, 7)
elif event.key == ord('s'):
player.changespeed(0, -7)
# --- Game logic
#Update sprites
all_sprite_list.update()
#Projectile mechanics
for projectile in projectile_list:
block_hit_list = pygame.sprite.spritecollide(projectile, block_list, True)
for block in block_hit_list:
projectile_list.remove(projectile)
#Determine if player hits enemy
blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True)
#Call on background image
screen.blit(background_image, background_position)
# --- Draw the window
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
It's because your if/elif/else logic is messed up a bit. You have two paths for the KEYDOWN event. If the first event happens to be a movement command, your code runs through the projectile code first (without finding a valid projectile command) and then tries to reference a projectile object that doesn't exist. Try this instead:
#---------- MAIN PROGRAM LOOP ----------#
while not done:
# --- Event processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
projectile = None # initialize
if event.key == pygame.K_UP:
projectile = ProjectileUp("LightningUp.png")
projectile.rect.x = player.rect.x+65
projectile.rect.y = player.rect.y
elif event.key == pygame.K_DOWN:
projectile = ProjectileDown("LightningDown.png")
projectile.rect.x = player.rect.x+65
projectile.rect.y = player.rect.y+100
elif event.key == pygame.K_LEFT:
projectile = ProjectileLeft("LightningLeft.png")
projectile.rect.x = player.rect.x+35
projectile.rect.y = player.rect.y+100
elif event.key == pygame.K_RIGHT:
projectile = ProjectileRight("LightningRight.png")
projectile.rect.x = player.rect.x+115
projectile.rect.y = player.rect.y+100
elif event.key == ord('a'):
player.changespeed(-7, 0)
elif event.key == ord('d'):
player.changespeed(7, 0)
elif event.key == ord('w'):
player.changespeed(0, -7)
elif event.key == ord('s'):
player.changespeed(0, 7)
if projectile: # did we create a valid projectile?
all_sprite_list.add(projectile)
projectile_list.add(projectile)
elif event.type == pygame.KEYUP:
if event.key == ord('a'):
player.changespeed(7, 0)
elif event.key == ord('d'):
player.changespeed(-7, 0)
elif event.key == ord('w'):
player.changespeed(0, 7)
elif event.key == ord('s'):
player.changespeed(0, -7)
I want to make the enemies shoot, firstly with the tab butten, after I get this working I want to make them shoot randomly. When I press the tab button it says AttributeError: 'Group' object has no attribute 'shootEnemy'.
What is going wrong?
At this moment there is no collision detection. I will add this later.
import pygame, sys
from pygame.locals import *
import random
screenWidth = 800
screenHeight = 600
FPS = 60
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Space Invaders")
clock = pygame.time.Clock()
shipWidth = 78
#colors
black=(0,0,0)
blue=(0,0, 255)
green=(0,128,0)
red=(255,0,0)
white=(255,255,255)
yellow=(255,255,0)
def app_quit():
pygame.quit()
sys.exit("System exit.")
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("spaceship7.png").convert()
self.image.set_colorkey(white)#make white transparant
self.rect = self.image.get_rect()
self.rect.centerx = screenWidth / 2
self.rect.bottom = screenHeight - 10
self.speedx = 0
def update(self):
self.speedx = 0
if event.type == KEYDOWN and event.key == K_LEFT:
self.speedx = -2
elif event.type == KEYDOWN and event.key == K_RIGHT:
self.speedx = 2
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.right = screenWidth
if self.rect.left < 0:
self.rect.left = 0
def shootPlayer(self):
bulletPlayer = BulletPlayer(self.rect.centerx, self.rect.top)
allSprites.add(bulletPlayer)
bulletsPlayer.add(bulletPlayer)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("enemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = random.randrange(0, 200)
self.speedx = random.randrange(1,2)
def update(self):
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.x = 50
self.rect.y = random.randrange(0, 250)
self.speedx = random.randrange(1,3)
if self.rect.x > screenWidth:
self.kill()
def shootEnemy(self):
bulletEnemy = BulletEnemy(self.rect.centerx, self.rect.bottom)
allSprites.add(bulletEnemy)
bulletsEnemy.add(bulletEnemy)
class BulletPlayer(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class BulletEnemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bulletenemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom > screenHeight:
self.kill()
class Wall(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("wall.png").convert()
self.rect = self.image.get_rect()
self.rect.center = 100, 300
allSprites = pygame.sprite.Group()
player = Player()
enemy = pygame.sprite.Group()
bulletsPlayer = pygame.sprite.Group()
bulletsEnemy = pygame.sprite.Group()
wall = Wall()
allSprites.add(player, enemy, bulletsPlayer, bulletsEnemy, wall)
for i in range(1):
e = Enemy()
allSprites.add(e)
enemy.add(e)
running = True
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
running = False
app_quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
if event.key == pygame.K_TAB:
enemy.shootEnemy()
allSprites.update()
screen.fill(black)
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
Change the line:
enemy.shoot()
to
random.choice(enemy.sprites()).shoot()
This will call the shoot() method of a random sprite from your SpriteGroup enemy.
new to pygame and game programming in general, just wondered how I could get a camera to follow a car (nothing fancy) in a top down car game - think Micro Machines! I'm using Python 3.6, and have got a bike rotating, and moving around. I've kept the code here shorter but I do have a static image for reference if the camera worked!
Here's what I have:
import pygame, math, sys, random
from pygame.locals import *
display_width = 1280
display_height = 800
# Sets size of screen
screen = pygame.display.set_mode((display_width, display_height))
# Initialises clock
clock = pygame.time.Clock()
# Colours
white = (255,255,255)
black = (0,0,0)
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
# Creates a vehicle class
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
# Creates object instance off
pygame.sprite.Sprite.__init__(self)
self.src_image = pygame.image.load(image)
self.position = position
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += (self.k_up +self.k_down)
if self.speed > self.MAX_FORWARD_SPEED:
self.speed = self.MAX_FORWARD_SPEED
if self.speed < -self.MAX_REVERSE_SPEED:
self.speed = -self.MAX_REVERSE_SPEED
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
x, y = self.position
rad = self.direction * math.pi / 180
x += -self.speed*math.sin(rad)
y += -self.speed*math.cos(rad)
self.position = (x, y)
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect()
self.rect.center = self.position
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
rect = screen.get_rect()
# Background
BackGround = Background('/home/pi/gametuts/images/backgrounds/bkg_img.png', [0, 0])
# Bike image load
bike = VehicleSprite('/home/pi/gametuts/images/BikePixelBig.png', rect.center)
bike_group = pygame.sprite.RenderPlain(bike)
# Ball image load
ball = VehicleSprite('/home/pi/gametuts/images/ironball.png', rect.center)
ball_group = pygame.sprite.RenderPlain(ball)
# Main game loop
def game_loop():
while 1:
#USER INPUT
# Sets frame rate
time = clock.tick(60)
for event in pygame.event.get():
if not hasattr(event, 'key'): continue
down = event.type == KEYDOWN
# Bike Input (Player 1)
if event.key == K_d: bike.k_right = down * -5
elif event.key == K_a: bike.k_left = down * 5
elif event.key == K_w: bike.k_up = down * 2
elif event.key == K_s: bike.k_down = down * -2
# Quit
elif event.key == K_ESCAPE: sys.exit(0)
#RENDERING
# Game background
screen.fill(white)
screen.blit(BackGround.image, BackGround.rect)
# Bike render
bike_group.update(time)
bike_group.draw(screen)
ball_group.update(time)
ball_group.draw(screen)
pygame.display.flip()
game_loop()
pygame.quit()
quit()
Thanks in advance!
The simplest way to implement a camera is to use a pygame.math.Vector2 as the camera, subtract the player velocity from it each frame and add it to the position of all game elements during the blitting.
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos, walls, *groups):
super().__init__(*groups)
self.image = pg.Surface((30, 50))
self.image.fill(pg.Color('dodgerblue'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
self.walls = walls
self.camera = Vector2(0, 0)
def update(self):
self.camera -= self.vel # Change the camera pos if we're moving.
# Horizontal movement.
self.pos.x += self.vel.x
self.rect.centerx = self.pos.x
# Change the rect and self.pos coords if we touched a wall.
for wall in pg.sprite.spritecollide(self, self.walls, False):
if self.vel.x > 0:
self.rect.right = wall.rect.left
elif self.vel.x < 0:
self.rect.left = wall.rect.right
self.pos.x = self.rect.centerx
self.camera.x += self.vel.x # Also move the camera back.
# Vertical movement.
self.pos.y += self.vel.y
self.rect.centery = self.pos.y
for wall in pg.sprite.spritecollide(self, self.walls, False):
if self.vel.y > 0:
self.rect.bottom = wall.rect.top
elif self.vel.y < 0:
self.rect.top = wall.rect.bottom
self.pos.y = self.rect.centery
self.camera.y += self.vel.y
class Wall(pg.sprite.Sprite):
def __init__(self, x, y, w, h, *groups):
super().__init__(*groups)
self.image = pg.Surface((w, h))
self.image.fill(pg.Color('sienna2'))
self.rect = self.image.get_rect(topleft=(x, y))
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
walls = pg.sprite.Group()
for rect in ((100, 170, 90, 20), (200, 100, 20, 140),
(400, 60, 150, 100), (300, 470, 150, 100)):
walls.add(Wall(*rect))
all_sprites.add(walls)
player = Player((320, 240), walls, all_sprites)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player.vel.x = 5
elif event.key == pg.K_a:
player.vel.x = -5
elif event.key == pg.K_w:
player.vel.y = -5
elif event.key == pg.K_s:
player.vel.y = 5
elif event.type == pg.KEYUP:
if event.key == pg.K_d and player.vel.x > 0:
player.vel.x = 0
elif event.key == pg.K_a and player.vel.x < 0:
player.vel.x = 0
elif event.key == pg.K_w and player.vel.y < 0:
player.vel.y = 0
elif event.key == pg.K_s and player.vel.y > 0:
player.vel.y = 0
all_sprites.update()
screen.fill((30, 30, 30))
for sprite in all_sprites:
# Add the player's camera offset to the coords of all sprites.
screen.blit(sprite.image, sprite.rect.topleft+player.camera)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
Edit: Here's your code example with a camera. I've also tried to improve a few more things, for example the max(min(...)) trick to clamp the speed value. I'm not sure if the movement works as you want, but you can of course adjust it yourself. (I'd probably make even more modifications to the update method.)
import math
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((1280, 800))
rect = screen.get_rect()
clock = pygame.time.Clock()
WHITE = pygame.Color('white')
# Load images globally and reuse them in your program.
# Also use the `.convert()` or `.convert_alpha()` methods after
# loading the images to improve the performance.
VEHICLE1 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE1.fill((130, 180, 20))
VEHICLE2 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE2.fill((200, 120, 20))
BACKGROUND = pygame.Surface((1280, 800))
BACKGROUND.fill((30, 30, 30))
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
self.src_image = image
self.image = image
self.rect = self.image.get_rect(center=position)
self.position = pygame.math.Vector2(position)
self.velocity = pygame.math.Vector2(0, 0)
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += self.k_up + self.k_down
# To clamp the speed.
self.speed = max(-self.MAX_REVERSE_SPEED,
min(self.speed, self.MAX_FORWARD_SPEED))
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
rad = math.radians(self.direction)
self.velocity.x = -self.speed*math.sin(rad)
self.velocity.y = -self.speed*math.cos(rad)
self.position += self.velocity
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect(center=self.position)
class Background(pygame.sprite.Sprite):
def __init__(self, image, location):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect(topleft=location)
def game_loop():
background = Background(BACKGROUND, [0, 0])
bike = VehicleSprite(VEHICLE1, rect.center)
ball = VehicleSprite(VEHICLE2, rect.center)
bike_group = pygame.sprite.Group(bike)
ball_group = pygame.sprite.Group(ball)
all_sprites = pygame.sprite.Group(bike_group, ball_group)
camera = pygame.math.Vector2(0, 0)
done = False
while not done:
time = clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
# Bike Input (Player 1)
if event.key == pygame.K_d:
bike.k_right = -5
elif event.key == pygame.K_a:
bike.k_left = 5
elif event.key == pygame.K_w:
bike.k_up = 2
elif event.key == pygame.K_s:
bike.k_down = -2
elif event.key == pygame.K_ESCAPE:
done = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
bike.k_right = 0
elif event.key == pygame.K_a:
bike.k_left = 0
elif event.key == pygame.K_w:
bike.k_up = 0
elif event.key == pygame.K_s:
bike.k_down = 0
camera -= bike.velocity
all_sprites.update(time)
screen.fill(WHITE)
screen.blit(background.image, background.rect)
for sprite in all_sprites:
screen.blit(sprite.image, sprite.rect.topleft+camera)
pygame.display.flip()
game_loop()
pygame.quit()
import pygame, random
pygame.init()
screen = pygame.display.set_mode((640, 480))
class Ship(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.screen = screen
self.image = pygame.image.load("ship.jpg")
self.image = self.image.convert()
self.rect = self.image.get_rect()
self.rect.center = (320, 400)
self.dx = 0
self.dy = 0
self.x = self.rect.centerx
self.y = self.rect.centery
def update(self):
self.checkBounds()
def checkBounds(self):
screen = self.screen
if self.x > screen.get_width():
self.x = screen.get_width()
if self.x < 0:
self.x = 0
class Missile(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("missile.jpg")
self.image = self.image.convert()
self.rect = self.image.get_rect()
self.reset()
def update(self):
self.rect.centery += self.dy
if self.rect.top > screen.get_height():
self.reset()
def reset(self):
self.rect.bottom = 0
self.rect.centerx = random.randrange(0, screen.get_width())
self.dy = random.randrange(5, 10)
def main():
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0, 0))
ship = Ship()
missile = Missile()
allSprites = pygame.sprite.Group(missile, ship)
clock = pygame.time.Clock()
keepGoing = True
while keepGoing:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
ship.rect.centerx = ship.rect.centerx-10
elif event.key == pygame.K_RIGHT:
ship.rect.centerx = ship.rect.centerx + 10
elif event.type == pygame.KEYUP:
ship.rect.centerx = ship.rect.centerx + 0
elif event.key == pygame.K_DOWN:
ship.rect.centerx = ship.rect.centerx - 0
if pygame.sprite.collide_rect(ship,missile) == True:
self.image = pygame.image.load("explosion.jpg")
allSprites.clear(screen, background)
allSprites.update()
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
self.image = pygame.image.load("explosion.jpg")
This line is not part of any class. There is no self here. I guess you mean
ship.image = pygame.image.load("explosion.jpg")
or something similar. Might as well be
missile.image = pygame.image.load("explosion.jpg")
So this is my game I've bean working on and so have things are going very well, the player can move around and shoot down the boxes which are ment to be moving but theres these small glitches, but before I go on heres the code:
import pygame, math, random, sys
from pygame import *
import random, math, cmath
pygame.init()
#variables end----------------------------------------------------------------
#imagers
grass = "grass_shit.png" #grass image
player_img = "shithead.png" #player name
ali_img = "shit_head2.png" #alien image
dead_screen = "dead_shit.png"
cross_hair = "crosshair.png"
playButton = "playbutton.png"
#screen
screen = pygame.display.set_mode((850, 640),0,32) #set screen
background = pygame.image.load(grass).convert() #load image to screen
health = 100
#mouse things
crosshair = pygame.image.load(cross_hair).convert_alpha()
#variables end----------------------------------------------------------------
pygame.mouse.set_visible(False)
black = ( 0, 0, 0)
white = ( 255, 255, 255)
red = ( 255, 0, 0)
blue = ( 0, 0, 255)
player_x, player_y = 0, 0
move_player_x, move_player_y = 0, 0
move_ali_x, move_ali_y = 0, 0
class Block(pygame.sprite.Sprite):
def __init__(self, color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
def update(self):
global move_ali_x
global move_ali_y
if block.rect.x < player_x:
move_ali_x =+ 0.05
elif block.rect.x > player_x:
move_ali_x =- 0.05
if block.rect.y < player_y:
move_ali_y =+ 0.05
elif block.rect.y > player_y:
move_ali_y =- 0.05
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20,20])
self.image.fill(red)
self.rect = self.image.get_rect()
def update(self):
pos = pygame.mouse.get_pos()
self.rect.x = player_x
self.rect.y = player_y
class Bullet(pygame.sprite.Sprite):
def __init__(self, mouse, player):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([4, 10])
self.image.fill(black)
self.mouse_x, self.mouse_y = mouse[0], mouse[1]
self.player = player
self.rect = self.image.get_rect()
def update(self):
speed = 10
range = 50000
distance = [self.mouse_x - self.player[0], self.mouse_y - self.player[1]]
norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
direction = [distance[0] / norm, distance[1] / norm]
bullet_vector = [direction[0] * speed, direction[1] * speed]
self.rect.x += bullet_vector[0]
self.rect.y += bullet_vector[1]
pygame.init()
screen_width = 850
screen_height = 640
screen = pygame.display.set_mode([screen_width,screen_height])
all_sprites_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
for i in range(5):
block = Block(blue)
block.rect.x = random.randrange(screen_width)
block.rect.y = random.randrange(350)
block_list.add(block)
all_sprites_list.add(block)
player = Player()
all_sprites_list.add(player)
done = False
clock = pygame.time.Clock()
score = 0
player.rect.y = 370
# -------- Main Program Loop -----------
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
bullet = Bullet(event.pos, [player.rect.x, player.rect.y])
bullet.rect.x = player.rect.x
bullet.rect.y = player.rect.y
all_sprites_list.add(bullet)
bullet_list.add(bullet)
if event.type== pygame.KEYDOWN:
if event.key==K_a:
move_player_x=-4
elif event.key==K_d:
move_player_x=+4
elif event.key==K_w:
move_player_y=-4
elif event.key==K_s:
move_player_y=+4
if event.type== pygame.KEYUP:
if event.key==K_a:
move_player_x=0
elif event.key==K_d:
move_player_x=0
elif event.key==K_w:
move_player_y=0
elif event.key==K_s:
move_player_y=0
# --- Game logic
all_sprites_list.update()
player_x += move_player_x
player_y += move_player_y
block.rect.y += move_ali_y
block.rect.x += move_ali_x
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, block_list, True)
for block in block_hit_list:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 1
print( score )
if bullet.rect.y < -10:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
if player.rect.colliderect(block.rect):
health =- 35
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_x -= crosshair.get_width() / 2
mouse_y -= crosshair.get_height() / 2
screen.blit(background,(0,0))
all_sprites_list.draw(screen)
screen.blit(crosshair,(mouse_x, mouse_y))
pygame.display.flip()
pygame.display.update()
clock.tick(20)
pygame.quit()
So glitch number one:
only one of the boxers moves, I cant figure out why it only one of them is moving towards the player, all the boxers are meant to move towards the player as this is hoping to become a zombie shooter.
Glitch two:
At a random point the box that does move does stops moving in all directions but one, so lets say this happens when the box in in the center of the screen, if the player goes to the left of the box, nothing, but when the player moves to thr right of the player it moves right, but only right not up or down, and this seams to happen at soem point everytime.
Well thats it, hope you can help thanks heaps stackoverflow
Your code should looks like this:
import pygame
from pygame import *
import sys
import math
import random
import cmath
#----------------------------------------------------------------------
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
#imagers
IMAGE_GRASS = "grass_shit.png" #grass image
IMAGE_PLAYER = "shithead.png" #player name
IMAGE_ALI = "shit_head2.png" #alien image
IMAGE_DEAD_SCREEN = "dead_shit.png"
IMAGE_CROSSHAIR = "crosshair.png"
IMAGE_PLAYBUTTON = "playbutton.png"
#~ IMAGE_GRASS = "ball3.png" #grass image
#~ IMAGE_PLAYER = "ball2.png" #player name
#~ IMAGE_ALI = "ball3.png" #alien image
#~ IMAGE_DEAD_SCREEN = "ball3.png"
#~ IMAGE_CROSSHAIR = "ball1.png"
#~ IMAGE_PLAYBUTTON = "ball3.png"
#----------------------------------------------------------------------
class Block(pygame.sprite.Sprite):
def __init__(self, color, x, y, player = None):
pygame.sprite.Sprite.__init__(self)
self.player = player
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.move_x = self.move_y = 0
def update(self):
if self.player:
player_x, player_y = self.player.rect.center
if self.rect.x < player_x:
self.rect.x += 1
elif self.rect.x > player_x:
self.rect.x -= 1
if self.rect.y < player_y:
self.rect.y += 1
elif self.rect.y > player_y:
self.rect.y -= 1
#----------------------------------------------------------------------
class Player(pygame.sprite.Sprite):
def __init__(self, screen_rect, x=0, y=0):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20,20])
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.min_x = screen_rect.left
self.min_y = screen_rect.top
self.max_x = screen_rect.right
self.max_y = screen_rect.bottom
self.move_x = self.move_y = 0
self.health = 100
def update(self):
pos = pygame.mouse.get_pos()
self.rect.x += self.move_x
self.rect.y += self.move_y
if self.rect.top < self.min_x:
self.rect.top = self.min_x
elif self.rect.bottom > self.max_y:
self.rect.bottom = self.max_y
if self.rect.left < self.min_x:
self.rect.left = self.min_x
elif self.rect.right > self.max_x:
self.rect.right = self.max_x
def event_handler(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
self.move_x = -4
elif event.key == pygame.K_d:
self.move_x = +4
elif event.key == pygame.K_w:
self.move_y = -4
elif event.key == pygame.K_s:
self.move_y = +4
if event.type == pygame.KEYUP:
if event.key in (pygame.K_a, pygame.K_d):
self.move_x = 0
elif event.key in (pygame.K_w, pygame.K_s):
self.move_y = 0
#----------------------------------------------------------------------
class Bullet(pygame.sprite.Sprite):
def __init__(self, start_pos, mouse_pos):
pygame.sprite.Sprite.__init__(self)
self.start_rect = start_pos.rect.copy()
self.mouse_x, self.mouse_y = mouse_pos # mouse[0], mouse[1]
self.image = pygame.Surface([5, 5])
self.image.fill(BLACK)
self.rect = self.image.get_rect()
self.rect.centerx = self.start_rect.centerx
self.rect.centery = self.start_rect.centery
self.speed = 10
self.max_range = 50
self.current_range = 0
distance_x = self.mouse_x - self.start_rect.centerx
distance_y = self.mouse_y - self.start_rect.centery
norm = math.sqrt(distance_x ** 2 + distance_y ** 2)
direction_x = distance_x / norm
direction_y = distance_y / norm
self.bullet_vector_x = direction_x * self.speed
self.bullet_vector_y = direction_y * self.speed
def update(self):
self.current_range += 1
if self.current_range < self.max_range:
print self.start_rect.centerx + (self.bullet_vector_x*self.current_range),
print self.rect.centerx + self.bullet_vector_x,
#self.rect.centerx += self.bullet_vector_x
self.rect.centerx = self.start_rect.centerx + (self.bullet_vector_x*self.current_range)
print self.rect.centerx
#self.rect.centery += self.bullet_vector_y
self.rect.centery = self.start_rect.centery + (self.bullet_vector_y*self.current_range)
else:
self.kill()
#----------------------------------------------------------------------
class Crosshair(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(IMAGE_CROSSHAIR).convert_alpha()
self.rect = self.image.get_rect()
def update(self):
mouse_x, mouse_y = pygame.mouse.get_pos()
self.rect.centerx = mouse_x
self.rect.centery = mouse_y
def draw(self, screen):
screen.blit(self.image,self.rect.topleft)
#----------------------------------------------------------------------
class Background(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(IMAGE_GRASS).convert_alpha()
self.rect = self.image.get_rect()
def draw(self, screen):
screen.fill((128,128,128))
screen.blit(self.image,(0,0))
#----------------------------------------------------------------------
class Game():
def __init__(self):
pygame.init()
screen_width = 850
screen_height = 640
self.screen = pygame.display.set_mode( (screen_width,screen_height) )
pygame.mouse.set_visible(False)
#-----
self.all_sprites_list = pygame.sprite.Group()
self.block_list = pygame.sprite.Group()
self.bullet_list = pygame.sprite.Group()
# --- create sprites ---
self.background = Background()
self.player = Player(self.screen.get_rect(), 0, 370)
self.all_sprites_list.add(self.player)
for i in range(5):
block = Block(BLUE, random.randrange(100, screen_width), random.randrange(10, screen_height-10), self.player)
self.block_list.add(block)
self.all_sprites_list.add(block)
self.crosshair = Crosshair()
#-----
font = pygame.font.SysFont("", 72)
self.text_pause = font.render("PAUSE", -1, RED)
self.text_pause_rect = self.text_pause.get_rect(center=self.screen.get_rect().center) # center text
#-----
self.score = 0
def bullet_create(self, start_pos, mouse_pos):
bullet = Bullet(start_pos, mouse_pos)
self.all_sprites_list.add(bullet)
self.bullet_list.add(bullet)
def bullets_update(self):
for bullet in self.bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, self.block_list, True)
for block in block_hit_list:
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
self.score += 1
print self.score
if bullet.rect.y < -10:
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
if pygame.sprite.collide_rect(self.player, block):
self.player.health =- 35
# -------- Main Program Loop -----------
def run(self):
clock = pygame.time.Clock()
RUNNING = True
PAUSED = False
while RUNNING:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
RUNNING = false
elif event.key == pygame.K_SPACE:
PAUSED = not PAUSED
elif event.type == pygame.MOUSEBUTTONDOWN:
self.bullet_create(self.player, event.pos)
# send event to player
self.player.event_handler(event)
# send event to crosshair for mousebuttondown
#if not PAUSED:
# self.crosshair.event_handler(event)
# --- updates ---
if not PAUSED:
self.all_sprites_list.update()
self.bullets_update()
self.crosshair.update()
# --- draws ---
self.background.draw(self.screen)
self.all_sprites_list.draw(self.screen)
self.crosshair.draw(self.screen)
if PAUSED:
self.screen.blit(self.text_pause, self.text_pause_rect.topleft)
pygame.display.update() # use flip() OR update()
# --- FPS ---
clock.tick(20)
# --- quit ---
pygame.quit()
#----------------------------------------------------------------------
Game().run()
Changes:
player can move but can leave screen
press space to pause game - but you can still move cursor and fire :)
bullet has max range - than it is removed
i change bullet vetor calculations because value was rounded to integer every frame and bullet trajectory was incorrect
bullet never change trajectory when player is moving
all code is in classes except some constant values. I add class Crosshair and Background
you can see how class (Player) handle events in event_handle
I use pygame.Rect() (screen.get_rect(), image.get_rect()) to get rect.top, rect.left, rect.center, rect.centerx, rect.topleft, etc.
There is still many things to do.
ps. if someone needs images 'ball1.png', 'ball2.png', 'ball3.png' to run this example you can find it in answer to
Space invaders project
Pygame- window and sprite class - python