From b99dbb396c313f4b3130b566c0df42c10eec6084 Mon Sep 17 00:00:00 2001 From: davidovski Date: Thu, 5 Jan 2023 11:35:28 +0000 Subject: Initial Commit --- boss.py | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 boss.py (limited to 'boss.py') diff --git a/boss.py b/boss.py new file mode 100644 index 0000000..b977d68 --- /dev/null +++ b/boss.py @@ -0,0 +1,203 @@ +from dataclasses import replace +import math + +from enemy import EnemyAttributes +from formation import ( + CircleFormation, + CircleFormationAttributes, + EnemyFormation, + FormationAttributes, + FormationEnemy, +) +from game import Game + + +class CircleBossFormation(EnemyFormation): + """Enemy Formation for the circular game boss""" + + RADIUS = 10 + CYCLE_PEROID = 500 + COUNT = 6 + + def __init__(self, game: Game, attributes: EnemyAttributes): + """Initialise the circle boss + + :param game: The game which this boss belongs to + :type game: Game + :param attributes: The attributes on which to base spawned enemies + :type attributes: EnemyAttributes + """ + self.image_name = "enemy0" + self.minion_image_name = "smallenemy0" + + self.alpha = 0 + + attributes = CircleFormationAttributes( + radius=40, + period=300, + count=CircleBossFormation.COUNT, + velocity=attributes.velocity, + cooldown=attributes.cooldown, + hp=attributes.hp//2, + reward=attributes.reward*10 + ) + self.circle_formation = CircleFormation( + game, self.minion_image_name, attributes) + + super().__init__(game, self.image_name, attributes) + + def create_enemies(self): + """Spawn the boss""" + self.spawn_enemy((-4, -4, 0)) + + def tick(self, player): + """Update the boss's position + + :param player: The player which to check collision with + :type player: Player + """ + super().tick(player) + self.circle_formation.x = self.x + self.circle_formation.y = self.y + a = (self.alpha/CircleBossFormation.CYCLE_PEROID)*2*math.pi - math.pi + + r = 50*math.sin(a) - 25 + + p = math.sin(a*2)*100 + + self.circle_formation.attributes.radius = math.floor( + CircleBossFormation.RADIUS + (r if r > 0 else 0) + ) + + self.circle_formation.attributes.period = math.floor( + 400 + (p if p < 100 else 100) + ) + + self.circle_formation.tick(player) + + # When the boss is dead, the minions will all die + if len(self.sprites) == 0: + if len(self.circle_formation.sprites) > 0: + self.circle_formation.sprites[0].damage() + else: + self.destroy() + + def destroy(self): + """Remove the circle boss""" + super().destroy() + self.circle_formation.destroy() + + def hide(self): + """Hide the circle boss""" + self.circle_formation.hide() + return super().hide() + + def show(self): + """Show the circle boss""" + self.circle_formation.show() + return super().show() + + +class SnakeBossFormation(EnemyFormation): + """Enemy formation for the snake boss""" + + LENGTH = 32 + + def __init__(self, game: Game, attributes: FormationAttributes): + """Initialise the snake boss + + :param game: The game which the boss belongs to + :type game: Game + :param attributes: The attributes of which to base spawned enemies on + :type attributes: FormationAttributes + """ + self.minion_name = "smallenemy1" + self.tail_name = "smallenemy1_evil" + self.head_name = "enemy2" + + self.phase = 1 + self.phase_timer = 0 + + super().__init__(game, self.minion_name, attributes) + + def create_enemies(self): + """Spawn the snake""" + head_attributes = replace(self.attributes) + head_attributes.hp *= 100 + self.head = FormationEnemy(self.game, self.head_name, + (0, 0, 0), head_attributes) + + self.sprites.append(self.head) + + for i in range(SnakeBossFormation.LENGTH): + self.spawn_enemy((0, 0, i+1)) + + tail_attributes = replace(self.attributes) + head_attributes.hp //= 5 + self.tail = FormationEnemy(self.game, self.tail_name, + (0, 0, SnakeBossFormation.LENGTH+1), + tail_attributes) + + self.sprites.append(self.tail) + + def spawn_enemy(self, offset): + """Spawn one enemy unit of the snake + + :param offset: The offset of the enemy + """ + attributes = replace(self.attributes) + if offset[2] % 6 == 0: + attributes.cooldown = 40 + else: + attributes.cooldown = -1 + + enemy = FormationEnemy(self.game, self.image_name, offset, attributes) + self.sprites.append(enemy) + return enemy + + def position_enemy(self, enemy: FormationEnemy): + """Position the enemy on the game screen + + :param enemy: The enemy to position + :type enemy: FormationEnemy + """ + if self.phase == 2: + p = 120 / (100 + math.cos(self.phase_timer / 400)*20) * 120 + else: + p = 120 + + m = 4 + t = ((-enemy.offset_a*m) + self.game.alpha) / p + math.pi + a = self.game.w // 2 + b = self.game.h // 3 + c = 0 + + if self.phase == 2: + n = 10 - (2000 / (self.phase_timer+2000))*5 + else: + n = 5 + + enemy.set_pos(( + int(self.x + a*math.sin(n*t+c)), + int(self.y + b*math.sin(t)) + )) + + def tick(self, player): + """Update the position of the enemies + + :param player: The player which to check collision with + """ + super().tick(player) + + if self.phase == 1: + self.head.hp = self.attributes.hp*100 + if self.tail.destroyed: + if len(self.sprites) > 1: + self.sprites[-1].damage(amount=(self.attributes.hp//4)) + else: + self.head.hp = self.attributes.hp * 3 + self.phase = 2 + elif self.phase == 2: + self.phase_timer += 1 + self.head.attributes.cooldown = int( + 20 + math.sin(self.phase_timer / 50)*10) -- cgit v1.2.1