Python Forum
[PyGame] adding mouse control to game
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyGame] adding mouse control to game
#1
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()
Reply
#2
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
Reply
#3
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
Reply
#4
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): http://www.codingwithruss.com/gamepage/invaders/

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()
Reply
#5
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.
Reply
#6
Hi,
thanks a lot for answering!

I will try to organize the code, as you mentioned.

It will take some time...

Greetings,

flash77
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Adding an inventory and a combat system to a text based adventure game detkitten 2 6,965 Dec-17-2019, 03:40 AM
Last Post: detkitten
  Adding persistent multiple levels to game michael1789 2 2,462 Nov-16-2019, 01:15 AM
Last Post: michael1789
  Adding a single player mode to my wxOthello game keames 29 12,310 May-01-2019, 02:56 AM
Last Post: SheeppOSU

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020