RapidGameFramework
Reusable Godot managers for data-driven small games
Loading...
Searching...
No Matches
character_controller_2d.gd
Go to the documentation of this file.
1extends RefCounted
2
3
10
11const DEFAULT_CONFIG := {
12 "run_speed": 180.0,
13 "acceleration": 1200.0,
14 "deceleration": 1600.0,
15 "gravity": 980.0,
16 "max_fall_speed": 520.0,
17 "jump_velocity": -340.0,
18 "coyote_time": 0.09,
19 "jump_buffer": 0.10,
20 "dash_speed": 420.0,
21 "dash_time": 0.12,
22 "dash_cooldown": 0.35
23}
24
25
26
27func create_state() -> Dictionary:
28 return {
29 "velocity": Vector2.ZERO,
30 "facing": 1,
31 "coyote_left": 0.0,
32 "jump_buffer_left": 0.0,
33 "dash_left": 0.0,
34 "dash_cooldown_left": 0.0,
35 "state": "idle"
36 }
37
38
39
41func step(state:Dictionary, input:Dictionary, delta:float, on_floor:bool, config:Dictionary = {}) -> Dictionary:
42 var settings = DEFAULT_CONFIG.duplicate(true)
43 for key in config.keys():
44 settings[key] = config[key]
45 var next = state.duplicate(true)
46 var velocity = next.get("velocity", Vector2.ZERO)
47 var move = clamp(float(input.get("move", 0.0)), -1.0, 1.0)
48 if abs(move) > 0.01:
49 next["facing"] = sign(move)
50 velocity.x = move_toward(velocity.x, move * float(settings["run_speed"]), float(settings["acceleration"]) * delta)
51 else:
52 velocity.x = move_toward(velocity.x, 0.0, float(settings["deceleration"]) * delta)
53 next["coyote_left"] = float(settings["coyote_time"]) if on_floor else max(0.0, float(next.get("coyote_left", 0.0)) - delta)
54 next["jump_buffer_left"] = float(settings["jump_buffer"]) if bool(input.get("jump_pressed", false)) else max(0.0, float(next.get("jump_buffer_left", 0.0)) - delta)
55 next["dash_cooldown_left"] = max(0.0, float(next.get("dash_cooldown_left", 0.0)) - delta)
56 if bool(input.get("dash_pressed", false)) and float(next.get("dash_cooldown_left", 0.0)) <= 0.0:
57 next["dash_left"] = float(settings["dash_time"])
58 next["dash_cooldown_left"] = float(settings["dash_cooldown"])
59 if float(next.get("dash_left", 0.0)) > 0.0:
60 next["dash_left"] = max(0.0, float(next["dash_left"]) - delta)
61 velocity = Vector2(float(next.get("facing", 1)) * float(settings["dash_speed"]), 0)
62 next["state"] = "dash"
63 else:
64 if float(next.get("jump_buffer_left", 0.0)) > 0.0 and float(next.get("coyote_left", 0.0)) > 0.0:
65 velocity.y = float(settings["jump_velocity"])
66 next["jump_buffer_left"] = 0.0
67 next["coyote_left"] = 0.0
68 else:
69 velocity.y = min(float(settings["max_fall_speed"]), velocity.y + float(settings["gravity"]) * delta)
70 next["state"] = _resolve_state(move, on_floor, velocity)
71 next["velocity"] = velocity
72 return next
73
74
75func _resolve_state(move:float, on_floor:bool, velocity:Vector2) -> String:
76 if not on_floor:
77 return "jump" if velocity.y < 0.0 else "fall"
78 if abs(move) > 0.01:
79 return "run"
80 return "idle"