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.
Related
Im new to python and im currently making a simple pygame but I can not grasp the concept of sprites. I want to replace the moving block with a player icon that I created.
Do I need to make a group just for one object or is there a way just to add the player without any groups?
from pygame import sprite
import pygame, sys
from pygame.locals import*
from pynput.keyboard import Key, Controller
class Player(pygame.sprite.Sprite):
def __init__(self, picture_path):
super().__init__()
self.image = pygame.image.load(picture_path)
self.rect = self.image.get_rect()
def main():
pygame.init()
DISPLAY=pygame.display.set_mode((1280,720),0,32)
pygame.display.set_caption('Der Sammler')
WHITE=(255,255,255)
BLUE=(0,0,255)
DISPLAY.fill(WHITE)
x = 0
y = 0
velocity1 = 0
acceleration = 0.1
velocity = pygame.Vector2()
velocity.xy = 3, 0
player = Player("player.png")
while True:
pygame.draw.rect(DISPLAY, BLUE, (x,y,50,50))
x += velocity.x
if x+ 50 > DISPLAY.get_width():
velocity.x = -3
if x < 0:
velocity.x = 3
pressed_keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
DISPLAY.fill((255, 255, 255))
pygame.draw.rect(DISPLAY,BLUE, (x,y, 50, 50))
y += velocity1
velocity1 += acceleration
if pressed_keys[pygame.K_SPACE]:
velocity1 = -3
pygame.display.update()
pygame.time.delay(10)
main()
Add an update method to Player and put the movement and gravity algorithm in that method:
class Player(pygame.sprite.Sprite):
def __init__(self, picture_path):
super().__init__()
self.image = pygame.image.load(picture_path)
self.rect = self.image.get_rect()
self.velocity = pygame.Vector2(3, 0)
self.acceleration = 0.1
def update(self, dispaly):
pressed_keys = pygame.key.get_pressed()
self.rect.x += self.velocity.x
if self.rect.right >= dispaly.get_width():
self.velocity.x = -3
if self.rect.left < 0:
self.velocity.x = 3
self.rect.y += self.velocity.y
self.velocity.y += self.acceleration
if pressed_keys[pygame.K_SPACE]:
self.velocity.y = -3
Add the player to a pygame.sprite.Group:
sprites = pygame.sprite.Group(player)
Call sprites.update() and sprites.draw() in the application loop to update the position of the player and to move the player:
while True:
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
sprites.update(DISPLAY)
DISPLAY.fill((255, 255, 255))
sprites.draw(DISPLAY)
pygame.display.update()
Also see How can I add objects to a "pygame.sprite.Group()"?.
Complete example:
import pygame, sys
from pygame.locals import*
class Player(pygame.sprite.Sprite):
def __init__(self, picture_path):
super().__init__()
self.image = pygame.image.load(picture_path)
self.rect = self.image.get_rect()
self.velocity = pygame.Vector2(3, 0)
self.acceleration = 0.1
def update(self, dispaly):
pressed_keys = pygame.key.get_pressed()
self.rect.x += self.velocity.x
if self.rect.right >= dispaly.get_width():
self.velocity.x = -3
if self.rect.left < 0:
self.velocity.x = 3
self.rect.y += self.velocity.y
self.velocity.y += self.acceleration
if pressed_keys[pygame.K_SPACE]:
self.velocity.y = -3
if self.rect.bottom > dispaly.get_height():
self.rect.bottom = dispaly.get_height()
self.velocity.y = 0
def main():
pygame.init()
DISPLAY=pygame.display.set_mode((1280,720),0,32)
pygame.display.set_caption('Der Sammler')
clock = pygame.time.Clock()
WHITE=(255,255,255)
BLUE=(0,0,255)
DISPLAY.fill(WHITE)
player = Player("player.png")
sprites = pygame.sprite.Group(player)
while True:
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
sprites.update(DISPLAY)
DISPLAY.fill((255, 255, 255))
sprites.draw(DISPLAY)
pygame.display.update()
clock.tick(100)
main()
I've been working on this project about tanks (based on game Tank Trouble) and I'm wondering how I can move forward after I change angle of the sprite. Also if you know how I can make my bullets ricochet from the walls. I will really appreciate any help given. Thank you!
Here is my tank and bullet:
Here is code of the game:
import sys
import pygame
class Game:
def __init__(self):
self.run = True
self.screen_width = 1060
self.screen_height = 798
self.image = pygame.image.load("sprites/background/background1.png")
self.image = pygame.transform.scale(self.image, (self.screen_width, self.screen_height))
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
# all_sprites is used to update and draw all sprites together.
self.all_sprites = pygame.sprite.Group()
# for collision detection with enemies.
self.bullet_group = pygame.sprite.Group()
self.tank = Tank()
self.all_sprites.add(self.tank)
bullet = Bullet(self.tank)
self.bullet_group.add(bullet)
self.all_sprites.add(bullet)
def handle_events(self):
keys = pygame.key.get_pressed()
self.tank.handle_events()
if keys[pygame.K_UP]:
self.tank.rect.centery -= 5
if keys[pygame.K_DOWN]:
self.tank.rect.centery += 5
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.run = False
if event.key == pygame.K_SPACE:
bullet = Bullet(self.tank)
self.bullet_group.add(bullet)
self.all_sprites.add(bullet)
def update(self):
# Calls `update` methods of all contained sprites.
self.all_sprites.update()
def draw(self):
self.screen.blit(self.image, (0, 0))
self.all_sprites.draw(self.screen) # Draw the contained sprites.
pygame.display.update()
class Tank(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("sprites/player/player_tank.png")
self.org_image = self.image.copy()
# A nicer way to set the start pos with `get_rect`.
self.rect = self.image.get_rect(center=(70, 600))
self.angle = 0
self.direction = pygame.Vector2(1, 0)
self.pos = pygame.Vector2(self.rect.center)
def handle_events(self):
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]:
self.angle += 3
if pressed[pygame.K_RIGHT]:
self.angle -= 3
self.direction = pygame.Vector2(1, 0).rotate(-self.angle)
self.image = pygame.transform.rotate(self.org_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Bullet(pygame.sprite.Sprite):
def __init__(self, tank):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("sprites/bullet/bullet.png")
self.image = pygame.transform.scale(self.image, (16, 16))
self.rect = self.image.get_rect()
self.rect.centerx = tank.rect.centerx + 3 # How much pixels from tank turret on x axis
self.rect.centery = tank.rect.centery - 25 # How much pixels from tank turret on y axis
def update(self):
self.rect.y -= 10 # Move up 10 pixels per frame.
def main():
pygame.init()
pygame.display.set_caption('Tank Game')
clock = pygame.time.Clock()
game = Game()
while game.run:
game.handle_events()
game.update()
game.draw()
clock.tick(60)
if __name__ == '__main__':
main()
pygame.quit()
sys.exit()
To move the tank in the direction which is faced, wirte a method, that computes a direction vector, dependent on an velocity argument and the self.angle attribute. The nagle and the velocity define a vector by Polar coordinats.
Add the vector to it's current position (self.pos). Finally update the self.rect attribute by the position:
class Tank(pygame.sprite.Sprite):
# [...]
def move(self, velocity):
direction = pygame.Vector2(0, velocity).rotate(-self.angle)
self.pos += direction
self.rect.center = round(self.pos[0]), round(self.pos[1])
Invoke the method when up or down is pressed:
class Game:
# [...]
def handle_events(self):
# [...]
if keys[pygame.K_UP]:
self.tank.move(-5)
if keys[pygame.K_DOWN]:
self.tank.move(5)
The movement direction of the bullets can be computed similar:
class Bullet(pygame.sprite.Sprite):
def __init__(self, tank):
#[...]
self.rect = self.image.get_rect()
self.angle = tank.angle
self.pos = pygame.Vector2(tank.pos)
self.rect.center = round(self.pos.x), round(self.pos.y)
self.direction = pygame.Vector2(0, -10).rotate(-self.angle)
def update(self):
self.pos += self.direction
self.rect.center = round(self.pos[0]), round(self.pos[1])
To make the bullet bounce, you have to reflect the direction when the bullet hits a border:
class Bullet(pygame.sprite.Sprite):
# [...]
def update(self):
self.pos += self.direction
self.rect.center = round(self.pos.x), round(self.pos.y)
if self.rect.left < 0:
self.direction.x *= -1
self.rect.left = 0
self.pos.x = self.rect.centerx
if self.rect.right > 1060:
self.direction.x *= -1
self.rect.right = 1060
self.pos.x = self.rect.centerx
if self.rect.top < 0:
self.direction.y *= -1
self.rect.top = 0
self.pos.y = self.rect.centery
if self.rect.bottom > 798:
self.direction.y *= -1
self.rect.right = 798
self.pos.y = self.rect.centery
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.
I'm trying to develop a Brick Breaker/Breakout game using pygame, but I'm facing a annoying problem that blots the "ball" on the paddle(player) when I move with the arrows, i'm lefting the code for you to have a look.
import pygame
pygame.init()
isRunning = True
WIDTH = 800
HEIGHT = 600
FPS = 60
clock = pygame.time.Clock()
window = pygame.display.set_mode((WIDTH, HEIGHT))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((60, 30))
self.image.fill((200, 255, 200))
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 30
def update(self):
self.speedx = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_a]:
self.speedx = -5
if keystate[pygame.K_d]:
self.speedx = 5
self.rect.x += self.speedx
if self.rect.right + self.speedx > WIDTH:
self.rect.right = WIDTH
if self.rect.left + self.speedx < 0:
self.rect.left = 0
ball = Ball(self.rect.centerx, self.rect.top)
for i in all_sprites:
print(i)
all_sprites.add(ball)
def shoot(self):
ball = Ball(self.rect.centerx, self.rect.top)
all_sprites.add(ball)
balls.add(ball)
class Ball(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 10))
self.image.fill((100, 150, 200))
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
pass
#self.rect.y += self.speedy
all_sprites = pygame.sprite.Group()
balls = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
while isRunning:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
isRunning = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
window.fill((0, 0, 30))
all_sprites.update()
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
quit()
I'm not sure if I understand your question, but the problem with the code is that you're creating a ball every time you're updating the player. Just remove the last four lines in the player update method and uncomment the line in the ball's update method and everything works as it should.
Additional tips
Delete the balls when they exit the screen. This will prevent the game from running slow or crashing. It can be don by adding if self.rect.bottom < 0: self.kill() in the ball update method.
Use elif when appropriate.
In the player update method you define an attribute self.speedx which is only used inside that method, thus it's better to just use a local variable instead. Also, it's discourage to define attributes outside the __init__ method.
Here's your code slightly modified.
import pygame
pygame.init()
is_running = True # Use lowercase_and_underscore for variable names.
WIDTH = 800
HEIGHT = 600
FPS = 60
clock = pygame.time.Clock()
window = pygame.display.set_mode((WIDTH, HEIGHT))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((60, 30))
self.image.fill((200, 255, 200))
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 30
def update(self):
speedx = 0 # Don't define attributes outside __init__. Local variable works in this case instead.
keystate = pygame.key.get_pressed()
if keystate[pygame.K_a]:
speedx = -5
elif keystate[pygame.K_d]: # Use elif so it doesn't need to check this condition if the above is true.
speedx = 5
self.rect.x += speedx
if self.rect.right + speedx > WIDTH:
self.rect.right = WIDTH
elif self.rect.left + speedx < 0: # Use elif so it doesn't need to check this condition if the above is true.
self.rect.left = 0
def shoot(self):
ball = Ball(self.rect.centerx, self.rect.top)
all_sprites.add(ball)
balls.add(ball)
class Ball(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 10))
self.image.fill((100, 150, 200))
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
if self.rect.bottom < 0: # Chack if the ball has exit above the screen.
self.kill() # If it has it should delete itself.
self.rect.y += self.speedy
all_sprites = pygame.sprite.Group()
balls = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
while is_running:
clock.tick(FPS)
print(all_sprites)
for event in pygame.event.get():
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
window.fill((0, 0, 30))
all_sprites.update()
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
quit()
EDIT: KEEPING THE BALL ON THE PADDLE AND LAUNCHING WITH SPACE
First you could create an attribute self.current_ball in the Player class which will reference the ball on the paddle. Then in the update method of the Player class you update the ball's position relative to the paddle.
To keep the ball at the paddle you have to change the ball's self.speedy to start at 0, otherwise it will move directly after being created. When you call the player.shoot() method you'll set self.speedy = -3 which will start the ball to move.
After it has been launched you just create a new ball on the paddle and repeat the same process.
import pygame
pygame.init()
is_running = True # Use lowercase_and_underscore for variable names.
WIDTH = 800
HEIGHT = 600
FPS = 60
clock = pygame.time.Clock()
window = pygame.display.set_mode((WIDTH, HEIGHT))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((60, 30))
self.image.fill((200, 255, 200))
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 30
self.current_ball = Ball(self.rect.centerx, self.rect.top)
all_sprites.add(self.current_ball)
balls.add(self.current_ball)
def update(self):
speedx = 0 # Don't define attributes outside __init__. Local variable works in this case instead.
keystate = pygame.key.get_pressed()
if keystate[pygame.K_a]:
speedx = -5
elif keystate[pygame.K_d]: # Use elif so it doesn't need to check this condition if the above is true.
speedx = 5
self.rect.x += speedx
if self.rect.right + speedx > WIDTH:
self.rect.right = WIDTH
elif self.rect.left + speedx < 0: # Use elif so it doesn't need to check this condition if the above is true.
self.rect.left = 0
self.current_ball.rect.midbottom = self.rect.midtop # Set the ball position relative to paddle position.
def shoot(self):
self.current_ball.speedy = -3 # The ball should start moving.
self.current_ball = Ball(self.rect.centerx, self.rect.top) # Create a new ball on the paddle.
all_sprites.add(self.current_ball)
balls.add(self.current_ball)
class Ball(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 10))
self.image.fill((100, 150, 200))
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 0 # The ball don't move from the beginning.
def update(self):
if self.rect.bottom < 0: # Chack if the ball has exit above the screen.
self.kill() # If it has it should delete itself.
self.rect.y += self.speedy
all_sprites = pygame.sprite.Group()
balls = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
while is_running:
clock.tick(FPS)
print(all_sprites)
for event in pygame.event.get():
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
window.fill((0, 0, 30))
all_sprites.update()
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
quit()
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