Posts: 148
Threads: 34
Joined: May 2020
Hi,
I'm trying to add mouse control for the character in a Space Invaders clone whose code I found online.
Determining the X position of the mouse pointer (event.pos[0]) works, in line 278 I pass this to the function
"spaceship.update(event.pos[0])".
The error occurs in line 242, see error message.
I don't understand the error message, because I specified "pos" on line 75...
When I move the mouse, the program crahses...
I tried very long and don't know the reason for the error.
Thank you very much for your support!
Traceback (most recent call last):
File "D:\Daten\aktuell\sinvaders\main.py", line 242, in <module>
game_over = spaceship.update()
TypeError: Spaceship.update() missing 1 required positional argument: 'pos'
import pygame
from pygame import mixer
from pygame.locals import *
import random
pygame.mixer.pre_init(44100, -16, 2, 512)
mixer.init()
pygame.init()
#define fps
clock = pygame.time.Clock()
fps = 60
screen_width = 1280
screen_height = 720
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Space Invanders')
#define fonts
font30 = pygame.font.SysFont('Constantia', 30)
font40 = pygame.font.SysFont('Constantia', 40)
#load sounds
#explosion_fx = pygame.mixer.Sound("img/explosion.wav")
#explosion_fx.set_volume(0.25)
#explosion2_fx = pygame.mixer.Sound("img/explosion2.wav")
#explosion2_fx.set_volume(0.25)
#laser_fx = pygame.mixer.Sound("img/laser.wav")
#laser_fx.set_volume(0.25)
#define game variables
rows = 4
cols = 10
alien_cooldown = 1000#bullet cooldown in milliseconds
last_alien_shot = pygame.time.get_ticks()
countdown = 3
last_count = pygame.time.get_ticks()
game_over = 0#0 is no game over, 1 means player has won, -1 means player has lost
#define colours
red = (255, 0, 0)
green = (0, 255, 0)
white = (255, 255, 255)
#load image
bg = pygame.image.load("images/bg.png")
screen_rect = bg.get_rect()
def draw_bg():
screen.blit(bg, (0, 0))
#define function for creating text
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
screen.blit(img, (x, y))
#create spaceship class
class Spaceship(pygame.sprite.Sprite):
def __init__(self, x, y, health):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/ship.png")
self.rect = self.image.get_rect()
self.rect.center = [x, y]
self.health_start = health
self.health_remaining = health
self.last_shot = pygame.time.get_ticks()
self.xmin = self.rect.width // 2 # Compute Spaceship x range.
self.xmax = screen_width - self.xmin
def update(self, pos):
self.centerx = max(self.xmin, min(self.xmax, pos))
#set a cooldown variable
cooldown = 500 #milliseconds
game_over = 0
#record current time
time_now = pygame.time.get_ticks()
#shoot, get key press
key = pygame.key.get_pressed()
if key[pygame.K_SPACE] and time_now - self.last_shot > cooldown:
#laser_fx.play()
bullet = Bullets(self.rect.centerx, self.rect.top)
bullet_group.add(bullet)
self.last_shot = time_now
#update mask
self.mask = pygame.mask.from_surface(self.image)
#draw health bar
pygame.draw.rect(screen, red, (self.rect.x, (self.rect.bottom + 10), self.rect.width, 15))
if self.health_remaining > 0:
pygame.draw.rect(screen, green, (self.rect.x, (self.rect.bottom + 10), int(self.rect.width * (self.health_remaining / self.health_start)), 15))
elif self.health_remaining <= 0:
explosion = Explosion(self.rect.centerx, self.rect.centery, 3)
explosion_group.add(explosion)
self.kill()
game_over = -1
return game_over
#create Bullets class
class Bullets(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/bullet.png")
self.rect = self.image.get_rect()
self.rect.center = [x, y]
def update(self):
self.rect.y -= 5
if self.rect.bottom < 0:
self.kill()
if pygame.sprite.spritecollide(self, alien_group, True, pygame.sprite.collide_mask):
self.kill()
#explosion_fx.play()
explosion = Explosion(self.rect.centerx, self.rect.centery, 2)
explosion_group.add(explosion)
#create Aliens class
class Aliens(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/alien" + str(random.randint(1, 5)) + ".png")
self.x = x
self.y = y
self.rect = self.image.get_rect()
self.rect.center = [x, y]
self.move_direction = 1
def update(self):
self.rect.x += self.move_direction
if self.rect.right >= screen_width or self.rect.left <= 0:
self.move_direction *= -1
# update mask
self.mask = pygame.mask.from_surface(self.image)
#create Alien Bullets class
class Alien_Bullets(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/alien_bullet.png")
self.rect = self.image.get_rect()
self.rect.center = [x, y]
def update(self):
self.rect.y += 2
if self.rect.top > screen_height:
self.kill()
if pygame.sprite.spritecollide(self, spaceship_group, False, pygame.sprite.collide_mask):
self.kill()
#explosion2_fx.play()
#reduce spaceship health
spaceship.health_remaining -= 1
explosion = Explosion(self.rect.centerx, self.rect.centery, 1)
explosion_group.add(explosion)
#create Explosion class
class Explosion(pygame.sprite.Sprite):
def __init__(self, x, y, size):
pygame.sprite.Sprite.__init__(self)
self.images = []
for num in range(1, 8):
img = pygame.image.load(f"images/explosion{num}.png")
if size == 1:
img = pygame.transform.scale(img, (20, 20))
if size == 2:
img = pygame.transform.scale(img, (100, 100))
if size == 3:
img = pygame.transform.scale(img, (160, 160))
#add the image to the list
self.images.append(img)
self.index = 0
self.image = self.images[self.index]
self.rect = self.image.get_rect()
self.rect.center = [x, y]
self.counter = 0
def update(self):
explosion_speed = 3
#update explosion animation
self.counter += 1
if self.counter >= explosion_speed and self.index < len(self.images) - 1:
self.counter = 0
self.index += 1
self.image = self.images[self.index]
#if the animation is complete, delete explosion
if self.index >= len(self.images) - 1 and self.counter >= explosion_speed:
self.kill()
#create sprite groups
spaceship_group = pygame.sprite.Group()
bullet_group = pygame.sprite.Group()
alien_group = pygame.sprite.Group()
alien_bullet_group = pygame.sprite.Group()
explosion_group = pygame.sprite.Group()
def create_aliens():
#generate aliens
for row in range(rows):
for item in range(cols):
alien = Aliens(100 + item * 100, 100 + row * 100)
alien_group.add(alien)
create_aliens()
#create player
spaceship = Spaceship(int(screen_width / 2), screen_height - 100, 3)
spaceship_group.add(spaceship)
run = True
while run:
clock.tick(fps)
#draw background
draw_bg()
if countdown == 0:
#create random alien bullets
#record current time
time_now = pygame.time.get_ticks()
#shoot
if time_now - last_alien_shot > alien_cooldown and len(alien_bullet_group) < 5 and len(alien_group) > 0:
attacking_alien = random.choice(alien_group.sprites())
alien_bullet = Alien_Bullets(attacking_alien.rect.centerx, attacking_alien.rect.bottom)
alien_bullet_group.add(alien_bullet)
last_alien_shot = time_now
#check if all the aliens have been killed
if len(alien_group) == 0:
game_over = 1
if game_over == 0:
#update spaceship
game_over = spaceship.update()
#update sprite groups
bullet_group.update()
alien_group.update()
alien_bullet_group.update()
else:
if game_over == -1:
draw_text('GAME OVER!', font40, white, int(screen_width / 2 - 100), int(screen_height / 2 + 50))
if game_over == 1:
draw_text('YOU WIN!', font40, white, int(screen_width / 2 - 100), int(screen_height / 2 + 50))
if countdown > 0:
draw_text('GET READY!', font40, white, int(screen_width / 2 - 110), int(screen_height / 2 + 50))
draw_text(str(countdown), font40, white, int(screen_width / 2 - 10), int(screen_height / 2 + 100))
count_timer = pygame.time.get_ticks()
if count_timer - last_count > 1000:
countdown -= 1
last_count = count_timer
#update explosion group
explosion_group.update()
#draw sprite groups
spaceship_group.draw(screen)
bullet_group.draw(screen)
alien_group.draw(screen)
alien_bullet_group.draw(screen)
explosion_group.draw(screen)
#event handlers
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEMOTION:
spaceship.update(event.pos[0])
pygame.display.update()
pygame.quit()
Posts: 6,798
Threads: 20
Joined: Feb 2020
Apr-06-2024, 09:24 PM
(This post was last modified: Apr-06-2024, 09:24 PM by deanhystad.)
Spaceship.update(self, pos) takes an argument. On line 242 your program calls the method but does not pass a value for pos.
game_over = spaceship.update() # No value for pos
Posts: 148
Threads: 34
Joined: May 2020
Hi,
thank you for answering...
I think, I got it now...
Because there were problems, if self.rect.centerx = max(self.xmin, min(self.xmax, xpos)) is inside the function "spaceship.update()"
I put it in a own function "move()".
Now it works...
#create spaceship class
class Spaceship(pygame.sprite.Sprite):
def __init__(self, x, y, health):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.health_start = health
self.health_remaining = health
self.image = pygame.image.load("images/ship.png")
self.rect = self.image.get_rect()
self.rect.center = [x, y]
self.xmin = self.rect.width // 2 # Compute Spaceship x range.
self.xmax = screen_width - self.xmin
self.last_shot = pygame.time.get_ticks()
def move(self, xpos):
self.rect.centerx = max(self.xmin, min(self.xmax, xpos))
def update(self):
#set a cooldown variable
cooldown = 500 #milliseconds
game_over = 0
#record current time
time_now = pygame.time.get_ticks()
#shoot, get key press
key = pygame.key.get_pressed()
if key[pygame.K_SPACE] and time_now - self.last_shot > cooldown:
#laser_fx.play()
bullet_1 = Bullets(self.rect.centerx - 43, self.rect.top)
bullet_2 = Bullets(self.rect.centerx + 43, self.rect.top)
#bullet = Bullets(self.rect.centerx, self.rect.top)
bullet_group.add(bullet_1)
bullet_group.add(bullet_2)
self.last_shot = time_now
#update mask
self.mask = pygame.mask.from_surface(self.image)
#draw health bar
pygame.draw.rect(screen, red, (self.rect.x, (self.rect.bottom + 10), self.rect.width, 15))
if self.health_remaining > 0:
pygame.draw.rect(screen, green, (self.rect.x, (self.rect.bottom + 10), int(self.rect.width * (self.health_remaining / self.health_start)), 15))
elif self.health_remaining <= 0:
explosion = Explosion(self.rect.centerx, self.rect.centery, 3)
explosion_group.add(explosion)
self.kill()
game_over = -1
return game_over
Posts: 148
Threads: 34
Joined: May 2020
May-13-2024, 07:03 PM
(This post was last modified: May-18-2024, 07:49 PM by Gribouillis.)
Hello, dear experienced programmers,
I need some help with a game I'm trying to program.
I know it will take a lot of effort for someone who wants to help me to look at the problem. Since I've tried hard myself but unfortunately can't get any further, I would really appreciate some help.
I hope not to upset anyone by asking for help with this fairly large problem.
I want to give the game to a friend (who isn't into programming forums at all, so he won't discover it).
The original code can be found online here (I used this as a basis and expanded it): Link Removed
To make debugging (and testing the different levels) easier, I temporarily reduced the number of aliens.
The game should get a little faster with each level. I also want to deviate from the normal space invaders idea every few levels and destroy the aliens within a breakout level. After this breakout level you should switch back to normal space invaders.
I've already partially managed that, but it doesn't quite work yet.
The first problem is:
I would like to implement mouse control, which has already worked well (lines 660 - 666).
In lines 127 - 130 I try to control the paddle. I'm having problems with xpos and paddle.move(event.pos[0]) on line 663.
event.pos[0] is the x position of the mouse.
Actually, I just want to pass event.pos[0] to the paddle.move() function.
In line 520 I have to set a value for xpos, but I don't know how, because it isn't in the event loop (line 663).
When the mouse control works again, you will face the second problem:
I have completed the first space invaders level and the program switches to the breakout level, which works fine.
Now comes the second problem:
Switching back to the space invaders level doesn't work, the program freezes when you start the breakout level (it's the third level).
Many thanks for the help!!
import os
import pygame
from PIL import Image
from pygame import mixer
from pygame.locals import *
import random, math
from itertools import product
################ breakout things #####################################################################################
TEXT_COLOR = (255, 255, 255)
FOREGROUND = (0, 0, 0) # Recolor image pixels that are this color
TRANSPARENT = (255, 255, 255) # Make image pixels this color transparent
BALL_COLOR = (255, 255, 255)
PADDLE_COLOR = (255, 255, 255)
BALL_IMAGE = "ball.png"
PADDLE_IMAGE = "paddle.png"
def create_image(file, color=None):
"""
Create image from a file. If color is specified, replace all FOREGROUND
pixels with color pixels. Modify image so TRANSPARENT colored pixels are
transparent.
"""
if color:
# Recolor the image
image = Image.open(file).convert("RGB")
for xy in product(range(image.width), range(image.height)):
if image.getpixel(xy) == FOREGROUND:
image.putpixel(xy, color)
image = pygame.image.fromstring(image.tobytes(), image.size, "RGB")
else:
image = pygame.image.load(file)
image.set_colorkey(TRANSPARENT)
return image.convert()
class EnhancedSprite(pygame.sprite.Sprite):
def __init__(self, image, group=None, **kwargs):
super().__init__(**kwargs)
self.image = image
self.rect = image.get_rect()
if group is not None:
group.add(self)
def at(self, x, y):
"""Convenience method for setting my position"""
self.x = x
self.y = y
return self
# Properties below expose properties of my rectangle so you can use
# self.x = 10 or self.centery = 30 instead of self.rect.x = 10
@property
def x(self):
return self.rect.x
@x.setter
def x(self, value):
self.rect.x = value
@property
def y(self):
return self.rect.y
@y.setter
def y(self, value):
self.rect.y = value
@property
def centerx(self):
return self.rect.centerx
@centerx.setter
def centerx(self, value):
self.rect.centerx = value
@property
def centery(self):
return self.rect.centery
@centery.setter
def centery(self, value):
self.rect.centery = value
@property
def right(self):
return self.rect.right
@right.setter
def right(self, value):
self.rect.right = value
@property
def bottom(self):
return self.rect.bottom
@bottom.setter
def bottom(self, value):
self.rect.bottom = value
@property
def width(self):
return self.rect.width
@property
def height(self):
return self.rect.height
class Paddle(EnhancedSprite):
"""The sprite the player moves around to redirect the ball"""
group = pygame.sprite.Group()
def __init__(self, x, y, health, xpos):
super().__init__(create_image(PADDLE_IMAGE, PADDLE_COLOR), self.group)
self.x = x
self.y = y
self.health_start = health
self.health_remaining = health
self.image = pygame.image.load("paddle.png")
self.rect = self.image.get_rect()
self.rect.center = x, y
self.xmin = self.rect.width // 2 # Compute Spaceship x range.
self.xmax = screen_width - self.xmin
self.xpos = xpos
self.last_shot = pygame.time.get_ticks()
def move(self, xpos):
self.xpos = xpos
"""Move to follow the cursor. Clamp to window bounds"""
self.rect.centerx = max(self.xmin, min(self.xmax, xpos))
class LifeCounter():
"""Keep track of lives count. Display lives remaining using ball image"""
def __init__(self, x, y, count=5):
self.x, self.y = x, y
self.image = create_image(BALL_IMAGE, BALL_COLOR)
self.spacing = self.image.get_width() + 5
self.group = pygame.sprite.Group()
self.reset(count)
def reset(self, count):
"""Reset number of lives"""
self.count = count
for c in range(count - 1):
EnhancedSprite(self.image, self.group).at(self.x + c * self.spacing, self.y)
def __len__(self):
"""Return number of lives remaining"""
return self.count
def kill(self):
"""Reduce number of lives"""
if self.count > 1:
self.group.sprites()[-1].kill()
self.count = max(0, self.count - 1)
class Ball(EnhancedSprite):
"""Ball bounces around colliding with walls, paddles and bricks"""
group = pygame.sprite.Group()
def __init__(self, paddle, lives, speed=5):
super().__init__(create_image(BALL_IMAGE, BALL_COLOR), self.group)
self.paddle = paddle
self.lives = lives
self.speed = speed
self.dx = self.dy = 0
self.xfloat = self.yfloat = 0
self.xmax = screen_width - self.rect.width
self.ymax = paddle.bottom - self.rect.height
self.reset(0)
def at(self, x, y):
self.xfloat = x
self.yfloat = y
return super().at(x, y)
def reset(self, score=None):
"""Reset for a new game"""
self.active = False
if score is not None:
self.score = score
def start(self):
"""Start moving the ball in a random direction"""
angle = random.random() - 0.5 # Launch angle limited to about +/-60 degrees
self.dx = self.speed * math.sin(angle)
self.dy = -self.speed * math.cos(angle)
self.active = True
def move(self):
"""Update the ball position. Check for collisions with bricks, walls and the paddle"""
hit_status = 0
if not self.active:
# Sit on top of the paddle
self.at(self.paddle.centerx - self.width // 2, self.paddle.y - self.height - 2)
return self
# Did I hit some bricks? Update the bricks and the score
x1, y1 = self.xfloat, self.yfloat
x2, y2 = x1 + self.dx, y1 + self.dy
if (xhits := pygame.sprite.spritecollide(self.at(x2, y1), alien_group, True, pygame.sprite.collide_mask)):
self.dx = -self.dx
hit_status += 1
if (yhits := pygame.sprite.spritecollide(self.at(x1, y2), alien_group, True, pygame.sprite.collide_mask)):
self.dy = -self.dy
hit_status += 2
#hits = pygame.sprite.spritecollide(self, alien_group, True, pygame.sprite.collide_mask)
if xhits or yhits:
for alien in xhits or yhits:
x, y = alien.hit()
# explosion_fx.play()
explosion = Explosion(x, y, 2)
explosion_group.add(explosion)
# if (hits := set(xhits) or set(yhits)):
# for alien in hits:
# self.score += alien.hit()
# Did I hit a wall?
if x2 <= 0 or x2 >= self.xmax:
self.dx = -self.dx
hit_status += 4
if y2 <= 0:
self.dy = abs(self.dy)
hit_status += 8
# Did I get past the paddle?
if (y2 >= self.paddle.y) and ((self.x > self.paddle.right) or (self.right < self.paddle.x)):
self.lives.kill()
self.active = False
elif self.dy > 0 and pygame.Rect.colliderect(self.at(x2, y2).rect, self.paddle.rect):
# I hit the paddle. Compute angle of reflection
bangle = math.atan2(-self.dx, self.dy) # Ball angle of approach
pangle = math.atan2(self.centerx - self.paddle.centerx, 30) # Paddle angle
rangle = (pangle - bangle) / 2 # Angle of reflection
self.dx = math.sin(rangle) * self.speed
self.dy = -math.cos(rangle) * self.speed
hit_status += 16
if hit_status > 0:
self.at(x1, y1)
else:
self.at(x2, y2)
######################################################################################################################
pygame.mixer.pre_init(44100, -16, 2, 512)
mixer.init()
pygame.init()
# define fps
clock = pygame.time.Clock()
fps = 60
screen_width = 1280
screen_height = 720
screen = pygame.display.set_mode((screen_width, screen_height))
################ space invaders things ###############################################################################
pygame.display.set_caption('Space Invanders')
# define fonts
font30 = pygame.font.SysFont('Constantia', 30)
font40 = pygame.font.SysFont('Constantia', 40)
# define game variables
# breakout level
list_of_breakout_levels = [2, 4, 6, 8]
# list_of_space_invaders_levels = [1, 3, 5, 7]
# rows = 4
# cols = 10
rows = 1
cols = 4
level = 1
move_direction = 1
alien_cooldown = 1000 # bullet cooldown in milliseconds
last_alien_shot = pygame.time.get_ticks()
countdown = 3
last_count = pygame.time.get_ticks()
game_over = 0 # 0 is no game over, 1 means player has won, -1 means player has lost
# define colours
red = (255, 0, 0)
green = (0, 255, 0)
white = (255, 255, 255)
# load image
bg = pygame.image.load("bg.png")
screen_rect = bg.get_rect()
def draw_bg():
screen.blit(bg, (0, 0))
# define function for creating text
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
screen.blit(img, (x, y))
# create spaceship class
class Spaceship(pygame.sprite.Sprite):
def __init__(self, x, y, health):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.health_start = health
self.health_remaining = health
self.image = pygame.image.load("ship.png")
self.rect = self.image.get_rect()
self.rect.center = x, y
self.xmin = self.rect.width // 2 # Compute Spaceship x range.
self.xmax = screen_width - self.xmin
self.last_shot = pygame.time.get_ticks()
def move(self, xpos):
self.xpos = xpos
self.rect.centerx = max(self.xmin, min(self.xmax, xpos))
def update(self):
# set a cooldown variable
cooldown = 500 # milliseconds
game_over = 0
# record current time
time_now = pygame.time.get_ticks()
# shoot, get key press
key = pygame.key.get_pressed()
if key[pygame.K_SPACE] and time_now - self.last_shot > cooldown:
# single bullet
single_bullet = SingleBullets(self.rect.centerx, self.rect.top)
single_bullet_group.add(single_bullet)
self.last_shot = time_now
# for later use (double bullets)
# bullet_1 = Bullets(self.rect.centerx - 43, self.rect.top)
# bullet_2 = Bullets(self.rect.centerx + 43, self.rect.top)
# update mask
self.mask = pygame.mask.from_surface(self.image)
# draw health bar
pygame.draw.rect(screen, red, (self.rect.x, (self.rect.bottom + 10), self.rect.width, 15))
if self.health_remaining > 0:
pygame.draw.rect(screen, green, (
self.rect.x, (self.rect.bottom + 10), int(self.rect.width * (self.health_remaining / self.health_start)),
15))
elif self.health_remaining <= 0:
explosion = Explosion(self.rect.centerx, self.rect.centery, 3)
explosion_group.add(explosion)
self.kill()
game_over = -1
return game_over
# create SingleBullets class
class SingleBullets(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
weapon_list = ["bullet.png", "flash.png", "rocket.png"]
self.chosen = random.choice(weapon_list)
self.image = pygame.image.load(self.chosen)
self.rect = self.image.get_rect()
self.rect.center = x, y
def update(self):
self.rect.y -= 5
if self.rect.bottom < 0:
self.kill()
hits = pygame.sprite.spritecollide(self, alien_group, True, pygame.sprite.collide_mask)
if hits:
self.kill()
for alien in hits:
x, y = alien.hit()
if self.chosen == "rocket.png":
explosion = Explosion(x, y, 4)
else:
explosion = Explosion(x, y, 2)
explosion_group.add(explosion)
# create RocketExplosion class
# for hits between aliens and rocket explosion
class RocketExplosion(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("explosion7.png")
self.rect = self.image.get_rect()
self.rect.center = x, y
def check(self, x, y):
hits_rocket_expl_and_alien_group = pygame.sprite.spritecollide(self, alien_group, False,
pygame.sprite.collide_mask)
if hits_rocket_expl_and_alien_group:
for alien in hits_rocket_expl_and_alien_group:
x, y = alien.hit()
# explosion_fx.play()
explosion = Explosion(x, y, 2)
explosion_group.add(explosion)
# create Aliens class
class Aliens(pygame.sprite.Sprite):
def __init__(self, x, y, move_direction):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("alien" + str(random.randint(1, 6)) + ".png")
self.x = x
self.y = y
self.move_direction = move_direction
self.rect = self.image.get_rect()
self.rect.center = x, y
def hit(self):
x = self.rect.centerx
y = self.rect.centery
self.kill()
return x, y
def update(self, move_direction):
self.rect.x += self.move_direction
if self.rect.right >= screen_width or self.rect.left <= 0:
self.move_direction = -self.move_direction
# update mask
self.mask = pygame.mask.from_surface(self.image)
# create Alien Bullets class
class Alien_Bullets(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("alien_bullet.png")
self.rect = self.image.get_rect()
self.rect.center = x, y
def update(self):
self.rect.y += 2
if self.rect.top > screen_height:
self.kill()
if pygame.sprite.spritecollide(self, spaceship_group, False, pygame.sprite.collide_mask):
self.kill()
# explosion2_fx.play()
# reduce spaceship health
spaceship.health_remaining -= 1
explosion = Explosion(self.rect.centerx, self.rect.centery, 1)
explosion_group.add(explosion)
# create Explosion class
class Explosion(pygame.sprite.Sprite):
def __init__(self, x, y, size):
pygame.sprite.Sprite.__init__(self)
self.images = []
for num in range(1, 8):
img = pygame.image.load(f"explosion{num}.png")
# ship is hit
if size == 1:
img = pygame.transform.scale(img, (20, 20))
# alien is hit
if size == 2:
img = pygame.transform.scale(img, (100, 100))
# ship gameover
if size == 3:
img = pygame.transform.scale(img, (160, 160))
# rocket hits alien
if size == 4:
if num == 7:
img = pygame.transform.scale(img, (500, 500))
rocket_Expl = RocketExplosion(x, y)
rocket_Expl.check(x, y)
# add the image to the list
self.images.append(img)
self.index = 0
self.image = self.images[self.index]
self.rect = self.image.get_rect()
self.rect.center = x, y
self.counter = 0
def update(self):
explosion_speed = 3
# update explosion animation
self.counter += 1
if self.counter >= explosion_speed and self.index < len(self.images) - 1:
self.counter = 0
self.index += 1
self.image = self.images[self.index]
# if the animation is complete, delete explosion
if self.index >= len(self.images) - 1 and self.counter >= explosion_speed:
self.kill()
# create sprite groups
spaceship_group = pygame.sprite.Group()
paddle_group = pygame.sprite.Group()
ball_group = pygame.sprite.Group()
single_bullet_group = pygame.sprite.Group()
flash_group = pygame.sprite.Group()
alien_group = pygame.sprite.Group()
alien_bullet_group = pygame.sprite.Group()
explosion_group = pygame.sprite.Group()
rocket_explosion_group = pygame.sprite.Group()
def create_aliens():
# generate aliens
for row in range(rows):
for item in range(cols):
alien = Aliens(100 + item * 100, 100 + row * 100, move_direction)
alien_group.add(alien)
# create player
spaceship = Spaceship(screen_width / 2, screen_height - 100, 3)
spaceship_group.add(spaceship)
paddle = Paddle(screen_width / 2, screen_height - 100, 3)
paddle_group.add(paddle)
lives = LifeCounter(10, screen_height - 30)
ball = Ball(paddle, lives)
ball_group.add(ball)
create_aliens()
run = True
while run:
clock.tick(fps)
# draw background
draw_bg()
if level <= 10:
if level in list_of_breakout_levels:
# breakout level
if countdown == 0:
# create random alien bullets
# record current time
time_now = pygame.time.get_ticks()
# in breakout levels aliens shouldn't shoot
# if time_now - last_alien_shot > alien_cooldown and len(alien_bullet_group) < 5 and len(
# alien_group) > 0:
# attacking_alien = random.choice(alien_group.sprites())
# alien_bullet = Alien_Bullets(attacking_alien.rect.centerx, attacking_alien.rect.bottom)
# alien_bullet_group.add(alien_bullet)
# last_alien_shot = time_now
# check if all the aliens have been killed
if len(alien_group) == 0:
game_over = 1
level += 1
countdown = 3
ball.kill()
paddle.kill()
create_aliens()
move_direction *= 1.25
game_over = 0
if game_over == 0:
# update paddle
game_over = paddle.move(xpos)
# update sprite groups
alien_group.update(move_direction)
else:
if game_over == -1:
draw_text('GAME OVER!', font40, white, int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if game_over == 1:
draw_text('YOU WIN!', font40, white, int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if countdown > 0:
draw_text('GET READY!', font40, white, int(screen_width / 2 - 110), int(screen_height / 2 + 50))
draw_text(str(countdown), font40, white, int(screen_width / 2 - 10), int(screen_height / 2 + 100))
count_timer = pygame.time.get_ticks()
if count_timer - last_count > 1000:
countdown -= 1
last_count = count_timer
# update explosion group
alien_group.update(move_direction)
explosion_group.update()
paddle_group.update()
ball_group.update()
# draw sprite groups
alien_group.draw(screen)
explosion_group.draw(screen)
paddle_group.draw(screen)
ball_group.draw(screen)
else:
# space invaders single bullets level
if countdown == 0:
# create random alien bullets
# record current time
time_now = pygame.time.get_ticks()
# shoot
if time_now - last_alien_shot > alien_cooldown and len(alien_bullet_group) < 5 and len(
alien_group) > 0:
attacking_alien = random.choice(alien_group.sprites())
alien_bullet = Alien_Bullets(attacking_alien.rect.centerx, attacking_alien.rect.bottom)
alien_bullet_group.add(alien_bullet)
last_alien_shot = time_now
# check if all the aliens have been killed
if len(alien_group) == 0:
game_over = 1
level += 1
countdown = 3
create_aliens()
move_direction *= 1.25
game_over = 0
if game_over == 0:
# update spaceship
game_over = spaceship.update()
# update sprite groups
single_bullet_group.update()
alien_group.update(move_direction)
alien_bullet_group.update()
explosion_group.update()
else:
if game_over == -1:
draw_text('GAME OVER!', font40, white, int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if game_over == 1:
draw_text('YOU WIN!', font40, white, int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if countdown > 0:
draw_text('GET READY!', font40, white, int(screen_width / 2 - 110), int(screen_height / 2 + 50))
draw_text(str(countdown), font40, white, int(screen_width / 2 - 10), int(screen_height / 2 + 100))
count_timer = pygame.time.get_ticks()
if count_timer - last_count > 1000:
countdown -= 1
last_count = count_timer
# update explosion group
explosion_group.update()
rocket_explosion_group.update()
# draw sprite groups
spaceship_group.draw(screen)
single_bullet_group.draw(screen)
alien_group.draw(screen)
alien_bullet_group.draw(screen)
explosion_group.draw(screen)
rocket_explosion_group.draw(screen)
else:
if level in list_of_breakout_levels:
pass
# breakout level
else:
pass
# space invaders double bullets levvel
# event handlers
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEMOTION:
if level in list_of_breakout_levels:
# breakout level
paddle.move(event.pos[0])
else:
# space invaders level
spaceship.move(event.pos[0])
elif event.type == pygame.MOUSEBUTTONUP:
if not ball.active:
ball.start()
ball.move()
pygame.display.flip()
pygame.quit()
Posts: 6,798
Threads: 20
Joined: Feb 2020
Quote:Actually, I just want to pass paddle.pos[0] to paddle.move().
How about pass spaceship.xpos as the starting position for paddel when you change into the breakout game and paddle.xpos to spaceship.move when transitioning back to space invaders mode.
When you switch back from breakout to space invadors you don't properly initialize space invaders. The code in lines 531 to 540 has to execute each time you start a new space invaders game.
I think your code would be easier to work with if you wrote a function to play space invaders and another to play breakout. Mixing the two as you have makes everything a mess.
Posts: 148
Threads: 34
Joined: May 2020
Hi,
thanks a lot for answering!
I will try to organize the code, as you mentioned.
It will take some time...
Greetings,
flash77
Posts: 148
Threads: 34
Joined: May 2020
May-20-2024, 08:29 AM
(This post was last modified: May-20-2024, 06:25 PM by flash77.)
Hi,
I got the 2 game functions (play_space_invaders() and play_breakout()) working...
It would be great, if someone could have a look, if I did everything right...
I got an problem with "move_direction":
It stays not constant within a level. It works only in one direction, turning around at the window's edge, the old speed is used.
Should I use in general an acceleration each level - wouldn't it lead to a slow-down of the gameplay?
Thanks for your help!!!
import os
import pygame
from PIL import Image
from pygame import mixer
from pygame.locals import *
import random, math
from itertools import product
pygame.mixer.pre_init(44100, -16, 2, 512)
mixer.init()
pygame.init()
# define fps
clock = pygame.time.Clock()
fps = 60
screen_width = 1280
screen_height = 720
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Space Invanders')
# define fonts
font30 = pygame.font.SysFont('Constantia', 30)
font40 = pygame.font.SysFont('Constantia', 40)
alien_cooldown = 1000 # bullet cooldown in milliseconds
last_count = pygame.time.get_ticks()
last_alien_shot = pygame.time.get_ticks()
# define colours
red = (255, 0, 0)
green = (0, 255, 0)
white = (255, 255, 255)
# load image
bg = pygame.image.load("bg.png")
screen_rect = bg.get_rect()
def draw_bg():
screen.blit(bg, (0, 0))
# define function for creating text
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
screen.blit(img, (x, y))
################ space invaders things ###############################################################################
# create spaceship class
class Spaceship(pygame.sprite.Sprite):
def __init__(self, x, y, health):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.health_start = health
self.health_remaining = health
self.image = pygame.image.load("ship.png")
self.rect = self.image.get_rect()
self.rect.center = x, y
self.xmin = self.rect.width // 2 # Compute Spaceship x range.
self.xmax = screen_width - self.xmin
self.last_shot = pygame.time.get_ticks()
def move(self, xpos):
self.xpos = xpos
self.rect.centerx = max(self.xmin, min(self.xmax, xpos))
def update(self):
# set a cooldown variable
cooldown = 500 # milliseconds
game_over = 0
# record current time
time_now = pygame.time.get_ticks()
# shoot, get key press
key = pygame.key.get_pressed()
if key[pygame.K_SPACE] and time_now - self.last_shot > cooldown:
# single bullet
single_bullet = SingleBullets(self.rect.centerx, self.rect.top)
single_bullet_group.add(single_bullet)
self.last_shot = time_now
# for later use (double bullets)
# bullet_1 = Bullets(self.rect.centerx - 43, self.rect.top)
# bullet_2 = Bullets(self.rect.centerx + 43, self.rect.top)
# update mask
self.mask = pygame.mask.from_surface(self.image)
# draw health bar
pygame.draw.rect(screen, red, (self.rect.x, (self.rect.bottom + 10), self.rect.width, 15))
if self.health_remaining > 0:
pygame.draw.rect(screen, green, (
self.rect.x, (self.rect.bottom + 10), int(self.rect.width * (self.health_remaining / self.health_start)),
15))
elif self.health_remaining <= 0:
explosion = Explosion(self.rect.centerx, self.rect.centery, 3)
explosion_group.add(explosion)
self.kill()
game_over = -1
return game_over
# create player
spaceship = Spaceship(screen_width / 2, screen_height - 100, 3)
# create SingleBullets class
class SingleBullets(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
weapon_list = ["bullet.png", "flash.png", "rocket.png"]
self.chosen = random.choice(weapon_list)
self.image = pygame.image.load(self.chosen)
self.rect = self.image.get_rect()
self.rect.center = x, y
def update(self):
self.rect.y -= 5
if self.rect.bottom < 0:
self.kill()
hits = pygame.sprite.spritecollide(self, alien_group, True, pygame.sprite.collide_mask)
if hits:
self.kill()
for alien in hits:
x, y = alien.hit()
if self.chosen == "rocket.png":
explosion = Explosion(x, y, 4)
else:
explosion = Explosion(x, y, 2)
explosion_group.add(explosion)
# create RocketExplosion class
# for hits between aliens and rocket explosion
class RocketExplosion(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("explosion7.png")
self.rect = self.image.get_rect()
self.rect.center = x, y
def check(self, x, y):
hits_rocket_expl_and_alien_group = pygame.sprite.spritecollide(self, alien_group, False,
pygame.sprite.collide_mask)
if hits_rocket_expl_and_alien_group:
for alien in hits_rocket_expl_and_alien_group:
x, y = alien.hit()
# explosion_fx.play()
explosion = Explosion(x, y, 2)
explosion_group.add(explosion)
# create Aliens class
class Aliens(pygame.sprite.Sprite):
def __init__(self, x, y, move_direction):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("alien" + str(random.randint(1, 6)) + ".png")
self.x = x
self.y = y
self.move_direction = move_direction
self.rect = self.image.get_rect()
self.rect.center = x, y
def hit(self):
x = self.rect.centerx
y = self.rect.centery
self.kill()
return x, y
def update(self, move_direction):
self.rect.x += self.move_direction
if self.rect.right >= screen_width or self.rect.left <= 0:
self.move_direction = -self.move_direction
# update mask
self.mask = pygame.mask.from_surface(self.image)
# create Alien Bullets class
class Alien_Bullets(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("alien_bullet.png")
self.rect = self.image.get_rect()
self.rect.center = x, y
def update(self):
self.rect.y += 2
if self.rect.top > screen_height:
self.kill()
if pygame.sprite.spritecollide(self, spaceship_group, False, pygame.sprite.collide_mask):
self.kill()
# explosion2_fx.play()
# reduce spaceship health
spaceship.health_remaining -= 1
explosion = Explosion(self.rect.centerx, self.rect.centery, 1)
explosion_group.add(explosion)
# create Explosion class
class Explosion(pygame.sprite.Sprite):
def __init__(self, x, y, size):
pygame.sprite.Sprite.__init__(self)
self.images = []
for num in range(1, 8):
img = pygame.image.load(f"explosion{num}.png")
# ship is hit
if size == 1:
img = pygame.transform.scale(img, (20, 20))
# alien is hit
if size == 2:
img = pygame.transform.scale(img, (100, 100))
# ship gameover
if size == 3:
img = pygame.transform.scale(img, (160, 160))
# rocket hits alien
if size == 4:
if num == 7:
img = pygame.transform.scale(img, (500, 500))
rocket_Expl = RocketExplosion(x, y)
rocket_Expl.check(x, y)
# add the image to the list
self.images.append(img)
self.index = 0
self.image = self.images[self.index]
self.rect = self.image.get_rect()
self.rect.center = x, y
self.counter = 0
def update(self):
explosion_speed = 3
# update explosion animation
self.counter += 1
if self.counter >= explosion_speed and self.index < len(self.images) - 1:
self.counter = 0
self.index += 1
self.image = self.images[self.index]
# if the animation is complete, delete explosion
if self.index >= len(self.images) - 1 and self.counter >= explosion_speed:
self.kill()
# create sprite groups
spaceship_group = pygame.sprite.Group()
spaceship_group.add(spaceship)
paddle_group = pygame.sprite.Group()
ball_group = pygame.sprite.Group()
single_bullet_group = pygame.sprite.Group()
flash_group = pygame.sprite.Group()
alien_group = pygame.sprite.Group()
alien_bullet_group = pygame.sprite.Group()
explosion_group = pygame.sprite.Group()
rocket_explosion_group = pygame.sprite.Group()
lives_group = pygame.sprite.Group()
def create_aliens(rows, cols, move_direction):
# generate aliens
for row in range(rows):
for item in range(cols):
alien = Aliens(100 + item * 100, 100 + row * 100, move_direction)
alien_group.add(alien)
def play_space_invaders(level, move_direction):
game_over = 0
create_aliens(1, 4, move_direction)
last_count = pygame.time.get_ticks()
last_alien_shot = pygame.time.get_ticks()
countdown = 3
run = True
while run:
clock.tick(fps)
# draw background
draw_bg()
# space invaders single bullets level
if countdown == 0:
# create random alien bullets
# record current time
time_now = pygame.time.get_ticks()
# shoot
if time_now - last_alien_shot > alien_cooldown and len(alien_bullet_group) < 5 and len(
alien_group) > 0:
attacking_alien = random.choice(alien_group.sprites())
alien_bullet = Alien_Bullets(attacking_alien.rect.centerx, attacking_alien.rect.bottom)
alien_bullet_group.add(alien_bullet)
last_alien_shot = time_now
# check if all the aliens have been killed
if len(alien_group) == 0:
game_over = 1
level += 1
move_direction *= 1.25
return level, move_direction
if game_over == 0:
# update spaceship
game_over = spaceship.update()
# update sprite groups
single_bullet_group.update()
alien_group.update(move_direction)
alien_bullet_group.update()
explosion_group.update()
else:
if game_over == -1:
draw_text('GAME OVER!', font40, white, int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if game_over == 1:
draw_text('YOU WIN!', font40, white, int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if countdown > 0:
draw_text('GET READY!', font40, white, int(screen_width / 2 - 110), int(screen_height / 2 + 50))
draw_text(str(countdown), font40, white, int(screen_width / 2 - 10), int(screen_height / 2 + 100))
count_timer = pygame.time.get_ticks()
if count_timer - last_count > 1000:
countdown -= 1
last_count = count_timer
# update explosion group
explosion_group.update()
rocket_explosion_group.update()
# draw sprite groups
spaceship_group.draw(screen)
single_bullet_group.draw(screen)
alien_group.draw(screen)
alien_bullet_group.draw(screen)
explosion_group.draw(screen)
rocket_explosion_group.draw(screen)
# event handlers
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEMOTION:
# space invaders level
spaceship.move(event.pos[0])
pygame.display.flip()
pygame.quit()
# breakout things #############################################################
TEXT_COLOR = (255, 255, 255)
FOREGROUND = (0, 0, 0) # Recolor image pixels that are this color
TRANSPARENT = (255, 255, 255) # Make image pixels this color transparent
BALL_COLOR = (255, 255, 255)
PADDLE_COLOR = (255, 255, 255)
BALL_IMAGE = "ball.png"
PADDLE_IMAGE = "paddle.png"
def create_image(file, color=None):
"""
Create image from a file. If color is specified, replace all FOREGROUND
pixels with color pixels. Modify image so TRANSPARENT colored pixels are
transparent.
"""
if color:
# Recolor the image
image = Image.open(file).convert("RGB")
for xy in product(range(image.width), range(image.height)):
if image.getpixel(xy) == FOREGROUND:
image.putpixel(xy, color)
image = pygame.image.fromstring(image.tobytes(), image.size, "RGB")
else:
image = pygame.image.load(file)
image.set_colorkey(TRANSPARENT)
return image.convert()
class EnhancedSprite(pygame.sprite.Sprite):
def __init__(self, image, group=None, **kwargs):
super().__init__(**kwargs)
self.image = image
self.rect = image.get_rect()
if group is not None:
group.add(self)
def at(self, x, y):
"""Convenience method for setting my position"""
self.x = x
self.y = y
return self
# Properties below expose properties of my rectangle so you can use
# self.x = 10 or self.centery = 30 instead of self.rect.x = 10
@property
def x(self):
return self.rect.x
@x.setter
def x(self, value):
self.rect.x = value
@property
def y(self):
return self.rect.y
@y.setter
def y(self, value):
self.rect.y = value
@property
def centerx(self):
return self.rect.centerx
@centerx.setter
def centerx(self, value):
self.rect.centerx = value
@property
def centery(self):
return self.rect.centery
@centery.setter
def centery(self, value):
self.rect.centery = value
@property
def right(self):
return self.rect.right
@right.setter
def right(self, value):
self.rect.right = value
@property
def bottom(self):
return self.rect.bottom
@bottom.setter
def bottom(self, value):
self.rect.bottom = value
@property
def width(self):
return self.rect.width
@property
def height(self):
return self.rect.height
class Paddle(EnhancedSprite):
"""The sprite the player moves around to redirect the ball"""
group = pygame.sprite.Group()
def __init__(self, x, y, health):
super().__init__(create_image(PADDLE_IMAGE, PADDLE_COLOR), self.group)
self.x = x
self.y = y
self.health_start = health
self.health_remaining = health
self.image = pygame.image.load("paddle.png")
self.rect = self.image.get_rect()
self.rect.center = x, y
self.xmin = self.rect.width // 2 # Compute Spaceship x range.
self.xmax = screen_width - self.xmin
self.last_shot = pygame.time.get_ticks()
def move(self, xpos):
"""Move to follow the cursor. Clamp to window bounds"""
self.rect.centerx = max(self.xmin, min(self.xmax, xpos))
class LifeCounter():
"""Keep track of lives count. Display lives remaining using ball image"""
def __init__(self, x, y, count=5):
self.x, self.y = x, y
self.image = create_image(BALL_IMAGE, BALL_COLOR)
self.spacing = self.image.get_width() + 5
self.group = pygame.sprite.Group()
self.reset(count)
def reset(self, count):
"""Reset number of lives"""
self.count = count
for c in range(count - 1):
EnhancedSprite(self.image, self.group).at(self.x + c * self.spacing, self.y)
def __len__(self):
"""Return number of lives remaining"""
return self.count
def kill(self):
"""Reduce number of lives"""
if self.count > 1:
self.group.sprites()[-1].kill()
self.count = max(0, self.count - 1)
class Ball(EnhancedSprite):
"""Ball bounces around colliding with walls, paddles and bricks"""
group = pygame.sprite.Group()
def __init__(self, paddle, lives, speed=5):
super().__init__(create_image(BALL_IMAGE, BALL_COLOR), self.group)
self.paddle = paddle
self.lives = lives
self.speed = speed
self.dx = self.dy = 0
self.xfloat = self.yfloat = 0
self.xmax = screen_width - self.rect.width
self.ymax = paddle.bottom - self.rect.height
self.reset(0)
def at(self, x, y):
self.xfloat = x
self.yfloat = y
return super().at(x, y)
def reset(self, score=None):
"""Reset for a new game"""
self.active = False
if score is not None:
self.score = score
def start(self):
"""Start moving the ball in a random direction"""
angle = random.random() - 0.5 # Launch angle limited to about +/-60 degrees
self.dx = self.speed * math.sin(angle)
self.dy = -self.speed * math.cos(angle)
self.active = True
def move(self):
"""Update the ball position. Check for collisions with bricks, walls and the paddle"""
hit_status = 0
if not self.active:
# Sit on top of the paddle
self.at(self.paddle.centerx - self.width // 2, self.paddle.y - self.height - 2)
return self
# Did I hit some bricks? Update the bricks and the score
x1, y1 = self.xfloat, self.yfloat
x2, y2 = x1 + self.dx, y1 + self.dy
if (xhits := pygame.sprite.spritecollide(self.at(x2, y1), alien_group, True, pygame.sprite.collide_mask)):
self.dx = -self.dx
hit_status += 1
if (yhits := pygame.sprite.spritecollide(self.at(x1, y2), alien_group, True, pygame.sprite.collide_mask)):
self.dy = -self.dy
hit_status += 2
# hits = pygame.sprite.spritecollide(self, alien_group, True, pygame.sprite.collide_mask)
if xhits or yhits:
for alien in xhits or yhits:
x, y = alien.hit()
# explosion_fx.play()
explosion = Explosion(x, y, 2)
explosion_group.add(explosion)
# if (hits := set(xhits) or set(yhits)):
# for alien in hits:
# self.score += alien.hit()
# Did I hit a wall?
if x2 <= 0 or x2 >= self.xmax:
self.dx = -self.dx
hit_status += 4
if y2 <= 0:
self.dy = abs(self.dy)
hit_status += 8
# Did I get past the paddle?
if (y2 >= self.paddle.y) and ((self.x > self.paddle.right) or (self.right < self.paddle.x)):
self.lives.kill()
self.active = False
elif self.dy > 0 and pygame.Rect.colliderect(self.at(x2, y2).rect, self.paddle.rect):
# I hit the paddle. Compute angle of reflection
bangle = math.atan2(-self.dx, self.dy) # Ball angle of approach
pangle = math.atan2(self.centerx - self.paddle.centerx, 30) # Paddle angle
rangle = (pangle - bangle) / 2 # Angle of reflection
self.dx = math.sin(rangle) * self.speed
self.dy = -math.cos(rangle) * self.speed
hit_status += 16
if hit_status > 0:
self.at(x1, y1)
else:
self.at(x2, y2)
def play_breakout(level, move_direction):
game_over = 0
paddle = Paddle(screen_width / 2, screen_height - 100, 3)
paddle_group.add(paddle)
lives = LifeCounter(10, screen_height - 30)
ball = Ball(paddle, lives)
ball_group.add(ball)
create_aliens(1, 4, move_direction)
last_count = pygame.time.get_ticks()
last_alien_shot = pygame.time.get_ticks()
countdown = 3
run = True
while run:
clock.tick(fps)
# draw background
draw_bg()
# breakout level
if countdown == 0:
# create random alien bullets
# record current time
time_now = pygame.time.get_ticks()
# in breakout levels aliens shouldn't shoot
# check if all the aliens have been killed
if len(alien_group) == 0:
paddle.kill()
ball.kill()
game_over = 1
level += 1
move_direction *= 1.25
return level, move_direction
if game_over == 0:
# update paddle
game_over = paddle.move(event.pos[0])
# update sprite groups
alien_group.update(move_direction)
else:
if game_over == -1:
draw_text('GAME OVER!', font40, white, int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if game_over == 1:
draw_text('YOU WIN!', font40, white, int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if countdown > 0:
draw_text('GET READY!', font40, white, int(screen_width / 2 - 110), int(screen_height / 2 + 50))
draw_text(str(countdown), font40, white, int(screen_width / 2 - 10), int(screen_height / 2 + 100))
count_timer = pygame.time.get_ticks()
if count_timer - last_count > 1000:
countdown -= 1
last_count = count_timer
# update explosion group
alien_group.update(move_direction)
explosion_group.update()
paddle_group.update()
ball_group.update()
# draw sprite groups
alien_group.draw(screen)
explosion_group.draw(screen)
paddle_group.draw(screen)
ball_group.draw(screen)
# event handlers
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEMOTION:
# breakout level
paddle.move(event.pos[0])
elif event.type == pygame.MOUSEBUTTONUP:
if not ball.active:
ball.start()
ball.move()
pygame.display.flip()
pygame.quit()
#game_over = 0 # 0 is no game over, 1 means player has won, -1 means player has lost
space_invaders_levels = [1, 3, 5]
breakout_levels = [2, 4]
level = 1
move_direction = 1
for i in range(1, 6):
if level not in breakout_levels:
level, move_direction = play_space_invaders(level, move_direction)
else:
level, move_direction = play_breakout(level, move_direction)
Posts: 48
Threads: 8
Joined: Jun 2022
I didn't find it on first look, but think if you find the spot in your code where they switch directions, you are always setting to the original move value and not the increased *1.25.
I usually switch directions by multiplying the value by -1.
|