def render(self): flip_x = self.facing_x == -1 self.order = 1 if self.invisible: if self.state == Player.STATE_HIDDEN: self.sprite.play('HIDDEN', flip_x) self.order = -1 else: if self.velocity_x != 0: self.sprite.play('INVISIBLE_RUN', flip_x) else: self.sprite.play('INVISIBLE', flip_x) elif self.state == Player.STATE_STANDARD: if self.velocity_y == 0 and not solid_below(self, self.x, self.y): self.sprite.play('JUMP', flip_x) elif self.velocity_y < 0: self.sprite.play('JUMP', flip_x) elif self.velocity_y > 0: self.sprite.play('FALL', flip_x) elif self.velocity_x != 0: self.sprite.play('RUN', flip_x) else: self.sprite.play('IDLE', flip_x) elif self.state == Player.STATE_CLIMBING: if self.state_args['vertical']: if self.velocity_y != 0: self.sprite.play('CLIMB_LADDER') self.sprite.resume() else: self.sprite.play('CLIMB_LADDER') self.sprite.pause() else: graphics.set_color(125, 125, 125) graphics.draw_entity_rect(self) self.gadget.render() return elif self.state == Player.STATE_CROUCHING: if self.velocity_x != 0: self.sprite.play('CRAWL', flip_x) else: self.sprite.play('CROUCH', flip_x) elif self.state == Player.STATE_LEDGEGRAB: self.sprite.play('HANG', flip_x) elif self.state == Player.STATE_PUSHING: self.sprite.play('PUSH', flip_x) else: # Default graphics.set_color(125, 125, 125) graphics.draw_entity_rect(self) self.gadget.render() return self.sprite.render(self.x, self.y) self.gadget.render()
def update(self): temp_x = self.x temp_y = self.y cx, cy = self.center players = self.container.get_group('player') target = None target_distance = None target_visible = False tcx, tcy = (0, 0) # Aggro closest player for player in players: temp_distance = self.distance_from(player) if target_distance is None or temp_distance < target_distance: target = player target_distance = temp_distance tcx, tcy = target.center # Visibility target_distance if target_distance <= Dog.AGGRO_RADIUS: if target_distance <= Dog.AGGRO_RADIUS: target_visible = True # Bite if self.collides(target, self.x, self.y) and \ self.state != Dog.STATE_STUNNED: self.bite(target) # Update state if self.state == Dog.STATE_STANDARD: # Movement if solid_below(self, temp_x + self.width * self.facing_x, temp_y) and not \ self.collides_solid(temp_x + self.width * self.facing_x, self.y): self.velocity_x = Dog.SPEED_WALK * self.facing_x else: self.velocity_x = 0 self.facing_x *= -1 # Detect player if target_visible: self.change_state(Dog.STATE_AGGRO) elif self.state == Dog.STATE_AGGRO: if target_distance > Dog.AGGRO_RADIUS: if not self.aggro_timer.tick(): self.change_state(Dog.STATE_STANDARD) self.velocity_x = 0 else: self.aggro_timer.reset() x_dist = abs(cx - tcx) if x_dist > (self.width / 2): x_dist = cx - tcx if x_dist < 0: self.facing_x = 1 else: self.facing_x = -1 if solid_below(self, temp_x + self.width * self.facing_x, temp_y): self.velocity_x = Dog.SPEED_RUN * self.facing_x else: self.velocity_x = 0 else: self.velocity_x = 0 elif self.state == Dog.STATE_STUNNED: self.stun_timer -= 1 if self.stun_timer <= 0: self.state = Dog.STATE_STANDARD # Finalize if self.velocity_y < MAX_GRAVITY: self.velocity_y += GRAVITY temp_x += self.velocity_x temp_y += self.velocity_y c, self.x, self.y, self.velocity_x, self.velocity_y = \ collision_resolution(self, temp_x, temp_y)
def update(self): temp_x = self.x temp_y = self.y player = self.container.get_name('player') distance_from_player = self.distance_from(player) pcx, pcy = player.center # All ladders that are below this entity are treated as solids in this # update. They are reverted back to this prior state at the end of the # update. altered_ladders = [ l for l in self.container.get_group('ladder') if l.y >= self.y + self.height ] for l in altered_ladders: l._temp_soldier_solid = l.solid l.solid = True # Calculate player_visible player_visible = False view_obstructions = self.container.get_group('opaque') if distance_from_player <= 64 and not player.invisible and \ player.state != Player.STATE_HIDDEN: if self.collides(player, self.x, self.y): player_visible = True else: opp = self.y - pcy adj = pcx - self.x angle = math.degrees(math.atan2(opp, adj)) if angle < 0: angle = 360 + angle sight_range = angle_from_facing(self.facing_x, self.facing_y) if sight_range <= angle <= sight_range + 60: player_visible = \ raycast(self.x, self.y, pcx, pcy, view_obstructions) if sight_range + 60 >= 360: angle = 360 - angle if sight_range <= angle <= sight_range + 60: player_visible = \ raycast(self.x, self.y, pcx, pcy, view_obstructions) if self.state == Soldier.STATE_IDLE: # TODO turn around, check behind you if player_visible: self.change_state(Soldier.STATE_ALERT, spotted=(pcx, pcy)) elif self.state == Soldier.STATE_PATROL: if player_visible: self.change_state(Soldier.STATE_ALERT, spotted=(pcx, pcy)) elif self.wait_timer > 0: self.wait_timer -= 1 if self.wait_timer <= 0: self.facing_x *= -1 else: if solid_below(self, temp_x, temp_y): tx = temp_x + self.width * self.facing_x if self.collides_solid(tx, self.y) or \ not solid_below(self, tx, temp_y): self.velocity_x = 0 self.wait_timer = 60 else: if self.slowed: self.velocity_x = Soldier.SPEED_SLOW * self.facing_x else: self.velocity_x = Soldier.SPEED * self.facing_x elif self.state == Soldier.STATE_ALERT: target_distance = 0 if player_visible: self.alert_timer = Soldier.ALERT_TIMER target_distance = Soldier.AGGRO_DISTANCE self.spotted_at = (pcx, pcy) else: if self.alert_timer == Soldier.ALERT_TIMER: # Player just went out of sight, therefore look where they # would be. ie where they are this frame self.spotted_at = (pcx, pcy) self.alert_timer -= 1 if self.alert_timer <= 0: self.change_state(Soldier.STATE_PATROL) return target_distance = 12 target = self.spotted_at # Compute facing angle opp = self.y - target[1] adj = target[0] - self.x player_angle = math.degrees(math.atan2(opp, adj)) if player_angle < 0: player_angle = 360 + player_angle self.facing_x, self.facing_y = facing_from_angle(player_angle) dist_x_target = abs(self.center_x - target[0]) # diff_y_target = self.center_y - target[1] # MOVEMENT if dist_x_target > target_distance: tx = temp_x + self.width * self.facing_x if solid_below(self, tx, temp_y) and not \ self.collides_solid(tx, self.y): if self.slowed: self.velocity_x = Soldier.SPEED_SLOW * self.facing_x else: self.velocity_x = Soldier.SPEED_ALERT * self.facing_x else: self.wait_timer = 60 # self.facing_x *= -1 self.velocity_x = 0 else: self.velocity_x = 0 # ACTION if self.slowed: self.attack_timer -= 0.25 else: self.attack_timer -= 1 if self.attack_timer <= 0 and player_visible: self.shoot(self.x, self.y, self.facing_x, self.facing_y) elif self.state == Soldier.STATE_STUNNED: self.stun_timer -= 1 if self.stun_timer <= 0: self.stun_timer = 0 self.state = Soldier.STATE_PATROL # GRAVITY if self.velocity_y < MAX_GRAVITY: self.velocity_y += GRAVITY # ADVANCE temp_x += self.velocity_x temp_y += self.velocity_y # FINALIZE c, self.x, self.y, self.velocity_x, self.velocity_y = \ collision_resolution(self, temp_x, temp_y) # Undo solid ladders for l in altered_ladders: l.solid = l._temp_soldier_solid del l._temp_soldier_solid
def update(self): temp_x = self.x temp_y = self.y has_solid_below = solid_below(self, self.x, self.y) # Key polling keydown_up = Key.down('up') keydown_down = Key.down('down') keydown_left = Key.down('left') keydown_right = Key.down('right') keydown_run = False # Key.down('lshift') keypressed_up = Key.pressed('up') keypressed_down = Key.pressed('down') keypressed_left = Key.pressed('left') keypressed_right = Key.pressed('right') keypressed_jump = Key.pressed('space') keypressed_gadget = Key.pressed('x') if self.state == Player.STATE_STANDARD: # Run/Walk if keydown_left == keydown_right: self.velocity_x = 0 self.walking_sound.stop() else: if keydown_left: if keydown_run: self.velocity_x = -Player.SPEED_FAST else: self.velocity_x = -Player.SPEED self.facing_x = -1 if keydown_right: if keydown_run: self.velocity_x = Player.SPEED_FAST else: self.velocity_x = Player.SPEED self.facing_x = 1 # Play walking sound effect if has_solid_below: self.walking_sound.play(-1) else: self.walking_sound.stop() # Push block block = peachy.collision.collides_group( self.container, 'block', self.at_point(temp_x + self.velocity_x, self.y)) if len(block) == 1 and has_solid_below: block = block[0] block_temp_x = block.x + self.velocity_x if not peachy.collision.collides_solid( self.container, block.at_point(block_temp_x, block.y)): self.change_state(Player.STATE_PUSHING, block=block) if self.x < block.x: self.x = block.x - self.width else: self.x = block.x + block.width return # Jump if keypressed_jump and has_solid_below: self.velocity_y = -Player.JUMP_FORCE # Wall Grab if self.velocity_y < 4 and self.velocity_y > 0: climb_wall = [] if keydown_left: climb_wall = solid_left(self, self.x, self.y) if keydown_right: climb_wall = solid_right(self, self.x, self.y) ledge = None for wall in climb_wall: if wall.y - self.y < 3 and not wall.member_of('block'): if self.y <= wall.y: ledge = wall else: ledge = None if ledge is not None: test = Rect(self.x, ledge.y - Player.HEIGHT_CROUCH, self.width, Player.HEIGHT_CROUCH) test.container = self.container if test.x + test.width <= ledge.x: test.x = ledge.x elif test.x >= ledge.x + ledge.width: test.x = ledge.x + ledge.width - test.width if not collides_solid(self.container, test): self.change_state(Player.STATE_LEDGEGRAB, ledge=ledge) return # Interact if keydown_up: interactables = collides_group(self.container, 'interact', self) for interact in interactables: if interact.member_of('rope'): vertical = False if interact.width == 0: vertical = True elif interact.height == 0: vertical = False self.change_state(Player.STATE_CLIMBING, handle=interact, vertical=vertical) interact.attach(self) return elif interact.member_of('ladder'): self.x = interact.x self.change_state(Player.STATE_CLIMBING, handle=interact, vertical=True) return elif keypressed_up: if interact.member_of('button'): interact.press() elif interact.member_of('door'): if self.gadget.state == gadgets.Gadget.STATE_ACTIVE: self.gadget.cancel() interact.enter() elif interact.member_of('lever'): interact.pull() elif interact.member_of('hiding-spot'): self.change_state(Player.STATE_HIDDEN, hiding_spot=interact) return elif interact.member_of('message-box'): interact.activate() return # Climb down ladder if keypressed_down: ladder = collides_group(self.container, 'ladder', self.at_point(self.x, self.y + 1)) if ladder: ladder = ladder[0] if self.y + self.height < ladder.y + ladder.height: self.x = ladder.x if self.y < ladder.y: self.y = ladder.y self.change_state(Player.STATE_CLIMBING, handle=ladder, vertical=True) return # Pickup if keypressed_up: pickups = collides_group(self.container, 'pickup', self) for pickup in pickups: if pickup.member_of('gadget'): self.change_gadget(pickup.gadget) elif pickup.member_of('key'): self.obtained_keys.append(pickup.tag) self.key_count += 1 pickup.destroy() # Crouching if keypressed_down and has_solid_below: self.change_state(Player.STATE_CROUCHING) return # Gravity if self.velocity_y < config.MAX_GRAVITY: self.velocity_y += config.GRAVITY elif self.state == Player.STATE_CLIMBING: if keypressed_jump: self.velocity_y = -Player.JUMP_FORCE self.change_state(Player.STATE_STANDARD) return handle = self.state_args['handle'] vertical = self.state_args['vertical'] if vertical: if keydown_up == keydown_down: self.velocity_y = 0 else: if keydown_up: if self.y > handle.y: self.velocity_y = -Player.SPEED_SLOW else: self.velocity_y = 0 if handle.member_of('ladder'): self.y = handle.y - self.height self.change_state(Player.STATE_STANDARD) return if keydown_down: if self.y + self.height < handle.y + handle.height: self.velocity_y = Player.SPEED_SLOW else: self.velocity_y = 0 self.change_state(Player.STATE_STANDARD) return else: if keypressed_down: self.change_state(Player.STATE_STANDARD) return if keydown_left == keydown_right: self.velocity_x = 0 else: if keydown_left: if self.x > handle.x: self.velocity_x = -Player.SPEED_SLOW else: self.velocity_x = 0 if keydown_right: if self.x + self.width < handle.x + handle.width: self.velocity_x = Player.SPEED_SLOW else: self.velocity_x = 0 elif self.state == Player.STATE_CROUCHING: if keydown_left == keydown_right: self.velocity_x = 0 else: if keydown_left: self.velocity_x = -Player.SPEED_SLOW self.facing_x = -1 if keydown_right: self.velocity_x = Player.SPEED_SLOW self.facing_x = 1 # attempt to grab ledge when crawling off one tx = self.velocity_x + self.x if not solid_below(self, tx, self.y): ledges = solid_below(self, self.x, self.y) try: ledge = ledges[0] if self.velocity_x > 0: test = Rect(ledge.x + ledge.width, ledge.y, self.width, Player.HEIGHT_STANDARD) else: test = Rect(ledge.x - self.width, ledge.y, self.width, Player.HEIGHT_STANDARD) test.container = self.container if not collides_solid(self.container, test): self.x = test.x self.facing_x *= -1 self.change_state(Player.STATE_LEDGEGRAB, ledge=ledge) return except IndexError: pass attempt_stand = False if keypressed_jump and has_solid_below: self.velocity_y = -Player.JUMP_FORCE attempt_stand = True if not keydown_down: attempt_stand = True if attempt_stand: self.height = Player.HEIGHT_STANDARD temp_y = self.y - \ abs(Player.HEIGHT_STANDARD - Player.HEIGHT_CROUCH) if collides_solid(self.container, self.at_point(self.x, temp_y)): self.height = Player.HEIGHT_CROUCH temp_y = self.y self.velocity_y = 0 else: self.state = Player.STATE_STANDARD self.y = temp_y self.height = Player.HEIGHT_STANDARD if collides_solid(self.container, self.at_point(temp_x, temp_y)): self.height = Player.HEIGHT_CROUCH else: self.state = Player.STATE_STANDARD elif self.state == Player.STATE_HIDDEN: if keypressed_up or keypressed_left or keypressed_right: self.change_state(Player.STATE_STANDARD) elif self.state == Player.STATE_LEDGEGRAB: # Climb up ledge if keypressed_up or keypressed_left or keypressed_right: ledges = None if keydown_up: try: ledges = solid_left(self, self.x, self.y) assert ledges[0].y == self.y except (AssertionError, IndexError): ledges = solid_right(self, self.x, self.y) elif keydown_left: ledges = solid_left(self, self.x, self.y) elif keydown_right: ledges = solid_right(self, self.x, self.y) try: ledge = ledges[0] assert ledge.y == self.y test = peachy.geo.Rect(self.x, ledge.y - Player.HEIGHT_CROUCH, self.width, Player.HEIGHT_CROUCH) test.container = self.container if test.x + test.width <= ledge.x: test.x = ledge.x elif test.x >= ledge.x + ledge.width: test.x = ledge.x + ledge.width - test.width if not collides_solid(self.container, test): self.change_state(Player.STATE_CROUCHING) self.x = test.x self.y = test.y return except (AssertionError, IndexError): pass # Let go of ledge if keypressed_left and not solid_left(self, self.x, self.y) or \ keypressed_right and not solid_right(self, self.x, self.y) or \ keypressed_down: self.state = Player.STATE_STANDARD if keypressed_jump: self.state = Player.STATE_STANDARD self.velocity_y = -Player.JUMP_FORCE elif self.state == Player.STATE_PUSHING: block = self.state_args['block'] if self.x > block.x and keydown_left: self.velocity_x = -Player.SPEED_SLOW elif self.x < block.x and keydown_right: self.velocity_x = Player.SPEED_SLOW else: self.change_state(Player.STATE_STANDARD) return if keypressed_jump: self.velocity_y = -Player.JUMP_FORCE self.change_state(Player.STATE_STANDARD) return test_x = temp_x + self.velocity_x if not rect_rect(self.at_point(test_x, self.y), block): self.change_state(Player.STATE_STANDARD) return block_temp_x = block.x + self.velocity_x if not collides_solid(self.container, block.at_point(block_temp_x, block.y)): block.x = block_temp_x # GADGET if self.state != Player.STATE_DEAD: if keypressed_gadget and self.gadget.name: self.gadget.use() # ADVANCE temp_x += self.velocity_x temp_y += self.velocity_y # LOCKED DOOR lock = collides_group(self.container, 'locked-door', self.at_point(temp_x, temp_y)) if lock: lock = lock[0] if self.key_count > 0: self.key_count -= 1 self.container.unlocked_doors.append(lock.tag) lock.destroy() # FINALIZE c, self.x, self.y, self.velocity_x, self.velocity_y = \ collision_resolution(self, temp_x, temp_y) self.gadget.update()