Player Script :
extends CharacterBody2D
enum PlayerState {
IDLE,
WALK,
WALL_JUMP,
WALL_SLIDE,
CLIMB,
}
@export var movement_data : PlayerMovementData
@onready var dash = $Dash
@onready var animated_sprite_2d = $AnimatedSprite2D
@onready var timer = $Timer
@onready var starting_position = global_position
@onready var wall_jump_timer = $WallJumpTimer
@onready var wall_slide_timer = $WallSlideTimer
@onready var wallslide = $wallslide
@onready var laddercheck = $LadderCheck
const GRAVITY := 600
const FALL_GRAVITY := 900
const DASH_SPEED = 450
const DASH_LENGTH = 0.1
const wall_jump_pushback = 1500
const wall_slide_gravity = 10
var state = PlayerState.IDLE
var on_ladder:bool = false
var health = 100
var health_max = 100
var health_min = 0
var can_dash = true
var dashing = false
var air_jump = false
var is_wall_sliding = false
var just_wall_jumped = false
var was_wall_normal = Vector2.ZERO
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
func _ready():
Events.playerBody = self
#on_ladder = false
func get_gravity(velocity: Vector2):
if velocity.y < 0:
return GRAVITY
return FALL_GRAVITY
func _physics_process(delta):
match state:
PlayerState.IDLE:
handle_idle_state(delta)
PlayerState.WALK:
handle_walk_state(delta)
PlayerState.WALL_JUMP:
handle_wall_jump_state(delta)
PlayerState.WALL_SLIDE:
handle_wall_slide_state(delta)
PlayerState.CLIMB:
handle_climb_state(delta)
#if is_on_ladder():
if not is_on_floor():
velocity.y += get_gravity(velocity) * delta
if Input.is_action_just_released("ui_up") and velocity.y < 0:
velocity.y = movement_data.jump_velocity / 4
#apply_gravity(delta)
handle_jump()
wall_slide(delta)
handle_wall_jump()
handle_dash()
var input_axis = Input.get_axis("ui_left", "ui_right")
handle_acceleration(input_axis, delta)
handle_air_acceleraion(input_axis, delta)
apply_friction(input_axis, delta)
apply_air_resistance(input_axis, delta)
update_animations(input_axis)
var was_on_floor = is_on_floor()
var was_on_wall = is_on_wall_only()
if was_on_wall:
was_wall_normal = get_wall_normal()
move_and_slide()
var just_left_ledge = was_on_floor and not is_on_floor() and velocity.y >= 0
if just_left_ledge:
timer.start()
just_wall_jumped = false
var just_left_wall = was_on_wall and not is_on_wall()
if just_left_wall:
wall_jump_timer.start()
if input_axis:
if dashing:
velocity.x = input_axis * DASH_SPEED
else:
velocity.x = input_axis * movement_data.speed
func is_on_ladder():
if not laddercheck.is_colliding(): return false
var collider = laddercheck.get_collider()
if not collider is Ladder: return false
return true
func _input(event : InputEvent):
if(event.is_action_pressed("ui_down") && is_on_floor()):
position.y += 1
func handle_idle_state(_delta):
return
func handle_walk_state(_delta):
return
func handle_wall_jump_state(_delta):
return
func handle_wall_slide_state(_delta):
return
func handle_climb_state(_delta):
return
#func apply_gravity(delta):
#if !is_on_floor():
#velocity.y += gravity * movement_data.gravity_scale * delta
#
func handle_dash():
if Input.is_action_just_pressed("dash") and can_dash and !is_on_wall:
dashing = true
can_dash = false
$dash_timer.start()
$dash_again_timer.start()
func handle_wall_jump():
if not is_on_wall_only() and wall_jump_timer.time_left <= 0.0: return
var wall_normal = get_wall_normal()
if wall_jump_timer.time_left > 0.0:
wall_normal = was_wall_normal
if Input.is_action_just_pressed("ui_up"):
velocity.x = wall_normal.x * movement_data.speed
velocity.y = movement_data.jump_velocity
just_wall_jumped = true
if Input.is_action_just_pressed("ui_up") and wall_normal == Vector2.RIGHT:
velocity.x = wall_normal.x * movement_data.speed
velocity.y = movement_data.jump_velocity
func wall_slide(delta):
if is_on_wall() and !is_on_floor():
if Input.is_action_pressed("ui_left") or Input.is_action_pressed("ui_right"):
is_wall_sliding = true
else:
is_wall_sliding = false
if is_wall_sliding:
velocity.y += (wall_slide_gravity * delta)
velocity.y = min(velocity.y, wall_slide_gravity)
func handle_jump():
if is_on_floor(): air_jump = true
if is_on_floor() or timer.time_left > 0.0:
if Input.is_action_just_pressed("ui_up"):
velocity.y = movement_data.jump_velocity
timer.stop()
elif not is_on_floor():
if Input.is_action_just_released("ui_up") and velocity.y < movement_data.jump_velocity / 2:
velocity.y = movement_data.jump_velocity / 2
if Input.is_action_just_pressed("ui_up") and air_jump and not just_wall_jumped:
velocity.y = movement_data.jump_velocity * 0.8
air_jump = false
func handle_acceleration(input_axis, delta):
if not is_on_floor() : return
if input_axis:
velocity.x = move_toward(velocity.x, movement_data.speed * input_axis, movement_data.acceleration * delta)
func handle_air_acceleraion(input_axis, delta):
if is_on_floor(): return
if input_axis != 0:
velocity.x = move_toward(velocity.x, movement_data.speed * input_axis, movement_data.air_acceleration * delta)
func apply_friction(input_axis, delta):
if input_axis == 0 and is_on_floor():
velocity.x = move_toward(velocity.x, 0, movement_data.friction * delta)
func apply_air_resistance(input_axis, delta):
if input_axis == 0 and not is_on_floor():
velocity.x = move_toward(velocity.x, 0, movement_data.air_resistance * delta)
func update_animations(input_axis):
if input_axis != 0:
animated_sprite_2d.flip_h = (input_axis < 0)
animated_sprite_2d.play("run")
else:
animated_sprite_2d.play("idle")
if not is_on_floor():
animated_sprite_2d.play("jump")
func _on_hazard_detector_area_entered(_area):
global_position = starting_position
func _on_dash_timer_timeout():
dashing = false
func _on_dash_again_timer_timeout():
can_dash = true

Player Movement Script :
class_name PlayerMovementData
extends Resource
@export var speed = 100.0
@export var acceleration = 800
@export var friction = 1000.0
@export var jump_velocity = -300.0
@export var gravity_scale = 1.0
@export var air_resistance = 200.0
@export var air_acceleration = 400.0
Boomerang Weapon Script :
extends Node2D
enum {IDLE, FLY, STICK}
@export var throw_speed = 2 * 60
@onready var parent: = get_parent()
var state: int = IDLE
var velocity: = Vector2.ZERO
var pos: = Vector2.ZERO
var spin_speed: float = 4*360
var player
#func _ready()->void:
#idle_position()
func _physics_process(delta):
match state:
IDLE:
idle()
FLY:
fly(delta)
STICK:
stick(delta)
func idle()->void:
look_at(get_global_mouse_position())
if Input.is_action_just_pressed("Click"):
throw()
func fly(delta:float)->void:
pos += velocity*delta #variable for disconnecting from parent movement
global_position = pos
#spin
rotation_degrees += spin_speed*delta
func stick(delta:float)->void:
#place for your solution
var target: = get_target()
var dist = global_position.distance_to(target)
if dist < throw_speed * delta:
idle_position()
else:
pos = pos.lerp(target, (throw_speed * delta)/dist)
global_position = pos
#spin
rotation_degrees += spin_speed*delta
func throw()->void:
state = FLY
$Timer.start()
velocity = (get_global_mouse_position() - global_position).normalized() * throw_speed
pos = global_position #variable for disconnecting from parent movement
func idle_position()->void:
state = IDLE
global_position = get_target()
func get_target()->Vector2:
return parent.global_position + Vector2(0,-2)
#func _on_Timer_timeout()->void:
#state = STICK
func _on_timer_timeout()->void:
state = STICK
ALSO : there is like 3 different functions that handle fall acceleration after jump but it should be only one…