Jam10/Scripts/Units/DownhillAutoscrollerPlayer.gd

246 lines
8.2 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 = 4 / 1.36 # 6 mph
var last_contacted_map_elem_type : int = Constants.MapElemType.SQUARE
var boost : float = 0 # to movement speed
var boost_effect: float = 0
var instant_accel: bool = false
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 handle_speed(delta):
if get_current_action() == Constants.UnitCurrentAction.RECOILING:
target_move_speed = min_speed
return
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)
boost_effect = 0.0
return
var slope: int = Constants.ELEM_TYPE_SLOPE[last_contacted_map_elem_type]
var speed_limit: float = Constants.SLOPE_SPEED[slope]
var accel: float = player_initiated_acceleration
if not get_condition(Constants.UnitCondition.IS_ON_GROUND, true):
speed_limit = target_move_speed
if scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED] and speed_limit < Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type]:
speed_limit = Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type]
speed_limit = max(min_speed, speed_limit)
if get_condition(Constants.UnitCondition.IS_ON_GROUND, true):
if scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED]:
speed_limit += 1.0
if boost_effect > 0:
speed_limit += boost_effect
if target_move_speed < boost_effect:
boost_effect = 0.0
elif slope < 2:
boost_effect -= delta
accel = (Constants.SLOPE_ACCEL if target_move_speed < speed_limit else Constants.SLOPE_DECEL)[slope]
target_move_speed = move_toward(target_move_speed, speed_limit, accel * delta)
if target_move_speed > speed_limit + 4.0:
target_move_speed -= speed_limit
target_move_speed *= pow(0.5, delta)
target_move_speed += speed_limit
func process_unit(delta, time_elapsed : float):
# always be movin'
facing = Constants.Direction.RIGHT
actions[Constants.ActionType.MOVE] = true
handle_speed(delta)
if boost_effect > 0:
boost_effect -= 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
boost_effect += boost
target_move_speed += boost
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)
set_unit_condition_with_timer(Constants.UnitCondition.IS_INVINCIBLE)
start_flash()
get_node("SpinningSprite").visible = false
get_node("SpinningSprite").rotation = 0
hit_audiostream_player.play()
boost = 0
boost_effect = 0
get_node("Camera2D").make_current()