Help Creating a Modular 2d Click Based Movement System

Godot Version

4.2

So I’m looking for help wrapping my head around how to implement a click based movement system for my top down game.

Structure is currently as follows:

Entity.gd → Player_Controller.gd → move.gd

Where Entity extends Character 2d, Player_Controller is a Entity, which then calls move, which is intended to be modular

Entity has the following relevant variables and functions:

var max_distance: int = 30

var speed : int = 100


func load_ability(ability_name: String):
	var scene = load("res://scenes/abilities/" + ability_name + "/" + ability_name + ".tscn")
	var sceneNode = scene.instantiate()
	add_child(sceneNode)
	return sceneNode

Player_controller.gd then Extends and loads the “move” ability via the following:

extends Entity

# === Abilities ===
@onready var move = load_ability('move')

#=== For Testing Only ===
var is_selected: bool = true

func _readInput():
	#movement_code
	if Input.is_action_just_pressed("left_click") and is_selected == true:
		var click_position = get_global_mouse_position()
		move.execute(self, click_position)


func _physics_process(_delta):
	_readInput()

and Move is a tscn with a single Node2D that has the following script attached.

extends Node2D

func execute(entity, location):
	var click_position = location
	
	if entity.position.distance_to(click_position) > 30 and entity.position.distance_to(click_position) <= (entity.max_distance * 12):
			var target_position = (click_position - entity.position).normalized()
			entity.velocity = target_position * 300
			entity.move_and_slide()

Right now this does both move the player, not allow you to select a location within the player sprite, and doesn’t let you trigger movement beyond the max distance, but it only moves a few pixels per click rather than going all the way to the final destination selected.

Any help is greatly appreciated

heya!

the reason why it moves only a few pixels is because you move the player in your function, which gets triggered only when you click, you need tohave the movement code in _process() or _physics_process() where it runs all the time, that way the player will move to the location instead of moving a few pixels :slight_smile:

Hope this helps!

1 Like

The function is called in _physics_process()

does that not have the same effect?

Edit: just checked with the following

extends Entity

# === Abilities ===
@onready var move = load_ability('move')


# === Player_Specefic_States === 
var is_selected: bool = true

func _readInput():
	#movement_code
	if Input.is_action_just_pressed("left_click") and is_selected == true:
		var click_position = get_global_mouse_position()
		move.execute(self, click_position)


func _physics_process(_delta):
	#_readInput()
		#movement_code
	if Input.is_action_just_pressed("left_click") and is_selected == true:
		var click_position = get_global_mouse_position()
		move.execute(self, click_position)

and it still has the same issue

if Input.is_action_just_pressed("left_click") and is_selected == true:

This line prevents the movement from continuing;
because Input.is_action_just_pressed("left_click") return true only when pressed

Meaning that until you click the expression is: false and true which means the rest of the code inside doesnt run

When you click the expression is: true and true which means it will execute, but only for a short while, because thats how the Input.is_action_just_pressed() works

Best bet would be to have a variable to check if the player is moving and set it to false when he reaches the destination.

1 Like

Ahhh I see,

I got it working now

Entity now has a target_position variable

func _readInput():
	#movement_code
	if Input.is_action_just_pressed("left_click") and is_selected == true:
		var clicked_position = get_global_mouse_position()
		target_position = clicked_position
		move.execute(self, target_position)

	if position != target_position:
		move.execute(self, target_position)

func _physics_process(_delta):
	_readInput()

Thank you for the help!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.