142 lines
4.8 KiB
Python
142 lines
4.8 KiB
Python
|
|
import math, random
|
|
|
|
from game_object import GameObject
|
|
from game_util_objects import StaticTileBG, Player, Character, WarpTrigger
|
|
from collision import CST_AABB
|
|
|
|
class PlatformWorld(StaticTileBG):
|
|
draw_col_layer = True
|
|
|
|
class PlatformPlayer(Player):
|
|
|
|
# from http://www.piratehearts.com/blog/2010/08/30/40/:
|
|
# JumpSpeed = sqrt(2.0f * Gravity * JumpHeight);
|
|
|
|
art_src = 'player'
|
|
#collision_shape_type = CST_AABB
|
|
col_width = 2
|
|
col_height = 3
|
|
handle_key_events = True
|
|
fast_move_steps = 1
|
|
col_radius = 1.75
|
|
move_accel_x = 400
|
|
move_accel_y = 2500
|
|
ground_friction = 20
|
|
air_friction = 15
|
|
max_jump_press_time = 0.15
|
|
editable = Player.editable + ['max_jump_press_time']
|
|
jump_key = 'x'
|
|
|
|
def __init__(self, world, obj_data=None):
|
|
Player.__init__(self, world, obj_data)
|
|
self.jump_time = 0
|
|
# don't jump again until jump is released and pressed again
|
|
self.jump_ready = True
|
|
self.started_jump = False
|
|
|
|
def started_colliding(self, other):
|
|
Player.started_colliding(self, other)
|
|
if isinstance(other, PlatformMonster):
|
|
# landing atop monster?
|
|
dx, dy = other.x - self.x, other.y - self.y
|
|
if abs(dy) > abs(dx) and dy < -1:
|
|
other.destroy()
|
|
|
|
def is_affected_by_gravity(self):
|
|
return True
|
|
|
|
def handle_key_down(self, key, shift_pressed, alt_pressed, ctrl_pressed):
|
|
if key == self.jump_key and self.jump_ready:
|
|
self.jump()
|
|
self.jump_ready = False
|
|
self.started_jump = True
|
|
|
|
def handle_key_up(self, key, shift_pressed, alt_pressed, ctrl_pressed):
|
|
if key == self.jump_key:
|
|
self.jump_ready = True
|
|
|
|
def allow_move_y(self, dy):
|
|
# disable regular up/down movement, jump button sets move_y directly
|
|
return False
|
|
|
|
def update_state(self):
|
|
self.state = 'stand' if self.is_on_ground() and (self.move_x, self.move_y) == (0, 0) else 'walk'
|
|
|
|
def moved_this_frame(self):
|
|
delta = math.sqrt(abs(self.last_x - self.x) ** 2 + abs(self.last_y - self.y) ** 2 + abs(self.last_z - self.z) ** 2)
|
|
return delta > self.stop_velocity
|
|
|
|
def is_on_ground(self):
|
|
# works for now: just check for -Y contact with first world object
|
|
ground = self.world.get_first_object_of_type('PlatformWorld')
|
|
contact = self.collision.contacts.get(ground.name, None)
|
|
if not contact:
|
|
return False
|
|
return contact.overlap.y < 0
|
|
|
|
def jump(self):
|
|
self.jump_time += self.get_time_since_last_update() / 1000
|
|
if self.jump_time < self.max_jump_press_time:
|
|
self.move_y += 1
|
|
|
|
def update(self):
|
|
on_ground = self.is_on_ground()
|
|
if on_ground and self.jump_time > 0:
|
|
self.jump_time = 0
|
|
# poll jump key for variable length jump
|
|
if self.world.app.il.is_key_pressed(self.jump_key) and \
|
|
(self.started_jump or not on_ground):
|
|
self.jump()
|
|
self.started_jump = False
|
|
Player.update(self)
|
|
# wobble as we walk a la ELC2
|
|
if self.state == 'walk' and on_ground:
|
|
self.y += math.sin(self.world.app.updates) / 5
|
|
|
|
class PlatformMonster(Character):
|
|
art_src = 'monster'
|
|
move_state = 'stand'
|
|
animating = True
|
|
fast_move_steps = 2
|
|
move_accel_x = 100
|
|
col_radius = 1
|
|
|
|
def pre_first_update(self):
|
|
# pick random starting direction
|
|
self.move_dir_x = random.choice([-1, 1])
|
|
self.set_timer_function('hit_wall', self.check_wall_hits, 0.2)
|
|
|
|
def is_affected_by_gravity(self):
|
|
return True
|
|
|
|
def allow_move_y(self, dy):
|
|
return False
|
|
|
|
def check_wall_hits(self):
|
|
"Turn around if a wall is immediately ahead of direction we're moving."
|
|
# check collision in direction we're moving
|
|
margin = 0.1
|
|
if self.move_dir_x > 0:
|
|
x = self.x + self.col_radius + margin
|
|
else:
|
|
x = self.x - self.col_radius - margin
|
|
y = self.y
|
|
# DEBUG see trace destination
|
|
#lines = [(self.x, self.y, 0), (x, y, 0)]
|
|
#self.app.debug_line_renderable.set_lines(lines)
|
|
hits, shapes = self.world.get_colliders_at_point(x, y,
|
|
#include_object_names=[],
|
|
include_class_names=['PlatformWorld',
|
|
'PlatformMonster'],
|
|
exclude_object_names=[self.name])
|
|
if len(hits) > 0:
|
|
self.move_dir_x = -self.move_dir_x
|
|
|
|
def update(self):
|
|
self.move(self.move_dir_x, 0)
|
|
Character.update(self)
|
|
|
|
|
|
class PlatformWarpTrigger(WarpTrigger):
|
|
warp_class_names = ['Player', 'PlatformMonster']
|