def update(self, dt, enemy_bullets, ship): """ Update movement, animation and shooting :param dt: time between frames :param enemy_bullets: Sprite group :param ship: Sprite - player :return: Nothing """ # Stage 1 if self.stage == 1: if self.animate(self.animation1, self.animation1_start, dt): if self.health < 2000: self.stage = 2 self.init_animation(self.animation2_start) self.calculate_movement(self.animation2) # Shooting if self.animation_frame == 5: if time() > self.shoot_timer1: position = [ self.rect.left + 34 + (12 * self.canon), self.rect.centery + 50 ] target = [ship.rect.centerx, ship.rect.centery] enemy_bullets.add(EnemyBullet(position, 0.15, 2, target)) SFX().blaster2.play() self.canon += 1 if self.canon > 4: self.canon = 1 self.shoot_timer1 = time() + 1 else: self.shoot_timer1 = time() + 0.25 # Stage 2 elif self.stage == 2: self.animate(self.animation2, self.animation2_start, dt) # Shooting if self.animation_frame == 5: if time() > self.shoot_timer1: enemy_bullets.add( EnemyBullet( [self.rect.left + 46, self.rect.centery + 50], 0.15, 2, -30)) enemy_bullets.add( EnemyBullet( [self.rect.left + 58, self.rect.centery + 50], 0.15, 2, -10)) enemy_bullets.add( EnemyBullet( [self.rect.left + 70, self.rect.centery + 50], 0.15, 2, 10)) enemy_bullets.add( EnemyBullet( [self.rect.left + 82, self.rect.centery + 50], 0.15, 2, 30)) SFX().blaster2.play() self.shoot_timer1 = time() + 0.8
def check_collisions(self): # Check collisions between bullets and enemies, bullets get removed automatically dict = pygame.sprite.groupcollide(self.level.enemies, self.bullets, False, True, pygame.sprite.collide_mask) for enemy in dict.keys(): # Create effects on impacting bullets for bullet in dict[enemy]: self.effects.add( hit.Hit([bullet.rect.centerx, bullet.rect.top])) enemy.hit() if enemy.health <= 0: if enemy.pickup: self.pickups.add( enemy.pickup([enemy.rect.centerx, enemy.rect.centery])) self.effects.add( hit.Explosion([enemy.rect.centerx, enemy.rect.centery])) self.status.score += enemy.reward self.level.enemies.remove(enemy) SFX().boom1.play() # check collisions between player and enemy bullets dict = pygame.sprite.spritecollide(self.ship, self.enemy_bullets, True, pygame.sprite.collide_mask) for bullet in dict: self.effects.add(hit.Hit([bullet.rect.centerx, bullet.rect.bottom])) self.ship.hit() self.status.lives -= 1 SFX().boom1.play() # Check collisions between player and enemies list = pygame.sprite.spritecollide(self.ship, self.level.enemies, False, pygame.sprite.collide_mask) for enemy in list: self.effects.add( hit.Explosion([enemy.rect.centerx, enemy.rect.centery])) self.ship.hit() self.level.enemies.remove(enemy) self.status.lives -= 1 SFX().boom1.play() # Check collisions between player and pickups list = pygame.sprite.spritecollide(self.ship, self.pickups, False) for pickup in list: pickup.pickup(self.status)
def _generate_blood_sfx(self): start = random.randrange(4) * 6 angle = random.randrange(0, 180) return SFX('assets/sfx/bloodSheet.png', (12, 2), (64, 64), self.sprite.get_position() + BLOOD_OFFSET, start, start + 6, rotation=angle)
def fire_bullet(self): # Set shooting flag self.ship.shooting = True # Set shooting timer self.ship.shooting_timer = time() + 0.1 # Add bullet if len(self.bullets) < CFG().bullet_count: self.bullets.add(Bullet(self.ship)) SFX().blaster1.play()
def _select_avatar(self, selection): active_units = self.left_units if self.active == "left" else self.right_units if self.current_phase == BattlePhase.ORDER: if selection in active_units: self._clear_selection() self.selected_avatar = selection selection.cell.set_fill_color(CellColor.ORANGE) selection.cell.set_border_color(CellColor.ORANGE_HIGHLIGHT) self.selection_arrow.position = (selection.sprite.get_center() + ARROW_OFFSET) self._update_panels() elif self.current_phase == BattlePhase.TARGET and self.selected_action == BattleAction.ATTACK: if not selection in active_units: self.unit_orders[self.selected_avatar] = { "order": BattleAction.ATTACK, "target": selection } x, y = selection.sprite.get_center() self.action_sfx = SFX('assets/sfx/retaliate.png', (16, 1), (64, 64), (x - 10, y - 50), 0, 15, frame_speed=80) self.current_phase = BattlePhase.ORDER self._select_action(BattleAction.NEXT_UNIT) elif self.current_phase == BattlePhase.TARGET and self.selected_action == BattleAction.DEFEND: # Units that are defended by an ally can't also defend an ally if self._avatar_is_defended_by_ally(self.selected_avatar) and selection != self.selected_avatar: # error message return # Each unit can be only be defended by one ally at a time if self._avatar_is_defended_by_ally(selection): # error message return # Cannot defend an ally that is also defending a different ally if selection in self.unit_orders and self.unit_orders[selection]['order'] == BattleAction.DEFEND: # error message return if selection in active_units: self.unit_orders[self.selected_avatar] = {"order": BattleAction.DEFEND, "target": selection} x, y = selection.sprite.get_center() self.action_sfx = SFX('assets/sfx/shield.png', (10, 1), (64, 64), (x - 10, y - 50), 0, 9, frame_speed=80) self.current_phase = BattlePhase.ORDER self._select_action(BattleAction.NEXT_UNIT)
def _select_action(self, action): active_units = self.left_units if self.active == "left" else self.right_units if self.current_phase == BattlePhase.ORDER: if action == BattleAction.ATTACK: self.current_phase = BattlePhase.TARGET FloatingText.create_new(FloatingText("attack", self.selected_avatar.sprite.get_center(), [255] * 4)) self.selected_action = BattleAction.ATTACK self._update_panels() elif action == BattleAction.DEFEND: self.current_phase = BattlePhase.TARGET FloatingText.create_new(FloatingText("defend", self.selected_avatar.sprite.get_center(), [255] * 4)) self.selected_action = BattleAction.DEFEND self._update_panels() elif action == BattleAction.NEXT_UNIT: empty_unit = False for unit in active_units: if not unit in self.unit_orders: empty_unit = True if not empty_unit: self._end_turn() return if not self.selected_avatar: self._select_avatar(active_units[0]) else: index = active_units.index(self.selected_avatar) index += 1 if index < (len(active_units) - 1) else -index self._select_avatar(active_units[index]) elif action == BattleAction.GUARD: FloatingText.create_new(FloatingText("guard", self.selected_avatar.sprite.get_center(), [255] * 4)) x, y = self.selected_avatar.sprite.get_center() self.action_sfx = SFX('assets/sfx/shield.png', (10, 1), (64, 64), (x - 10, y - 50), 0, 9, frame_speed=80) self.unit_orders[self.selected_avatar] = { "order": BattleAction.GUARD, "target": None } self._select_action(BattleAction.NEXT_UNIT) elif self.current_phase == BattlePhase.TARGET: if action == BattleAction.CANCEL: self.current_phase = BattlePhase.ORDER self._update_panels()
def __init__(self): GameScene.__init__(self) self.background = suie.Image(asset_manager.load_image('wcBattleBackground.png'), (0, 0)) self.selection_arrow = SFX('assets/ui/rotatingArrow.png', (7, 2), (40, 40), (0, 0), 0, 13, True, frame_speed=80) self.action_sfx = None self.grid = Grid(Vector(suie.SCREEN_WIDTH // 2 - 168, 150), (7, 9)) self.left_units = [] self.right_units = [] self.dead_units = [] for i in range(3): self.left_units.append(factory.generate_avatar('footman', 12 + i)) self.right_units.append(factory.generate_avatar('archer', 14 + i)) self.executor = BattleExecutor(self.left_units, self.right_units, self.grid) self._arrange_units() self.current_phase = BattlePhase.ORDER self.active = "left" self.turn_count = 0 """ Save unit orders in this dict. Ex/ Avatar: { order: BattleAction.ATTACK, target: Avatar2 }, Avatar2: { order: BattleAction.DEFEND, target: Avatar3 }, etc... """ self.unit_orders = {} self.avatar_icons = [] self.action_icons = [] self.selected_avatar = None self.hovered_avatar = None self.selected_action = None self._setup_panels() self._start_turn('left')
def update(self, dt, enemy_bullets, ship, status): """ Updated level, background and enemies :param dt: :param enemy_bullets: :param ship: :return: True if the game should be running, False if not """ if not SFX().is_music_playing(): SFX().music_play(self.music) # If at the start of level show story if self.starting: if self.story.update('start'): return False # No more story - start level self.show_name = True self.timer = time() + 3 self.starting = False self.enemy_hold = True # Show level name, hold enemies elif self.show_name: if self.timer > time(): self.enemy_hold = True else: self.show_name = False # No more level + no more enemies if len(self.layout) == 0 and len(self.enemies) == 0: # Show end story if self.story.update('end'): return False # End level self.ending = True pygame.mixer.music.stop() return True # Background update self.background.update(dt, self.enemy_hold) # Enemy spawning and level progression if self.enemy_hold: if len(self.enemies) == 0: self.enemy_hold = False else: if self.timer < time() and len(self.layout) != 0: self.timer = time() + CFG().spawn_speed line = self.layout.pop(-1) position = 0 for char in line: position += 1 # If there is enemy calculate it's x position if char != '-': spacing = CFG().int_screen_width / CFG().level_width pos_x = spacing * position - spacing / 2 # Stop spawning until all enemies are gone if char == '_': self.enemy_hold = True break if char == 'a': self.enemies.add(asteroid.Asteroid(pos_x)) elif char == 's': self.enemies.add(shifter.Shifter(pos_x)) elif char == '1': self.enemies.add(boss.Boss1(status)) # Enemy update self.enemies.update(dt, enemy_bullets, ship) # Get rid of enemies out of screen for sprite in self.enemies: if sprite.rect.top > CFG().int_screen_height: self.enemies.remove(sprite) return True
class BattleScene(GameScene): def __init__(self): GameScene.__init__(self) self.background = suie.Image(asset_manager.load_image('wcBattleBackground.png'), (0, 0)) self.selection_arrow = SFX('assets/ui/rotatingArrow.png', (7, 2), (40, 40), (0, 0), 0, 13, True, frame_speed=80) self.action_sfx = None self.grid = Grid(Vector(suie.SCREEN_WIDTH // 2 - 168, 150), (7, 9)) self.left_units = [] self.right_units = [] self.dead_units = [] for i in range(3): self.left_units.append(factory.generate_avatar('footman', 12 + i)) self.right_units.append(factory.generate_avatar('archer', 14 + i)) self.executor = BattleExecutor(self.left_units, self.right_units, self.grid) self._arrange_units() self.current_phase = BattlePhase.ORDER self.active = "left" self.turn_count = 0 """ Save unit orders in this dict. Ex/ Avatar: { order: BattleAction.ATTACK, target: Avatar2 }, Avatar2: { order: BattleAction.DEFEND, target: Avatar3 }, etc... """ self.unit_orders = {} self.avatar_icons = [] self.action_icons = [] self.selected_avatar = None self.hovered_avatar = None self.selected_action = None self._setup_panels() self._start_turn('left') # self.grid.debug_fill() def _avatar_is_defended_by_ally(self, avatar): for ordered in self.unit_orders: if ordered == avatar: continue order = self.unit_orders[ordered] if order['order'] == BattleAction.DEFEND and order['target'] == avatar: return True return False def _avatar_has_order(self, avatar): return avatar in self.unit_orders def _start_turn(self, who): self.active = who if who == "left": self.turn_count += 1 self.current_phase = BattlePhase.ORDER self.selected_avatar = None self.selected_action = None for unit in self.left_units + self.right_units: unit.cell.set_fill_color(CellColor.SHADOW) unit.cell.set_border_color(None) self._update_panels() def _end_execution_phase(self): self.unit_orders.clear() for unit in self.left_units: if not unit.is_alive(): self.left_units.remove(unit) self.dead_units.append(unit) for unit in self.right_units: if not unit.is_alive(): self.right_units.remove(unit) self.dead_units.append(unit) # Check for battle finish here self._start_turn('left') def _end_turn(self): if self.active == 'left': self._start_turn('right') else: self.selected_avatar = None self.current_phase = BattlePhase.EXECUTION self.executor.execute(self.unit_orders, self._end_execution_phase, self.turn_count) self._update_panels() def _lineup_units(self, unit_list, xcoord: int): size = len(unit_list) if size == 1: unit_list[0].set_cell(self.grid[xcoord, 3]) elif size == 2: unit_list[0].set_cell(self.grid[xcoord, 2]) unit_list[1].set_cell(self.grid[xcoord, 4]) elif size == 3: unit_list[0].set_cell(self.grid[xcoord, 1]) unit_list[1].set_cell(self.grid[xcoord, 3]) unit_list[2].set_cell(self.grid[xcoord, 5]) elif size == 4: unit_list[0].set_cell(self.grid[xcoord, 2]) unit_list[1].set_cell(self.grid[xcoord, 3]) unit_list[2].set_cell(self.grid[xcoord, 4]) unit_list[3].set_cell(self.grid[xcoord, 5]) elif size == 5: for i in range(5): unit_list[i].set_cell(self.grid[xcoord, i + 2]) elif size == 6: for i in range(6): unit_list[i].set_cell(self.grid[xcoord, i + 1]) def _arrange_units(self): for unit in self.left_units: unit.sprite.set_facing(Facing.RIGHT) for unit in self.right_units: unit.sprite.set_facing(Facing.LEFT) self._lineup_units(self.left_units, 0) self._lineup_units(self.right_units, 6) def _select_action(self, action): active_units = self.left_units if self.active == "left" else self.right_units if self.current_phase == BattlePhase.ORDER: if action == BattleAction.ATTACK: self.current_phase = BattlePhase.TARGET FloatingText.create_new(FloatingText("attack", self.selected_avatar.sprite.get_center(), [255] * 4)) self.selected_action = BattleAction.ATTACK self._update_panels() elif action == BattleAction.DEFEND: self.current_phase = BattlePhase.TARGET FloatingText.create_new(FloatingText("defend", self.selected_avatar.sprite.get_center(), [255] * 4)) self.selected_action = BattleAction.DEFEND self._update_panels() elif action == BattleAction.NEXT_UNIT: empty_unit = False for unit in active_units: if not unit in self.unit_orders: empty_unit = True if not empty_unit: self._end_turn() return if not self.selected_avatar: self._select_avatar(active_units[0]) else: index = active_units.index(self.selected_avatar) index += 1 if index < (len(active_units) - 1) else -index self._select_avatar(active_units[index]) elif action == BattleAction.GUARD: FloatingText.create_new(FloatingText("guard", self.selected_avatar.sprite.get_center(), [255] * 4)) x, y = self.selected_avatar.sprite.get_center() self.action_sfx = SFX('assets/sfx/shield.png', (10, 1), (64, 64), (x - 10, y - 50), 0, 9, frame_speed=80) self.unit_orders[self.selected_avatar] = { "order": BattleAction.GUARD, "target": None } self._select_action(BattleAction.NEXT_UNIT) elif self.current_phase == BattlePhase.TARGET: if action == BattleAction.CANCEL: self.current_phase = BattlePhase.ORDER self._update_panels() def _hover_avatar(self, avatar, flag: bool): if flag and not self.hovered_avatar: self.hovered_avatar = avatar if avatar == self.selected_avatar: return active_units = self.left_units if self.active == "left" else self.right_units if self.current_phase == BattlePhase.ORDER: color = CellColor.BLUE if avatar in active_units else CellColor.RED bcolor = CellColor.BLUE_HIGHLIGHT if avatar in active_units else CellColor.SHADOW_HIGHLIGHT elif self.current_phase == BattlePhase.TARGET: color = CellColor.GREEN if avatar in active_units else CellColor.RED bcolor = CellColor.GREEN_HIGHLIGHT if avatar in active_units else CellColor.RED_HIGHLIGHT elif self.current_phase in [BattlePhase.WAITING, BattlePhase.EXECUTION]: color, bcolor = CellColor.SHADOW, CellColor.SHADOW_HIGHLIGHT avatar.cell.set_fill_color(color) avatar.cell.set_border_color(bcolor) elif not flag: self.hovered_avatar = None if avatar == self.selected_avatar: return avatar.cell.set_fill_color(CellColor.SHADOW) avatar.cell.set_border_color(None) def _clear_selection(self): if self.selected_avatar: self.selected_avatar.cell.set_fill_color(CellColor.SHADOW) self.selected_avatar.cell.set_border_color(None) self.selected_avatar = None self._update_panels() def _select_avatar(self, selection): active_units = self.left_units if self.active == "left" else self.right_units if self.current_phase == BattlePhase.ORDER: if selection in active_units: self._clear_selection() self.selected_avatar = selection selection.cell.set_fill_color(CellColor.ORANGE) selection.cell.set_border_color(CellColor.ORANGE_HIGHLIGHT) self.selection_arrow.position = (selection.sprite.get_center() + ARROW_OFFSET) self._update_panels() elif self.current_phase == BattlePhase.TARGET and self.selected_action == BattleAction.ATTACK: if not selection in active_units: self.unit_orders[self.selected_avatar] = { "order": BattleAction.ATTACK, "target": selection } x, y = selection.sprite.get_center() self.action_sfx = SFX('assets/sfx/retaliate.png', (16, 1), (64, 64), (x - 10, y - 50), 0, 15, frame_speed=80) self.current_phase = BattlePhase.ORDER self._select_action(BattleAction.NEXT_UNIT) elif self.current_phase == BattlePhase.TARGET and self.selected_action == BattleAction.DEFEND: # Units that are defended by an ally can't also defend an ally if self._avatar_is_defended_by_ally(self.selected_avatar) and selection != self.selected_avatar: # error message return # Each unit can be only be defended by one ally at a time if self._avatar_is_defended_by_ally(selection): # error message return # Cannot defend an ally that is also defending a different ally if selection in self.unit_orders and self.unit_orders[selection]['order'] == BattleAction.DEFEND: # error message return if selection in active_units: self.unit_orders[self.selected_avatar] = {"order": BattleAction.DEFEND, "target": selection} x, y = selection.sprite.get_center() self.action_sfx = SFX('assets/sfx/shield.png', (10, 1), (64, 64), (x - 10, y - 50), 0, 9, frame_speed=80) self.current_phase = BattlePhase.ORDER self._select_action(BattleAction.NEXT_UNIT) def _handle_events(self, event_list): for event in event_list: if event.type == KEYDOWN: if event.key == K_BACKSPACE: if self.current_phase == BattlePhase.ORDER: self._clear_selection() elif self.current_phase == BattlePhase.TARGET: self._select_action(BattleAction.CANCEL) elif event.key == K_TAB: if self.current_phase == BattlePhase.ORDER: self._select_action(BattleAction.NEXT_UNIT) elif event.type == MOUSEMOTION: x, y = pygame.mouse.get_pos() if self.hovered_avatar and not self.hovered_avatar.cell.get_rect().collidepoint(x, y): self._hover_avatar(self.hovered_avatar, False) for unit in self.left_units + self.right_units: if unit.cell.get_rect().collidepoint(x, y): self._hover_avatar(unit, True) elif event.type == MOUSEBUTTONDOWN: for unit in self.left_units + self.right_units: x, y = pygame.mouse.get_pos() if unit.cell.get_rect().collidepoint(x, y): self._select_avatar(unit) def update(self, event_list, elapsed): for unit in self.left_units: unit.update(elapsed) for unit in self.right_units: unit.update(elapsed) FloatingText.update_all(elapsed) self.hud_panel.update(event_list) if self.current_phase != BattlePhase.EXECUTION: self._handle_events(event_list) if self.current_phase == BattlePhase.EXECUTION: self.executor.update(event_list, elapsed) def draw(self, screen): self.background.draw(screen) self.grid.draw(screen) for unit in self.dead_units: unit.draw(screen) for unit in self.left_units + self.right_units: unit.draw(screen) if self.selected_avatar: self.selection_arrow.draw(screen) if self.action_sfx: self.action_sfx.draw(screen) FloatingText.draw_all(screen) self.hud_panel.draw(screen) if self.current_phase == BattlePhase.EXECUTION: self.executor.draw(screen) def cleanup(self): pass # --- HUD FUNCTIONALITY --- def _letter_from_order(self, order): if order == BattleAction.GUARD: return "G" elif order == BattleAction.DEFEND: return "D" elif order == BattleAction.ATTACK: return "A" def _update_panels(self): active_group = self.left_units if self.active == 'left' else self.right_units self.info_label.set_text("ACTIVE: %s | PHASE: %s | TURN #: %s" % (self.active, self.current_phase, self.turn_count)) for icon in self.avatar_icons: self.lineup_panel.remove_child(icon) self.avatar_icons.clear() if self.current_phase == BattlePhase.ORDER: for i in range(len(active_group)): icon = suie.AvatarIcon((i * (suie.AvatarIcon.WIDTH + 2), 0), active_group[i]) if active_group[i] == self.selected_avatar: icon.highlight(True) if active_group[i] in self.unit_orders: icon.set_action(self._letter_from_order(self.unit_orders[active_group[i]]["order"])) self.avatar_icons.append(icon) self.lineup_panel.add_child(icon) for icon in self.action_icons: self.action_panel.remove_child(icon) self.action_icons.clear() if self.current_phase == BattlePhase.ORDER and self.selected_avatar: self.action_icons.append(suie.ActionIcon((0, 0), lambda: self._select_action(BattleAction.ATTACK), "a", 116)) self.action_icons.append(suie.ActionIcon((suie.ActionIcon.WIDTH + 2, 0), lambda: self._select_action(BattleAction.DEFEND), "d", 164)) self.action_icons.append(suie.ActionIcon(((suie.ActionIcon.WIDTH + 2) * 2, 0), lambda: self._select_action(BattleAction.NEXT_UNIT), "n", 170)) self.action_icons.append(suie.ActionIcon(((suie.ActionIcon.WIDTH + 2) * 3, 0), lambda: self._select_action(BattleAction.GUARD), "g", 172)) elif self.current_phase == BattlePhase.TARGET and self.selected_avatar: self.action_icons.append(suie.ActionIcon((0, 0), lambda: self._select_action(BattleAction.CANCEL), "c", 91)) for icon in self.action_icons: self.action_panel.add_child(icon) def _setup_panels(self): self.lineup_panel = suie.Panel((5, suie.SCREEN_HEIGHT - 90), (360, 80)) border = suie.Border((0, 0), (80, 80)) self.target_panel = suie.Panel((suie.SCREEN_WIDTH - 85, suie.SCREEN_HEIGHT - 85), (80, 80), [border]) self.action_panel = suie.Panel((375, suie.SCREEN_HEIGHT - 85), (320, 80)) border = suie.Border((0, 0), (600, 20)) self.info_label = suie.Label((10, 6), "ACTIVE: %s | PHASE: %s | TURN #: %s" % (self.active, self.current_phase, self.turn_count), font_size=10) self.info_panel = suie.Panel((2, 2), (600, 20), [border, self.info_label]) self.hud_panel = suie.Panel((0, 0), (suie.SCREEN_WIDTH, suie.SCREEN_HEIGHT), [self.info_panel, self.lineup_panel, self.target_panel, self.action_panel])