256 lines
9.8 KiB
GDScript
256 lines
9.8 KiB
GDScript
extends Player
|
|
|
|
class_name DownhillAutoscrollerPlayer
|
|
|
|
export var min_speed : float = 3
|
|
export var max_speed : float = 11
|
|
export var player_initiated_acceleration : float = 5
|
|
export var boost_per_second : float = 6 / 1.36 # 6 mph
|
|
|
|
var last_contacted_map_elem_type : int = Constants.MapElemType.SQUARE
|
|
|
|
var boost : float = 0 # to movement speed
|
|
|
|
var respawn_pos : Vector2
|
|
|
|
var hit_audiostream_player : AudioStreamPlayer
|
|
var spin_audiostream_player : AudioStreamPlayer
|
|
var jump_audiostream_player : AudioStreamPlayer
|
|
var land_audiostream_player : AudioStreamPlayer
|
|
var snow_audiostream_player : AudioStreamPlayer
|
|
|
|
func init_unit_w_scene(scene):
|
|
.init_unit_w_scene(scene)
|
|
hit_audiostream_player = scene.get_node("HitAudioStreamPlayer")
|
|
spin_audiostream_player = scene.get_node("SpinAudioStreamPlayer")
|
|
jump_audiostream_player = scene.get_node("JumpAudioStreamPlayer")
|
|
land_audiostream_player = scene.get_node("LandAudioStreamPlayer")
|
|
snow_audiostream_player = scene.get_node("SnowAudioStreamPlayer")
|
|
|
|
func execute_actions(delta):
|
|
.execute_actions(delta)
|
|
for action_num in Constants.UNIT_TYPE_ACTIONS[Constants.UnitType.PLAYER]:
|
|
if !actions[action_num]:
|
|
continue
|
|
match action_num:
|
|
# handle custom actions
|
|
Constants.ActionType.SPIN:
|
|
spin(delta)
|
|
_:
|
|
pass
|
|
|
|
func spin(delta):
|
|
if (get_current_action() != Constants.UnitCurrentAction.SPINNING):
|
|
spin_audiostream_player.play()
|
|
set_current_action(Constants.UnitCurrentAction.SPINNING)
|
|
boost += boost_per_second * delta
|
|
current_sprite.visible = false
|
|
get_node("SpinningSprite").visible = true
|
|
get_node("SpinningSprite").rotation += delta * 32
|
|
|
|
func move():
|
|
set_unit_condition(Constants.UnitCondition.MOVING_STATUS, Constants.UnitMovingStatus.MOVING)
|
|
if (get_current_action() == Constants.UnitCurrentAction.IDLE
|
|
and unit_conditions[Constants.UnitCondition.IS_ON_GROUND]):
|
|
if last_contacted_map_elem_type == Constants.MapElemType.SQUARE:
|
|
set_sprite(Constants.SpriteClass.WALK, 0)
|
|
elif (last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_RIGHT_1
|
|
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_RIGHT_2):
|
|
set_sprite(Constants.SpriteClass.WALK, 1)
|
|
elif last_contacted_map_elem_type == Constants.MapElemType.SLOPE_RIGHT:
|
|
set_sprite(Constants.SpriteClass.WALK, 2)
|
|
elif (last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_1
|
|
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_2):
|
|
set_sprite(Constants.SpriteClass.WALK, 3)
|
|
elif last_contacted_map_elem_type == Constants.MapElemType.SLOPE_LEFT:
|
|
set_sprite(Constants.SpriteClass.WALK, 4)
|
|
|
|
func jump():
|
|
if get_current_action() != Constants.UnitCurrentAction.JUMPING:
|
|
jump_audiostream_player.play()
|
|
.jump()
|
|
|
|
func reset_current_action():
|
|
.reset_current_action()
|
|
if get_current_action() == Constants.UnitCurrentAction.SPINNING:
|
|
if not actions[Constants.ActionType.SPIN]:
|
|
set_current_action(Constants.UnitCurrentAction.IDLE)
|
|
get_node("SpinningSprite").visible = false
|
|
get_node("SpinningSprite").rotation = 0
|
|
.handle_idle()
|
|
current_sprite.visible = true
|
|
else:
|
|
spin_audiostream_player.stop()
|
|
|
|
func custom_inputs():
|
|
if scene.input_table[Constants.PlayerInput.GBA_B][scene.I_T_JUST_PRESSED]:
|
|
if not get_condition(Constants.UnitCondition.IS_ON_GROUND, true):
|
|
set_action(Constants.ActionType.SPIN)
|
|
if (get_current_action() == Constants.UnitCurrentAction.SPINNING
|
|
and scene.input_table[Constants.PlayerInput.GBA_B][scene.I_T_PRESSED]):
|
|
set_action(Constants.ActionType.SPIN)
|
|
|
|
func handle_idle():
|
|
if boost == 0:
|
|
.handle_idle()
|
|
|
|
func process_unit(delta, time_elapsed : float):
|
|
# always be movin'
|
|
facing = Constants.Direction.RIGHT
|
|
actions[Constants.ActionType.MOVE] = true
|
|
|
|
# Fine tune the player's speed
|
|
|
|
print(last_contacted_map_elem_type)
|
|
|
|
if get_current_action() == Constants.UnitCurrentAction.RECOILING:
|
|
target_move_speed = min_speed
|
|
else:
|
|
# override player input so that leftward movement is deceleration,
|
|
# right movement is acceleration
|
|
if scene.input_table[Constants.PlayerInput.LEFT][scene.I_T_PRESSED]:
|
|
target_move_speed = move_toward(target_move_speed, min_speed, player_initiated_acceleration * delta)
|
|
else:
|
|
if not get_condition(Constants.UnitCondition.IS_ON_GROUND, true):
|
|
if (target_move_speed < Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type]
|
|
and scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED]):
|
|
target_move_speed = move_toward(target_move_speed, Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type], player_initiated_acceleration * delta)
|
|
if target_move_speed > max_speed:
|
|
target_move_speed = move_toward(target_move_speed, max_speed, player_initiated_acceleration * delta)
|
|
else:
|
|
# shallow slope: arctan(.5) = 27 degrees, sin(27) = 0.45
|
|
# steep slope: sin(45) = 0.71
|
|
var ground_influenced_acceleration = 0
|
|
var is_decel : bool = false
|
|
if (last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_RIGHT_1
|
|
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_RIGHT_2
|
|
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_1
|
|
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_2):
|
|
ground_influenced_acceleration = Constants.GRAVITY * 0.45
|
|
if (last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_1
|
|
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_2):
|
|
is_decel = true
|
|
elif (last_contacted_map_elem_type == Constants.MapElemType.SLOPE_RIGHT
|
|
or last_contacted_map_elem_type == Constants.MapElemType.SLOPE_LEFT):
|
|
ground_influenced_acceleration = Constants.GRAVITY * 0.71
|
|
if last_contacted_map_elem_type == Constants.MapElemType.SLOPE_LEFT:
|
|
is_decel = true
|
|
if is_decel or ground_influenced_acceleration == 0:
|
|
var end_speed
|
|
if ground_influenced_acceleration == 0:
|
|
# flat ground
|
|
if scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED]:
|
|
end_speed = max(min(target_move_speed, max_speed), Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type])
|
|
else:
|
|
end_speed = min(target_move_speed, max_speed)
|
|
else:
|
|
# incline
|
|
if scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED]:
|
|
end_speed = Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type]
|
|
else:
|
|
end_speed = min_speed
|
|
if target_move_speed < end_speed:
|
|
target_move_speed = move_toward(target_move_speed, end_speed, player_initiated_acceleration * delta)
|
|
else:
|
|
if ground_influenced_acceleration > 0:
|
|
target_move_speed = move_toward(target_move_speed, end_speed, ground_influenced_acceleration * delta)
|
|
else:
|
|
target_move_speed = move_toward(target_move_speed, end_speed, player_initiated_acceleration * delta)
|
|
else:
|
|
var acceleration = ground_influenced_acceleration
|
|
if scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED]:
|
|
acceleration = max(acceleration, player_initiated_acceleration)
|
|
if target_move_speed < max_speed:
|
|
target_move_speed = move_toward(target_move_speed, max_speed, acceleration * delta)
|
|
else:
|
|
target_move_speed = move_toward(target_move_speed, max_speed, player_initiated_acceleration * delta)
|
|
|
|
.process_unit(delta, time_elapsed)
|
|
|
|
# treat all collisions as right-side collisions
|
|
func hit(dir : int):
|
|
# Unit.gd implementation override
|
|
hit_queued = true
|
|
hit_dir = Constants.Direction.RIGHT
|
|
|
|
# Player.gd implementation
|
|
set_unit_condition_with_timer(Constants.UnitCondition.IS_INVINCIBLE)
|
|
start_flash()
|
|
set_action(Constants.ActionType.RECOIL)
|
|
set_current_action(Constants.UnitCurrentAction.RECOILING)
|
|
set_unit_condition(Constants.UnitCondition.MOVING_STATUS, Constants.UnitMovingStatus.IDLE)
|
|
|
|
get_node("SpinningSprite").visible = false
|
|
get_node("SpinningSprite").rotation = 0
|
|
|
|
hit_audiostream_player.play()
|
|
|
|
# override super class's RECOIL_PUSHBACK
|
|
func handle_recoil():
|
|
if not hit_queued:
|
|
return
|
|
hit_queued = false
|
|
# skip recoil pushback logic, since target_move_speed is already
|
|
# set to min_speed
|
|
|
|
func landed():
|
|
get_node("SpinningSprite").visible = false
|
|
get_node("SpinningSprite").rotation = 0
|
|
land_audiostream_player.play()
|
|
if get_current_action() == Constants.UnitCurrentAction.SPINNING:
|
|
hit(Constants.Direction.RIGHT)
|
|
boost = 0
|
|
spin_audiostream_player.stop()
|
|
return
|
|
if boost > 0:
|
|
scene.find_node("CanvasLayer").flash_boost = true
|
|
h_speed += boost
|
|
target_move_speed = h_speed
|
|
boost = 0
|
|
|
|
func react(delta):
|
|
.react(delta)
|
|
|
|
# Check if fallen off
|
|
if last_contacted_map_elem_type == Constants.MapElemType.OOB_LOWER:
|
|
# Called when the player falls in a hole
|
|
|
|
# Calculate respawn point
|
|
var tilemap : TileMap = get_node("../Stage")
|
|
var tile : Vector2 = pos.floor()
|
|
tile.y *= -1
|
|
while tilemap.get_cellv(tile) == 22 or tilemap.get_cellv(tile) < 0:
|
|
tile += Vector2.RIGHT
|
|
while tilemap.get_cellv(tile) >= 0:
|
|
tile += Vector2.UP
|
|
respawn_pos = tile
|
|
respawn_pos.x += 0.5
|
|
respawn_pos.y *= -1
|
|
last_contacted_map_elem_type = Constants.MapElemType.SLOPE_LEFT
|
|
# =======================
|
|
|
|
# reset speed
|
|
# should other things be done here?
|
|
# - player's ongoing trick has to be reset
|
|
# - camera has to freeze its y position as player drops offscreen
|
|
# - a smooth transition has to play
|
|
# - player starts off recoiling and slowed down (they are hit)
|
|
var spectator_cam : Camera2D = get_node("../SpectatorCam")
|
|
spectator_cam.position = get_node("Camera2D").get_camera_screen_center()
|
|
spectator_cam.offset = get_node("Camera2D").offset
|
|
spectator_cam.make_current()
|
|
var anim_player : AnimationPlayer = scene.find_node("PitTransitionPlayer")
|
|
anim_player.play("PitTransition")
|
|
if get_condition(Constants.UnitCondition.IS_ON_GROUND, true) and h_speed > 3:
|
|
if not snow_audiostream_player.playing:
|
|
snow_audiostream_player.play()
|
|
else:
|
|
snow_audiostream_player.stop()
|
|
|
|
func respawn_from_pit():
|
|
pos = respawn_pos
|
|
hit(Constants.Direction.RIGHT)
|
|
boost = 0
|
|
get_node("Camera2D").make_current()
|
|
|