derkork / godot-statecharts

A state charts extension for Godot 4
MIT License
679 stars 33 forks source link

How to handle input events #125

Closed nik-lampe closed 1 month ago

nik-lampe commented 1 month ago

This is not an "issue", but rather a question on how to accomplish something.

I was following this tutorial on a card dragging mechanism and wanted to build it with this extension.

Here is the video at one of the relevant time stamps. https://youtu.be/Pa0P1lUoC-M?t=1195 You don't need to watch the video, it's just for reference in case I am not able to make my point clear. :)

So, in the video the input events from the root node (in this case a control node) are passed to the current state, and then handled in the code of the different states.

Now I'm not sure, what is the right way to do something like this with godot-statecharts.

There is a signal state_input, which I guess I should use. But as this is triggered by all events happening, it's not as trivial to check if the input event was in the cards collision shape and was not handled by a card which is "on top" and thus has not been bubbled up or passed through. I'm using a Area2D which has the signal input_event which I'd love to use as it only handles events which are in the shape. But I guess there is no way to feed this signal into the statechart? Are there any suggestions how this can be done in an appropriate way? Or is manually checking if the event happend inside the rect of the Area2D and was not handled by any other overlapping card?

My nodes are very simple so far: image

nik-lampe commented 1 month ago

Just now I'm having the idea of having a hovered state, which is transitioned in and out by a event on mouse_enter and mouse_exit of the Area2D. And then just use the state_input signal and don't check for overlapping anymore. 🤔

nik-lampe commented 1 month ago

Just now I'm having the idea of having a hovered state, which is transitioned in and out by a event on mouse_enter and mouse_exit of the Area2D. And then just use the state_input signal and don't check for overlapping anymore. 🤔

But I'm afraid this might break for example when the user tabs out of the game and back in and then the cursor is somewhere else without ever actually exiting the area

derkork commented 1 month ago

A very simple way would be to use a UI container for the card and use it's gui_input method to signal to the state chart when the mouse is pressed/released while being over the UI.

image

The state chart has two states Static and Dragging. It enters Dragging when the pressed signal is sent and returns to Static when the released signal is send. The Dragging statesstate_input` signal is now connected to the root node. So whenever the state chart is in Dragging state all input wil be sent to the root node. This node just checks if the input was a mouse motion and moves the card with it.

image

And that's all there is to it.

https://github.com/derkork/godot-statecharts/assets/327257/fbfe6b30-7db5-4868-bf19-317e972c44bc

That being said, I think using state charts for this is really overkill, this is so simple, you can actually just use boolean to track whether the card is currrently being dragged or not and then do it without state charts.

derkork commented 1 month ago

godot_state_charts_examples.zip

Here is a zip with my setup in case you want to play around. Just put the "godot_statecharts_examples" folder to the root of your project.

nik-lampe commented 1 month ago

Thank you!

I did not think about control nodes as I’m new to godot.

Also I’m aware, that using state charts is kind of an overkill for this, I just wanted to use it on the next best occasion. And also I think it might be handy, when I want to add more logic and states.