Godot Version
Godot 4.4
Question
I want dash logic that results in a quick dash that does not allow you to change direction while dashing.
After trying several approaches, I settled for a “dashing manager” node with the following logic.
@export var target:PhysicsBody2D
func _physics_process(_delta: float) -> void:
if not target: return
if target is CharacterBody2D and dash_vector != Vector2.ZERO:
target.velocity = dash_vector
func dash(dash_sp:float , direction:Vector2, time:float = 0.1):
dash_vector = direction.normalized() * dash_sp
var dash_tween = create_tween()
dash_tween.finished.connect(func():dash_finished.emit())
dash_tween.tween_property(self,"dash_vector",Vector2.ZERO,time)
Essentially, when the dash function is executed, the target’s velocity gets overwritten to be dash_vector and that dash vector is tweened so that it ends up in 0 after a while. There’s a lot of omitted logic to make sure two dashes don’t happen at the same time, cooldowns, etc.
However, it feels kind of wrong, and in order to dash without changing direction midways i have to overwrite velocity so other applied forces such as knockback (which has a similar logic) are ignored.
What do you think of this approach? I think for now I’m fine with it but I want to make sure I am not committing any crime and see other implementations
Nothing strikes me as wrong about how you are making the character dash.
I think you might be well served by using a finite state machine, with DASHING as one of the states. That way you could disable directional input while in that state, then re-enable that input when you leave the state.
1 Like
I had thought of that, but with my current implementation it would mean too much boilerplate. My objective is to build a library, and these things need to be as modular and independent as possible, so I don’t like depending on state machines, but if I build a “characterController” and make this module dependent on it, I could use the state machine in a clean way.
Thanks for replying!!
Finite state machines can be very flexible. I have one in my character class where each state is paired with a lambda. This makes it very easy to change, as well as makes it easy to define a common set of behaviors. There is no boilerplate because I just need to define states for what a character does differently than other characters.
I firmly believe in libraries as well. Modular, independent, code is so much easier to modify and maintain. I just like state machines as the framework for calling those modules.
As an example, here is my default state when an enemy is looking for the player:
var seeking = func() -> void:
look_at_player()
pursue()
While I respect that in your code base you need to do what works best for you, I think state machines are an awesome tool for controlling code flow and worth the effort to implement.
Yeah, I really like state machines as well, and was thinking about making a state machine library based on xstate. All my characters have one, I just wanted to build a “dash_node” that provided that function to characterBodies without Including any logic inside a character body related to dashing (aside from the function call) I know it sounds silly, I just was (am) really fixated on that concept.
Not that my implementation works bad, it actually gets the job done, the only problem I have found for now is that if hit while dashing, there will be no knockback, but I think that can be fixed by adding a dash cancel on the hit event or something like that.