def move(self): distance = ml.distance_to_point(self.rect.center, ml.player.rect.center) if distance < self.homing_distance: angle = ml.angle_to_point(self.rect.center, ml.player.rect.center) self.x, self.y, _ = ml.move_point(self, ml.player.rect.center, self.homing_speed, angle, 5) elif self.moving_from_spawn: if self.x == self.target_point[0] and self.y == self.target_point[1]: self.moving_from_spawn = False else: self.x, self.y, _ = ml.move_point(self, self.target_point, self.from_spawn_speed, 0, 360) else: self.y += self.falling_speed
def phase3(self): self.turning_rate = ml.normalize_target_fps(10) # Match the player's speed self.move_speed = ml.normalize_target_fps( float(ml.get_upgrade_values('Movement Speed')) - 1) # Keep the boss positioned above the player above_player = (ml.player.rect.centerx, ml.player.rect.centery - 350) self.x, self.y, self.movement_angle = ml.move_point( self, above_player, self.move_speed, self.movement_angle, self.turning_rate) # Keep boss on screen if self.rect.centery < 0: self.y = 0 # Face the player self.current_angle = ml.angle_to_point(self.rect.center, ml.player.rect.center) # Shoot self.phase2_bd = BulletData(self, coords=self.rect.center, speed=7) self.phase2_timer = self.shoot(self.phase2_timer, self.phase2_bd, self.phase2_fd) self.phase2spread_timer = self.shoot(self.phase2spread_timer, self.phase2spread_bd, self.phase2spread_fd) # Left arc self.phase2arc_bd.coords = self.rect.midleft self.phase2arc_fd.angle = ml.burst_angles(20, 180, 10)[self.phase2arc_counter] self.phase2arc_timer, self.phase2arc_counter = \ self.shoot(self.phase2arc_timer, self.phase2arc_bd, self.phase2arc_fd, self.phase2arc_counter) # Right arc self.phase2arc_bd.coords = self.rect.midright self.phase2arc_fd.angle = ml.burst_angles(20, 0, -10)[self.phase2arc2_counter] self.phase2arc2_timer, self.phase2arc2_counter = \ self.shoot(self.phase2arc2_timer, self.phase2arc_bd, self.phase2arc_fd, self.phase2arc2_counter)
def setup_phase4(self): self.minion3.kill() self.minion3part.kill() self.laser = BossPart('laser_blue.png') self.laser.y = -1000 self.minion1.add(ml.boss_part_group) self.minion1part.add(ml.boss_part_group) self.minion1.move((self.rect.centerx, self.rect.centery - 100)) self.minion1part.move((self.rect.centerx, self.rect.centery - 100)) self.minion2.move((self.rect.centerx - 100, self.rect.centery)) self.minion2part.move((self.rect.centerx - 100, self.rect.centery)) self.minion3 = BossPart('mini_ring.png') self.minion3part = BossPart('mini_ring_red.png') self.minion3.move((self.rect.centerx + 100, self.rect.centery)) self.minion3part.move((self.rect.centerx + 100, self.rect.centery)) self.phase1fd.multi = 6 self.phase1fd.interval = 15 self.phase1fd.firing_speed = 0.5 self.phase1bd.parent = self.minion3 self.phase1bd.speed = 3.5 self.phase1timer1 = ml.time() + self.phase_change_delay self.phase1timer2 = ml.time() + self.phase_change_delay self.phase1timer3 = ml.time() + self.phase_change_delay + (1 / (2 * 0.5)) self.phase1timer4 = ml.time() + self.phase_change_delay + (1 / (2 * 0.5)) self.phase2minionbd.parent = self.minion1 self.minion1.current_angle = ml.angle_to_point( self.rect.center, ml.player.rect.center) + 180 self.minion_angle = 90 self.phase3minionbd1.turning_rate = 0.9 self.spawn_powerups(base_powerup_spawn * 7)
def shoot(timer, bullet_data, firing_data, burst_counter=0): # TODO clean up shoot() documentation """ All-encompassing method for shooting. Mix and match arguments to achieve desired patterns. -- timer should be a time from ml.time(). -- firing_speed limits the rate. If the shoot is successful, returns the current ml.time() to reset the timer, otherwise returns the original timer. -- interval is the angular gap between multi-shot bullets. -- angle determines the angle that the bullet is first fired at. If not defined, firing angle will be random from 0 to 360. If defined, aim will override angle. -- random_arc modifies the angle of the shot by random.uniform(-random_arc, random_arc). -- burst, if greater than 0, sets method to burst mode. It will shoot a number of times equal to burst with burst_delay time between each shot. In burst mode, firing_speed acts as the delay, in seconds, between bursts, rather than the number of attacks per second. burst_counter keeps track of how far through the burst it has gotten. In burst mode, method will return 2 values. The first will be a ml.time(). If the burst has completed, it will return a new ml.time(), otherwise it will return the original timer. The second value will be the incremented counter, or 0 if the burst has finished. The new burst counter should be passed back in the next time the method is called. See enemybullet.BulletData for further documentation. Usage: self.timer = self.omni_shot(args) Burst mode: self.timer, self.burst_counter = self.omni_shot(args) """ parent = bullet_data.parent firing_speed = firing_data.firing_speed interval = firing_data.interval aim = firing_data.aim multi = firing_data.multi random_arc = firing_data.random_arc burst = firing_data.burst burst_delay = firing_data.burst_delay counter = burst_counter angle = firing_data.angle if burst: if aim: shot_angle = ml.angle_to_point(parent.rect.center, ml.player.rect.center) elif angle is None: shot_angle = random.uniform(0, 360) else: shot_angle = angle if counter < burst and ml.time() - timer >= burst_delay: shot_angles = ml.multi_shot_angles(multi, shot_angle, interval) for arc_shot in range(multi): EnemyBullet(bullet_data, angle=shot_angles[arc_shot] + random.uniform(-random_arc, random_arc)) return ml.time(), counter + 1 else: # Reset counter if ml.time() - timer >= firing_speed: counter = 0 return timer, counter elif ml.time() - timer >= (1 / firing_speed): if aim: shot_angle = ml.angle_to_point(parent.rect.center, ml.player.rect.center) elif angle is None: shot_angle = random.uniform(0, 360) else: shot_angle = angle shot_angles = ml.multi_shot_angles(multi, shot_angle, interval) for arc_shot in range(multi): EnemyBullet( bullet_data, angle=shot_angles[arc_shot] + random.uniform(-random_arc, random_arc), ) return ml.time() return timer
def phase4(self): # Move boss in circle around center of window window_center = ml.window_width / 2, ml.window_height / 2 radius = 200 self.circle_angle += 0.5 circle_x = ml.window_width / 2 + \ radius * math.cos(math.radians(self.circle_angle)) circle_y = ml.window_height / 2 + \ radius * math.sin(math.radians(self.circle_angle)) target_point = circle_x, circle_y self.x, self.y, _ = ml.move_point(self, target_point, 999, 0, 360) # Laser self.laser.change_image(image=ml.get_laser_image( ml.angle_to_point(self.rect.center, window_center))) self.laser.move(window_center) if ml.time() - self.phase_change_time > self.phase_change_delay + 2: self.collide_parts() # Minions self.minion1part.animate(angle_change=15) self.minion2part.animate(angle_change=15) self.minion3part.animate(angle_change=15) # minion3 self.minion3.x, self.minion3.y, _ = ml.move_point( self.minion3, ml.player.rect.center, 1, 0, 360) self.phase1fd.angle = 0 self.phase1timer1 = self.shoot(self.phase1timer1, self.phase1bd, self.phase1fd) self.phase1fd.angle = 180 self.phase1timer2 = self.shoot(self.phase1timer2, self.phase1bd, self.phase1fd) self.phase1fd.angle = 90 self.phase1timer3 = self.shoot(self.phase1timer3, self.phase1bd, self.phase1fd) self.phase1fd.angle = 270 self.phase1timer4 = self.shoot(self.phase1timer4, self.phase1bd, self.phase1fd) # minion1 self.minion1.x, self.minion1.y, self.minion1.current_angle = \ ml.move_point(self.minion1, ml.player.rect.center, 5, self.minion1.current_angle, 0.5) self.phase2minion_timer = self.shoot(self.phase2minion_timer, self.phase2minionbd, self.phase2minionfd) # Bounce off walls if self.minion1.rect.left < 0: self.minion1.rect.left = 0 self.minion1.x = self.minion1.rect.centerx self.minion1.current_angle = 180 - self.minion1.current_angle elif self.minion1.rect.right > ml.window_width: self.minion1.rect.right = ml.window_width self.minion1.x = self.minion1.rect.centerx self.minion1.current_angle = 180 - self.minion1.current_angle elif self.minion1.rect.top < 0: self.minion1.rect.top = 0 self.minion1.y = self.minion1.rect.centery self.minion1.current_angle = 360 - self.minion1.current_angle elif self.minion1.rect.bottom > ml.window_height: self.minion1.rect.bottom = ml.window_height self.minion1.y = self.minion1.rect.centery self.minion1.current_angle = 360 - self.minion1.current_angle self.minion1.current_angle = ml.normalize_angle( self.minion1.current_angle) # minion2 self.minion_angle = ml.normalize_angle(self.minion_angle + 1) radius = 250 circle_x = ml.player.rect.centerx + radius * math.cos( math.radians(self.minion_angle)) circle_y = ml.player.rect.centery - radius * math.sin( math.radians(self.minion_angle)) minion2_point = circle_x, circle_y self.minion2.x, self.minion2.y, _ = ml.move_point( self.minion2, minion2_point, 20, 0, 360) self.minion2part.move((self.minion2.x, self.minion2.y)) self.phase3miniontimer1 = self.shoot(self.phase3miniontimer1, self.phase3minionbd1, self.phase3minionfd) # Move parts self.minion1part.move((self.minion1.x, self.minion1.y)) self.minion2part.move((self.minion2.x, self.minion2.y)) self.minion3part.move((self.minion3.x, self.minion3.y))