Point and Click Pathfinding

Godot Version

4.7.2

Question

I’m very new to both Godot and this forum, so if this needs to go somewhere else let me know. I’m also pretty new to programming in general, but I have messed around with python a little bit and I have a general understanding how gdscript work.

What I’m trying to do is make a 2d point and click game where there’s a player character that moves between items that the player will select. So far i have an object with a button on it that essentially activates the character’s ability to move (so the physics process only activates when the button has been pressed). The object also has a collision shape that redisables the player movement when the character hits it. The character itself currently moves toward the mouse click’s x position , which is fine and all, except that it means that the player can click the button to activate movement and then click anywhere on the screen to move the character there instead of to the object. Then I realized that I don’t need the character to go anywhere on the screen I just need it to go to where the object is, and the object has a set position.

My question is how exactly do I make a node that will send its position to the character in a way that the character can then use to move towards it without having to code each node to do it individually? Ideally I’d just have a “send the coordinates I’m at” signal that can be used for the same type of node in different locations, but I don’t really know how to achieve that.

Have you tried this demo?

I haven’t, but I’ll give it a try.

That’s really cool, but unfortunately not really what I’m looking for (unless there’s something in there that I missed). I need the character to move to an object when you click the object, but not move anywhere else when you click random places on the screen.

Unless, is there a way to make only certain areas of the navmesh clickable? So that the character can move through the rest of the polygon, but the player can only select certain locations?

So, only process the event and set the path when the player clicks on an object you’re interested in. The code that would need to be modified/replaced for that starts around here godot-demo-projects/2d/navigation/character.gd at 31d1c0c1122717b3ad74aeb94255bc38def52747 · godotengine/godot-demo-projects · GitHub

In order to detect clicks on specific objects, I suggest using an Area2D with input-pickable true. Then, in those objects you can use _input_event to set_movement_target().

So, if I’m understanding you correctly, I’d make an area 2d for my object and set the movement target for the navigation agent in the script for that instead of in the script for the character, and then in the script for the character I’d still be using the navigation agent’s target position for the movement target?

Sounds about right. Since the clicked object can’t (or shouldn’t) set the player’s target position variable directly, you might use a signal or a global var for last clicked object.

How would I get the signal to send the location variable? I’ve read the docs on signals and I understand *generally* how they work, but I can’t find any information on how to do this specific thing.

I imagine I’d need a custom signal in the object like: (I cannot for the life of me figure out how to get the code to format correctly)

signal clicked(location_var)
if Input.is_action_pressed("left_click"):

        clicked.emit(location_var)

And then in the player I’d need something like:

var object_location = Object.new()
object_location.clicked.connect(move_function)
Func move_function(target_location):
 Print(target_location)

Or to just make it work easily, make a global.gd script & make it an autoload.

signal target_changed

var target_object: Node2D

In player, sub to the signal and in the objects emit it.

# player.gd
func _ready() → void:
    Global.target_changed.connect(_on_target_changed)

# object.gd
func _input_event(...) -> void:
    Global.target_object = self
    Global.target_changed.emit()

Or leave target_object in the player and have the signal pass it as an argument. Lots of other ways to do it, too.

I couldn’t figure out how to make it work with a global script (I was probably doing something wrong, but I don’t know what), but I did figure out how to make the object signal the character directly, so the problem is solved! Thank you so much for your help and suggestions!