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


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,918 Dec-17-2019, 03:40 AM
Last Post: detkitten
  Adding persistent multiple levels to game michael1789 2 2,430 Nov-16-2019, 01:15 AM
Last Post: michael1789
  Adding a single player mode to my wxOthello game keames 29 12,180 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