how do i 'click and move' on 3D?

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

Im on the version 3.2.1 of godot, for what i have seen on tutorials in order to code my kinematicbody and move it, i need get_global_mouse_position but when i wrote it the progam doesn’t recognize that code. Instead i think i need to use global_transform but i don’t know how to use it.

What other method could i use to move a KBody3D with a mouse? if you can provide the code it would be awesome.

what camera view is this? Is it a top down? Third person?

Millard | 2020-05-21 16:43

Im a newbie so, i think it is called Eagle View, from the sky, but if im not mistaken it is the same as Third Person but from a higher perspective? if that’s the case what should i do?

Denzere | 2020-05-21 16:49

What tutorial are you following? Have you checked the 3d navmesh template? It has a point and click system for movement. It uses rays cast from the camera to calculate where has been clicked.

DamonR | 2020-05-21 22:04

This is one of the tutorials i have been following: https://www.youtube.com/watch?v=_urHlep2P84
And this from the Godot Manual: 2D movement overview — Godot Engine (stable) documentation in English
Some of the code lines doesn’t work on 3D so im a bit confused

I’m aware of the point and blick system on 3Dnavmesh but im not sure how to to link the signal that the RayCast emits and link it to the KinecBody in order to make it move

Denzere | 2020-05-22 20:20

Do you have an example of the code you’re using? I know some things are very different between 2D and 3D, I mostly work in 3D, as that’s just my preference.

From what I remember, the navmesh example doesn’t use a signal, it uses the raycasts to get a position, which it then uses. But the navmesh example uses a master code to run the scene. I used it to figure out how to create enemies which use a navmesh for movement from within their own code. I haven’t used it for a point and click system.

I think there is (or was) a point and click add-on for Godot. Esporia I think.

DamonR | 2020-05-23 00:35

The Godot 3D point and click framework is Escoria (I was so close).

GitHub - godot-escoria/escoria-demo-game: Game example for the point'n'click adventure framework Escoria

I haven’t tried it myself, but it may have something you find useful.

DamonR | 2020-05-23 00:41

This is the exact code I’ve been using so far

extends KinematicBody

var max_speed = 400
var speed = 0
var move_direction
var acceleration = 1200
var moving = false
var destination = Vector3()
var movement = Vector3()
var position = Vector3(0, 0, 0) # ?

func _unhandled_input(event):
if event.is_action_pressed(‘Boton_derecho’):
moving = true
destination = global_transform # here is wherei had the most trouble so far

func _physics_process(delta):
MovementLoop(delta)

func MovementLoop(delta):
if moving == false:
speed = 0
else:
speed += acceleration * delta
if speed > max_speed:
speed = max_speed
movement = position.move_direction(destination) * speed
move_direction = rad2deg(destination.angle_to(destination)) #angle_to doesnt work on 3.2.1
if position.distance_to(destination) > 5:
movement = move_and_slide(movement)
else:
moving = false

For this code I followed a 2D tutorial and changed some lines with I know so far to be able to work on 3D
This is the video where i saw it: https://youtu.be/05OixHPbxNA

Denzere | 2020-05-23 17:50

I will check it (y)

Denzere | 2020-05-23 17:51

:bust_in_silhouette: Reply From: DamonR

I knocked up a quick demo based on your code.
It contains 2 versions, with and without a navmesh.
There is some code which doesn’t need to be there, as I reused it from other projects.
Hope it helps.

To get the 3D mouse click position, I use camera raycasts for normal and origin, and then call a raycast between those two points, getting the 3D position of that intersect as the move target.

The demo project can be found here.

The modified code I used was:

extends KinematicBody

var maxspeed = 400
var speed = 0
var movedirection
var acceleration = 120
var moving = false
var destination = Vector3()
var movement = Vector3()
var position = Vector3(0, 0, 0) # ?

# added vars
var player_position = Vector3()
var marker_position = Vector3()
var move_speed = 15.0
var slow_speed = 3.0
var travel_speed = 5.0
var velocity = Vector3()
var gravity = 0.0

func _input(event):
#func _unhandled_input(event):
#	if event.isactionpressed('Botonderecho'):
#		moving = true
		#destination = globaltransform # here is wherei had the most trouble so far
	if (event.is_class("InputEventMouseButton") and event.button_index == BUTTON_LEFT and event.pressed):
		var from = get_parent().get_node("Cam").project_ray_origin(event.position)#*100

		var to = from + get_parent().get_node("Cam").project_ray_normal(event.position)*100
		var space_state = get_world().direct_space_state
		var result = space_state.intersect_ray(from, to, [self], collision_mask)
		print ("RESULT : ", result.position)
		moving = true
		destination = result.position

func  _physics_process(delta):
	move_to_marker(destination, delta)
#	MovementLoop(delta)

#func MovementLoop(delta):
#	if moving == false:
#		speed = 0
#	else:
#		speed += acceleration * delta
#	if speed > maxspeed:
#		speed = maxspeed
#		movement = position.direction_to(destination) * speed #move_direction(destination) * speed
#		movedirection = rad2deg(destination.angle_to(destination)) #angleto doesnt work on 3.2.1
#	if position.distance_to(destination) > 5:
#		movement = move_and_slide(movement)
#	else:
#		moving = false

func move_to_marker (marker, delta):
	player_position = self.get_global_transform().origin
	marker_position = marker
	var offset = Vector3()
	offset = marker_position - player_position
	var dir = Vector3()
	dir += offset
	dir = dir.normalized()
	velocity.y += delta*gravity
	var hv = velocity
	var target = dir
	var attacking = false
	target *= move_speed
	var ATTACK_ACCEL = 1
	var SPRINT_ACCEL = 2
	var accel
	if dir.dot(hv) > 0:
		accel = travel_speed
	else:
		accel = slow_speed
	hv = hv.linear_interpolate(target, accel*delta)
	velocity.x = hv.x
	velocity.z = hv.z
	velocity.y = hv.y
	velocity = move_and_slide(velocity, Vector3(0,1,0))

Thank you so much!!

Denzere | 2020-05-25 23:34

how would you modify your code so you could use pathfinding aswell as moving while the mouse button is pressed not only once to the point it was pressed to ?

i tried to work it out myself with a diffrent approach ( having the movement part in the camera script ) and i was able to update the mouselocation while the mouse was down but couldnt figure out the movement of the player :frowning:
( i had a prin msg that updated in runtime )

Reddit - Dive into anything

fufuu | 2021-09-29 01:05

Hi fufuu,

To use pathfinding, there are a couple of options in Godot I have experimented with, you can use navmeshes, or AStar. There is an example navmesh project available from Godot, and miziziz did a good tutorial on using gridmaps to create an AStar grid.

https://www.youtube.com/watch?v=A1xjUuRZmWQ

It’s a couple of years old now, but should still work, I got it to work a few months back when I was experimenting with an RTS build, you can enable/disable points in runtime, and setup is easy using gridmaps.

In order to move when the mouse is down, but without changing the location every frame, I would split the code into 2 parts, using Input.is_action_just_pressed(LMB) to create a new “go to” point and do the path calculation, this could be in an input function instead of a process function. Then to have the character move while the mouse button is held, use Input.is_action_pressed(LMB) and call to update the movement along the path.

The main problem I can see here, is if you accidentally release LMB, and change the target point when clicking again, it may be easier to use a different button for setting a location and moving along the path. Or if you mean you would like to be able to hold the LMB while moving the mouse onscreen and have the character follow it, which would require constant recalculating of paths (if using pathfinding). This could be overcome to a degree using timers to limit the number of times it calculates paths per second.

It’s been a while since I’ve worked on anything like this, but I will try and modify the demo project linked above to include an example of what I mean.

Damon R.

DamonR | 2021-09-29 09:49

Updated the demo project from above with AStar pathfinding and steering behaviours from GDQuest.

GitHub - DamonRaziel/Godot-Click-and-Move-Demos: Click and move demos created for those who may want it.

There are 2 AStar demo scenes, one which is click and move with LMb, and one where you use RMB to set target location, and then press and hold LMB to move units to the target location.

Hope this helps.

DamonR | 2021-09-29 12:17