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 var last_contacted_map_elem_type : int = Constants.MapElemType.SQUARE var boost : float = 0 # to movement speed 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): set_current_action(Constants.UnitCurrentAction.SPINNING) boost += boost_per_second * delta 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) 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 process_unit(delta, time_elapsed : float): # always be movin' facing = Constants.Direction.RIGHT actions[Constants.ActionType.MOVE] = true # Check if fallen off if last_contacted_map_elem_type == Constants.MapElemType.OOB_LOWER: oob_lower() # Fine tune the player's speed 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) # 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(): if get_current_action() == Constants.UnitCurrentAction.SPINNING: hit(Constants.Direction.RIGHT) boost = 0 return target_move_speed += boost boost = 0 func 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 pos = tile pos.x += 0.5 pos.y *= -1 last_contacted_map_elem_type = Constants.MapElemType.SLOPE_LEFT # ======================= # reset speed # should other things be done here? h_speed = 0