I’m programming an endboss for my space invaders game.
I don’t provide the full code of my game, but just the part I’ve got problems with. (It would be to much content and it would be hard to orientate.)
So I post some dummy code to work with (I will implement the solved problem to the whole code later).
(The instantiation of the endboss laser is in line 166.)
In the class EndBossLaser:
with “def init” and “def rotate_laser_around_endboss_center” the laser is placed at the EndBossGun’s tip.
This works perfect. To check this, I commented out “def update” of the EndBossLaser class – everything works fine.
I’ve got problems with the “def update” of the EndBossLaser class.
When I don’t comment out “def update” of the EndBossLaser class the problems occurs.
In picture1 you can see that, if the player is right downwards of the endboss’s center, the laser comes correctely out of the endboss’s gun.
In picture2 you can see the problem:
There is an offset.
When the “def update” of the EndBossLaser class is commented out, the laser stays at the gun’s tip, no matter in which angle the gun is rotated, everything works fine.
When I don’t comment out “def update” of the EndBossLaser class, the part which moves the laser is active. The error must be in this function.
I don’t know how to correct this.
It would be great, if someone could tell me how to make it right!!
Thank you very much in advance!!
import pygame
from math import radians, sin, cos
import math
from pygame import Vector2
pygame.init()
screen_width = 800
screen_height = 600
fps = 60
end_boss_cooldown = 3000 # bullet cooldown in milliseconds
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("End Boss Example")
ship_image_path = "ship_4.png"
gun_image_path = "singleGun.png"
laser_image_path = "endboss_laser2.png"
end_boss_gun_length = 100
# how to entry
# pygame.transform.rotate(degrees)
# math.cos(radians)
class EndBossGun(pygame.sprite.Sprite):
def __init__(self, x, y, angle):
super().__init__()
self.x = x
self.y = y
self.angle = angle
self.image = pygame.image.load(gun_image_path)
self.gun_image = self.image.copy()
self.rect = self.gun_image.get_rect()
self.rect.center = (x, y)
self.last_shot = pygame.time.get_ticks()
def aim(self, p):
# Rotate end_boss' gun
x_dist = p[0] - self.x
y_dist = self.y - (screen_height - 100)
self.angle = math.degrees(math.atan2(y_dist, x_dist)) + 90
self.image = pygame.transform.rotate(self.gun_image, self.angle)
self.rect = self.image.get_rect(center=(self.x, self.y))
gun_tip_x = end_boss_centerx + end_boss_gun_length * math.cos(self.angle / 180 * math.pi)
gun_tip_y = end_boss_centery + end_boss_gun_length * math.sin(self.angle / 180 * math.pi)
return self.angle, gun_tip_x, gun_tip_y
# Create EndBoss class
class EndBoss(pygame.sprite.Sprite):
def __init__(self, x, y, health):
super().__init__()
self.x = x
self.y = y
self.health_start = health
self.health_remaining = health
self.image = pygame.image.load(ship_image_path)
self.rect = self.image.get_rect()
self.rect.center = (x, y)
# Initialize objects
end_boss_centerx = screen_width / 2
end_boss_centery = 195
end_boss_center = end_boss_centerx, end_boss_centery
end_boss = EndBoss(end_boss_centerx, end_boss_centery, 300)
end_boss_group = pygame.sprite.Group()
end_boss_group.add(end_boss)
end_boss_gun = EndBossGun(end_boss_centerx, end_boss_centery, 0)
end_boss_gun_group = pygame.sprite.Group()
end_boss_gun_group.add(end_boss_gun)
end_boss_laser_start_pos = end_boss_centerx, end_boss_centery + end_boss_gun_length
end_boss_laser_group = pygame.sprite.Group()
# Create EndBossLaser class
class EndBossLaser(pygame.sprite.Sprite):
def __init__(self, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.angle = angle
self.image = pygame.image.load(laser_image_path)
self.clean_image = self.image.copy()
self.image = pygame.transform.rotate(self.clean_image, angle)
self.rect = self.image.get_rect()
# laser starts at the gun's end
self.rect.center = self.x, self.y
def rotate_laser_around_endboss_center(self, point, pivot_point=(end_boss_centerx, end_boss_centery)):
# justify laser in the same angle of the gun
angle_radians = self.angle / 180 * math.pi
# point: is the point to be rotated
x, y = point
# pivot_point: is the point around which the point is rotated
offset_x, offset_y = pivot_point
adjusted_x = (x - offset_x)
adjusted_y = (y - offset_y)
cos_rad = math.cos(angle_radians)
sin_rad = math.sin(angle_radians)
qx = offset_x + cos_rad * adjusted_x + sin_rad * adjusted_y
qy = offset_y + -sin_rad * adjusted_x + cos_rad * adjusted_y
# qx, qy: new position of the point which was rotated
self.rect.center = qx, qy
def update(self):
self.x += math.cos(self.angle / 180 * math.pi)
self.y += math.sin(self.angle / 180 * math.pi)
self.rect.center = self.x, self.y
def draw_bg():
screen.fill((0, 0, 0))
# Dummy spaceship class for testing
class Spaceship(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((50, 50))
self.image.fill((255, 255, 255))
self.rect = self.image.get_rect()
self.rect.center = (screen_width // 2, screen_height - 50)
def update(self):
pass
def move(self, x):
self.rect.centerx = x
spaceship = Spaceship()
spaceship_group = pygame.sprite.Group()
spaceship_group.add(spaceship)
single_bullet_group = pygame.sprite.Group()
explosion_group = pygame.sprite.Group()
font40 = pygame.font.Font(None, 40)
def draw_text(text, font, color, x, y):
img = font.render(text, True, color)
screen.blit(img, (x, y))
def play_end_boss_level():
game_over = 0
last_count = pygame.time.get_ticks()
last_end_boss_shot = pygame.time.get_ticks()
countdown = 3
run = True
while run:
p = pygame.mouse.get_pos()
clock.tick(fps)
draw_bg()
if countdown == 0:
angle, gun_tip_x, gun_tip_y = end_boss_gun.aim(p)
time_now = pygame.time.get_ticks()
if time_now - last_end_boss_shot > end_boss_cooldown and len(end_boss_group) > 0:
# start position laser
end_boss_laser = EndBossLaser(gun_tip_x, gun_tip_y, angle)
end_boss_laser_group.add(end_boss_laser)
end_boss_laser.rotate_laser_around_endboss_center(end_boss_laser_start_pos)
last_end_boss_shot = time_now
if len(end_boss_group) == 0:
game_over = 1
if game_over == 0:
spaceship.update()
single_bullet_group.update()
end_boss_group.update()
end_boss_gun_group.update()
explosion_group.update()
end_boss_laser_group.update()
else:
if game_over == -1:
draw_text('GAME OVER!', font40, (255, 255, 255), int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if game_over == 1:
draw_text('YOU WIN!', font40, (255, 255, 255), int(screen_width / 2 - 100),
int(screen_height / 2 + 50))
if countdown > 0:
draw_text('GET READY!', font40, (255, 255, 255), int(screen_width / 2 - 110), int(screen_height / 2 + 50))
draw_text(str(countdown), font40, (255, 255, 255), 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
spaceship_group.draw(screen)
single_bullet_group.draw(screen)
explosion_group.draw(screen)
end_boss_group.draw(screen)
end_boss_gun_group.draw(screen)
end_boss_laser_group.draw(screen)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
spaceship.move(p[0])
pygame.display.flip()
pygame.quit()
clock = pygame.time.Clock()
if __name__ == "__main__":
play_end_boss_level()
[![enter image description here][1]][1]