How to connect local events (for touch movement) with state machine?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By anssiko

Hi,

I’m trying to wrap my head around the node-based state machine structure. I’m reverse engineering the “Finite state machine” demo and trying to define which direction to move the player in 2d with a local event for mobile touch input.

It seems that make_input_local is only available for use when extended to KinematicBody2d. Anywhere else in the tree it gives error “method not declared”.

(I have a usable version of player movement with all code in one file, but is is getting difficult to maintain with more states. Which is why I’m trying to split it to different files.)

Questions:

  • What are the limitations on applying “make_input_local”? The docs are unclear on this.
  • What would be the most simple node based state machine structure? A tutorial on this?
  • Where and how in state machine should I define local event touch controls?

I’ll add more detailed information in the comments.

          

At the moment the input direction in the demo is defined with this (in motion.gd):

func get_input_direction():
	var input_direction = Vector2()
	input_direction.x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
	input_direction.y = Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
	return input_direction

My usable version of movement detects the direction of the touch from player, like this:

func _input(event):
	if event is InputEventMouseButton and event.button_index == BUTTON_LEFT:
		if event.pressed:
			var local_event = make_input_local(event)
			if local_event.position.x > 20: 
				state = STATES.MoveRight
			elif local_event.position.x < -20:
				state = STATES.MoveLeft
			elif round(local_event.position.x) in range(-19, 19):
				if is_on_ladder:
					state = STATES.Climb
				elif not is_on_ladder:
					state = STATES.Jump
		else:
			state = STATES.Idle

The node structure of the demo is:

KinematicBody2d
    State machine
        Idle
        Move
        Jump

The script structure of the demo is:

player_controller.gd (extends KinematicBody2d)
state_machine.gd (extends Node "StateMachine")
player_node_state_machine.gd (extends Node "StateMachine")
state.gd (extends Node "StateMachine")
    motion.gd
        on_ground.gd
              idle
              move.gd
        on_air.gd
              jump

anssiko | 2020-03-05 13:20

:bust_in_silhouette: Reply From: njamster

What are the limitations on applying make_input_local? The docs are unclear on this.

No, the documentation is pretty clear about this! make_input_local is a method of the CanvasItem-class, which states at the top that it is inherited by Control and Node2D. So these two nodes and everything than inherits from them directly or indirectly allows for using make_input_local. Judging from your description you might have tried to call make_input_local in a script extending a Node (not a Node2D!) - that indeed won’t work as it’s not inheriting from CanvasItem.

What would be the most simple node based state machine structure? A tutorial on this?

Have you checked out GDQuest’s video on Finite State Machines?

Thank you for answering, that cleared make_input_local (and the overall logic) to me. I made a new version of touch controls with (invisible) touchscreenbuttons, which seems to work very well. This allows me to map them directly as “basic” inputs, and I was able to work around make_input_local problems.

I’ve familiarized myself with GDQuest’s tutorial on youtube, Godot and github, and also checked out all the available tutorials on youtube. I’m starting to understand how the concept works, but mapping out all the connections seems to take time (since I don’t have developer background, I guess).

anssiko | 2020-03-08 19:14