Issues with move_and_slide Godot 4.2.1

Godot Version

v4.2.1.stable.official [b09f793f5]

Question

I am trying to use the move_and_slide() in my code. How can I implement this?

CONTEXT

I am making an RTS game and this is the start of my script that I am using to make it. This script is labeled “skrimish_master” and is being used to control what happens in-match as the player is playing. I can get my “Actors” (my RTS units) to look_at my right mouse click, context_GameObject.look_at(Vector3(results.position.x, 0, results.position.z)), but I cant get the Actor to move towards the right click in a smooth manner. It only jumps to its location.

move_and_slide() isn’t working to make the unit move to the right click location.

My unit is created using a class Actor and is stores in a Dictionary called teams_skrimish_actors_DICTIONARY[squad_#] as Actor_# so it then looks like teams_skrimish_actors_DICTIONARY[squad_#[Actor_#]]

I can get the

CODE / SCRIPT

extends Node

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

@onready var formation_type
@onready var selected_actors: Array
@onready var mouse_pos
@onready var camera_ref:Camera3D = $"../Camera3D"
@onready var results

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#this is the currently selected Game Object that exists in the world
@onready var context_GameObject = null
@onready var context_GameObject_Group = null
@onready var building_rally_point:Vector3
@onready var delta_ref

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

@onready var actor_GameObject = preload("res://Assets/GAME_READY/UNITS/HUMANS/unit_static_body_3d.tscn")
@onready var actors_container_ref = $Actors_container
@onready var squad_count = 0
@onready var teams_skrimish_actors_DICTIONARY = {
	"solo_actors": {
	},
	"squad_1": {
	}
}

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

@onready var Action_Button_Menu_Ref: Dictionary = {
	"Button_1": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_1_HBoxContainer/Action_Button_1,
	"Button_2": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_1_HBoxContainer/Action_Button_2,
	"Button_3": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_1_HBoxContainer/Action_Button_3,
	"Button_4": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_1_HBoxContainer/Action_Button_4,
	"Button_5": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_2_HBoxContainer/Action_Button_5,
	"Button_6": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_2_HBoxContainer/Action_Button_6,
	"Button_7": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_2_HBoxContainer/Action_Button_7,
	"Button_8": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_2_HBoxContainer/Action_Button_8,
	"Button_9": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_3_HBoxContainer/Action_Button_9,
	"Button_10": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_3_HBoxContainer/Action_Button_10,
	"Button_11": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_3_HBoxContainer/Action_Button_11,
	"Button_12": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_3_HBoxContainer/Action_Button_12,
}

@onready var GUI_icons: Dictionary = {
	"back_icon": preload("res://UserInterface/back_Arrow.svg"),
	"blank_icon": preload("res://UserInterface/BLANK_Icon.png"),
	"build_icon": preload("res://UserInterface/build_icon.svg"),
	"delete_icon": preload("res://UserInterface/Delete_Icon.png"),
	"godot_icon": preload("res://UserInterface/icon.svg"),
	"move_icon": preload("res://UserInterface/Move_Icon.png"),
	"stop_icon": preload("res://UserInterface/Stop_Icon.png"),
	"tile_icon": preload("res://UserInterface/tile.svg"),
}

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

func _ready() -> void:
	for button in Action_Button_Menu_Ref:
		Action_Button_Menu_Ref[button].texture_normal = preload("res://UserInterface/BLANK_Icon.png")

func _process(delta: float) -> void:
	delta_ref = delta

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

@onready var square_formation_positions:Dictionary = {}

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

class Actor:
	var name: String
	var id: int
	var group_id: int
	var level: int = 1
	var level_progress: int = 0
	var position: Vector3
	var health: int = 120
	var moral: int = 100
	var armour: int = 25
	var speed: int = 15
	var weapon: String
	var faction: String
	var party: String
	var skin: Color

	func _init(_name: String, _id: int, _group_id: int, _level: int, _level_progress: float, _position: Vector3, _health: int, _moral: int, _armour: int, _speed: int, _weapon: String, _faction: String, _party: String, _skin: Color):
		name = _name
		id = _id
		group_id = _group_id
		level = _level
		level_progress = _level_progress
		position = _position
		health = _health
		moral = _moral
		armour = _armour
		speed = _speed
		weapon = _weapon
		faction = _faction
		party = _party
		skin = _skin
		self.material_overide = skin
	
	
	
	func move(where: Vector3, to: Vector3):
		# should be move_and_slide() but cant figure it out yet
		pass
	
	func attack(who: Actor):
		# Should right click a location and if it is an enemy, attack, else repair, heal, move etc.
		pass

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

class Squad:
	var actor_name = "Actor"+str(ID_Count)
	var ID_Count = 0
	var group_ID = 0
	var squad_position = null
	var faction: String = "Faction_1"
	var party: String = "Faction_1"

	var formation: String = "Square"
	
	var squad_dictionary: Dictionary = {}
	
	func spawn_actor(actor_type:String):
		var actor
		match actor_type:
			"Assault":
				squad_dictionary[ID_Count] = Actor.new(actor_name, ID_Count, group_ID, 1, 0, squad_position, 120, 150, 50, 15, weapon("rifle"), faction, party, Color.YELLOW)
				ID_Count += 1
			"Engineer":
				squad_dictionary[ID_Count] = Actor.new(actor_name, ID_Count, group_ID, 1, 0, squad_position, 90, 170, 40, 10, weapon("shotgun"), faction, party, Color.GREEN)
				ID_Count += 1
			_:
				print("Invalid actor type")
				return null
		return actor
	
	#func _physics_process(delta):
		#Vector3(self.transform.basis.z).normalized() * delta
		#move_and_slide()
		#pass
	
	func set_formation(type: String):
		var squad_leader = squad_dictionary[0]
		match type:
			"square":
				var actor_offset:int = 5
				var layer_offset:int = 10
				squad_dictionary["Position_1"] = squad_dictionary[0].position
				squad_dictionary["Position_2"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z) # L
				squad_dictionary["Position_3"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z) # R
				squad_dictionary["Position_4"] = Vector3(squad_leader.position.x, 0, squad_leader.position.z + actor_offset) # U
				squad_dictionary["Position_5"] = Vector3(squad_leader.position.x, 0, squad_leader.position.z - actor_offset) # D
				squad_dictionary["Position_6"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z + actor_offset) # LU
				squad_dictionary["Position_7"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z + actor_offset) # RU
				squad_dictionary["Position_8"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z - actor_offset) # LD
				squad_dictionary["Position_9"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z - actor_offset) # RD
				squad_dictionary["Position_10"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z) # LL
				squad_dictionary["Position_11"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z) # RR
				squad_dictionary["Position_12"] = Vector3(squad_leader.position.x, 0, squad_leader.position.z + layer_offset) # UU
				squad_dictionary["Position_13"] = Vector3(squad_leader.position.x, 0, squad_leader.position.z - layer_offset) # DD
				squad_dictionary["Position_14"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z - layer_offset) # UL
				squad_dictionary["Position_15"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z - layer_offset) # UR
				squad_dictionary["Position_16"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z + layer_offset) # DL
				squad_dictionary["Position_17"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z + layer_offset) # DR
				squad_dictionary["Position_18"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z + actor_offset) # LL U
				squad_dictionary["Position_19"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z - actor_offset) # LL D
				squad_dictionary["Position_20"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z + layer_offset) # LL UU
				squad_dictionary["Position_21"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z - layer_offset) # LL DD
				squad_dictionary["Position_22"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z + actor_offset) # RR U
				squad_dictionary["Position_23"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z - actor_offset) # RR D
				squad_dictionary["Position_24"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z - layer_offset) # RR UU
				squad_dictionary["Position_25"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z + layer_offset) # RR DD
			_:
				pass
	
	func generate_actor(from):
		#the is linked to a button and is used to spawn an actor from a building or squad
		
		pass

	func weapon(type):
		match type:
			"rifle":
				pass
			"shotgun":
				pass
			_:
				pass


#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

func delete():
	
	pass

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

func _input(event):
	if event is InputEventMouseButton:
		mouse_pos = event.position
		rayCast()
		if event.is_action_released("Left_Click"):
			print("Left mouse button pressed")
			if results.size() > 0:
				print(results)
				for group_name in results.collider.get_groups():
					match group_name:
						"Selectable":
							pass
						"Unit":
							context_GameObject = results.collider
							context_GameObject_Group = group_name
							Action_Button_Menu_Ref["Button_1"].texture_normal = GUI_icons["move_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["build_icon"]
							Action_Button_Menu_Ref["Button_4"].texture_normal = GUI_icons["stop_icon"]
							Action_Button_Menu_Ref["Button_9"].texture_normal = GUI_icons["back_icon"]
							Action_Button_Menu_Ref["Button_12"].texture_normal = GUI_icons["delete_icon"]
							print("WAS Unit")
						"Building":
							context_GameObject = results.collider
							context_GameObject_Group = group_name
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["godot_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["build_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["godot_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["back_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["godot_icon"]
							print("WAS Building")
						"Map":
							context_GameObject = null
							context_GameObject_Group = null
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["back_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							print("WAS Map")
						_:
							context_GameObject = null
							context_GameObject_Group = null
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["back_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
					#do button code here
		if event.is_action_released("Right_Click"):
			print("Right mouse button pressed")
			if context_GameObject_Group != null:
				match context_GameObject_Group:
					"Unit":
						#context_GameObject.move_and_slide()
						print(context_GameObject.position)
						print(results.position, "\n")
						var round_context = Vector3(round(context_GameObject.position.x), round(context_GameObject.position.y), round(context_GameObject.position.z))
						var round_results = Vector3(round(results.position.x), round(results.position.y), round(results.position.z))
						context_GameObject.velocity = Vector3(0, 0, -1) * 15
						context_GameObject.look_at(Vector3(results.position.x, 0, results.position.z))
						print(context_GameObject.transform.basis.z)
						#context_GameObject.transform.origin -= Vector3(context_GameObject.transform.basis.z).normalized()
						#while round(context_GameObject.position) != round_results:
						#while range(round(context_GameObject.position.x), round_results.x-1, round_results.x+1):
						#context_GameObject.move_and_slide()
						#while context_GameObject.position.x < round_results.x-.2 || round(context_GameObject.position.x) > round_results.x+.2:
							#print("round_context: ", round(context_GameObject.position))
							#print("round_results: ", round_results, "\n")
							#context_GameObject.transform.origin -= Vector3(context_GameObject.transform.basis.z).normalized() * delta_ref
					"Building":
						pass
					_:
						pass

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

func rayCast():
    var worldspace = camera_ref.get_world_3d().direct_space_state
	var from = camera_ref.project_ray_origin(mouse_pos)
	var to = camera_ref.project_position(mouse_pos, 1000)
	results = worldspace.intersect_ray(PhysicsRayQueryParameters3D.create(from, to))

CONCLUSION

Hopfully someone that is smarted than me can help me solve this. I genuinly am not sure how to complete get over this hurtle.

Regards,
Self.name

CharacterBody3D.move_and_slide() is a method of the class CharacterBody3D

To use it you’ll need to extend that class and code it accordingly. Check the Getting Started section of the documentation here Introduction — Godot Engine (4.0) documentation in English where it will teach you how to do that both in 2D and in 3D.

1 Like

I have tried doing context_GameObject.move_and_slide() andf that doesn’t work for me either. my Actor just sits there and turns toward the click and moves on the positive X axis. Only when I click, not for ever. When I see print it, I get this…

Printing 'context_GameObject.move_and_slide()' - true

My actor is one of a CharacterBody3D and the preload I am using is a saved scene where the Actor sits @onready var actor_GameObject = preload("res://Assets/GAME_READY/UNITS/HUMANS/unit_static_body_3d.tscn")

The unit_statis_body_3d was just the name I gave it at that time. It isn’t actually a static body 3D

Any instance of me seeing move_and_slide() work for other people was because it was inside the physics_process() function but I don’t know how to guide myt code so that the move_and_slide() fires in the physics_process() function.

Is there a way to recursivley call the move_and_slide() in a way that will move it until its velocity becomes zero?

Unless I am mistaken that creating an instance of a class with a character body doesn’t work.

Here is my scene tree…

GLOBAL_OBJECT #root
---->GAME_GRAPHICAL_EFFECTS
---->Camera3D
---->DirectrionalLight3D
---->Control
---->SKRIMISH_MAP
------->SKRIMISH_UI
------->SKRIMISH_MAP_PLAINS_
------->HQ_BUILDING_
------->RECRUIT_BUILDING_
------->Actors_container #Node3D
----------->ACTOR_0000 #CharacterBody3D

My ACTOR_0000 is of type CharacterBody3D, so when I call the class it should instance one of the scenes I have set up as an Actor.

Perhaps im misreading the code but to me your getting the position of the mouse click which isnt a vector3 so in a 3dspace you cant use the raw mouse coordinates as a location to move to without essentially being constrained to a 2d plane.

1 Like

Edit: I have also tried setting a velocity to the CharacterBody3D and that did not help. Unless I am miss understanding what it does or how it work, which is extremely likely lol.

Essentually my thought process is this…

  1. The CharacterBody3D exists in the world

  2. The player left clicks on that Actor and places it’s node (the CharacterBody3D) into the @onready var context_GameObject = null

  3. When the player commits a right click, the Actor turns and faces where the right click was commited context_GameObject.look_at(Vector3(results.position.x, 0, results.position.z))

  4. The Actror will then commit a move_and_slide() and travel towards the location of the right mouse click with this code, presumable along its local negative z axis.

I have changed the code since my post in an effort to get the Actor to move. Maybe I should use translate instead.

while context_GameObject.position.distance_to(results.position) > .3: #if the position of Actor is more than .3 unit away from the mouse click position (results.position)
	print("distance from Actor to right click position: ", context_GameObject.position.distance_to(results.position))
	print("Actor position: ", context_GameObject.position)
	print("right click position: ", results.position, "\n")
	context_GameObject.move_and_slide()
	#context_GameObject.transform.origin = context_GameObject.transform.origin - Vector3((context_GameObject.transform.basis.z).normalized())

Doing this will face the Actor towards the right click, but the Actor will teleport towards the right click instead of smoothly moving towards the right click location.

How do I get the move_and_slide() to activate inside of the physics so that it moves smoothly? If it works that way. I am just a hobbyist when it comes to making my game so I only usually get weekends to work on the game. I am fairly unintelligent on how the nodes actually function behind the scenes.

Here is the code output from my print() statements after selecting the Actor, then right clicking to the right of the Actor about 1 unit away…

Actor rotation BEFORE ‘look_at’: (0, 0, 0)

distance from Actor to right click position: 1.02085864543915
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0, 0, 0)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 1.00419235229492
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.016627, 0.000827, -0.001156)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.98752582073212
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.033253, 0.000934, -0.002311)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.97085911035538
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.04988, 0.00094, -0.003467)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.95419245958328
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.066506, 0.00094, -0.004623)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.93752580881119
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.083133, 0.00094, -0.005779)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.92085915803909
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.099759, 0.00094, -0.006934)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.904192507267
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.116386, 0.00094, -0.00809)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.88752579689026
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.133012, 0.00094, -0.009246)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.87085920572281
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.149639, 0.00094, -0.010402)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.85419249534607
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.166266, 0.00094, -0.011557)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.83752584457397
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.182892, 0.00094, -0.012713)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.82085913419724
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.199519, 0.00094, -0.013869)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.80419254302979
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.216145, 0.00094, -0.015025)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.78752589225769
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.232772, 0.00094, -0.01618)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.7708592414856
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.249398, 0.00094, -0.017336)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.75419253110886
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.266025, 0.00094, -0.018492)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.73752593994141
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.282651, 0.00094, -0.019648)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.72085922956467
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.299278, 0.00094, -0.020803)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.70419263839722
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.315904, 0.00094, -0.021959)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.68752598762512
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.332531, 0.00094, -0.023115)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.67085939645767
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.349157, 0.00094, -0.024271)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.65419268608093
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.365784, 0.00094, -0.025426)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.63752609491348
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.382411, 0.00094, -0.026582)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.62085938453674
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.399037, 0.00094, -0.027738)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.60419285297394
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.415664, 0.00094, -0.028893)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.5875261425972
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.43229, 0.00094, -0.030049)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.57085955142975
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.448917, 0.00094, -0.031205)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.55419290065765
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.465543, 0.00094, -0.032361)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.5375263094902
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.48217, 0.00094, -0.033516)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.52085959911346
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.498796, 0.00094, -0.034672)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.50419300794601
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.515423, 0.00094, -0.035828)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.48752635717392
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.532049, 0.00094, -0.036984)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.47085973620415
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.548676, 0.00094, -0.038139)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.45419308543205
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.565302, 0.00094, -0.039295)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.43752646446228
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.581929, 0.00094, -0.040451)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.42085987329483
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.598556, 0.00094, -0.041607)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.40419325232506
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.615182, 0.00094, -0.042762)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.38752663135529
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.631809, 0.00094, -0.043918)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.37086004018784
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.648435, 0.00094, -0.045074)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.35419344902039
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.665062, 0.00094, -0.04623)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.33752682805061
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.681688, 0.00094, -0.047385)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.32086026668549
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.698315, 0.00094, -0.048541)
right click position: (1.018401, -0.000004, -0.070791)

distance from Actor to right click position: 0.30419367551804
Actor rotation AFTER ‘look_at’: (0, -1.501396, 0)
Actor position: (0.714941, 0.00094, -0.049697)
right click position: (1.018401, -0.000004, -0.070791)

This is the end of the output as the unit has reached its destination (via teleport instead of smoothly sliding over to it) and then the script waits for a new input.

So it is a little messy but I was able to figure it out.

I was not sure how to get the move_and_slide() to function inside the func _physics_process(delta) but I eventually figured it out by adding a toggle to the top of the scipt.

I added a @onready var move: bool = false toggle and when the actor is above a certain distance then it would toggle true which would then activate the move_and_slide() and move along its local -z basis. This was the code here…


Right click to change move to true

		if event.is_action_released("Right_Click"):
			print("Right mouse button pressed")
			if context_GameObject_Group != null:
				match context_GameObject_Group:
					"Unit":
						for actor in context_GameObjects:
							var round_context = Vector3(round(context_GameObjects[actor].position.x), round(context_GameObjects[actor].position.y), round(context_GameObjects[actor].position.z))
							var round_results = Vector3(round(results.position.x), round(results.position.y), round(results.position.z))
							context_GameObjects[actor].velocity = Vector3(0, 0, -1) * 15
							print("Actor rotation BEFORE 'look_at': ", context_GameObjects[actor].rotation, "\n")
							context_GameObjects[actor].look_at(Vector3(results.position.x, 0, results.position.z))
							if context_GameObjects[actor].position.distance_to(results.position) > 0.3:
								move = true

negative z basis

context_GameObjects[actor].velocity = (-context_GameObjects[actor].transform.basis.z * delta) * 200

func _physics_process(delta):

func _physics_process(delta):
	if move == true:
		for actor in context_GameObjects:
			context_GameObjects[actor].velocity = (-context_GameObjects[actor].transform.basis.z * delta) * 200
			context_GameObjects[actor].move_and_slide()
			print("DISTANCE: ", context_GameObjects[actor].position.distance_to(results.position))
			print("RIGHT CLICK POS: ", context_GameObjects[actor].position)
			print("ACTOR POS: ", context_GameObjects[actor].position, "\n")
			
			if context_GameObjects[actor].position.distance_to(results.position) <= 0.1:
				move = false

skrimish_master.gd code

extends Node

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

@onready var formation_type
@onready var mouse_pos
@onready var results
@onready var camera_ref:Camera3D = $"../Camera3D"
@onready var actor_container = $Actors_container

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#this is the currently selected Game Object that exists in the world
@onready var context_GameObjects:Dictionary = {}
@onready var context_GameObject_Group = null
@onready var building_rally_point:Vector3
@onready var delta_ref

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

@onready var actor_GameObject = preload("res://Assets/GAME_READY/UNITS/HUMANS/unit_static_body_3d.tscn")
@onready var actors_Dictionary: Dictionary = {}
@onready var squad_count = 0
@onready var teams_skrimish_actors_DICTIONARY = {
	"solo_actors": {
	},
	"squad_1": {
	}
}

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

@onready var Action_Button_Menu_Ref: Dictionary = {
	"Button_1": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_1_HBoxContainer/Action_Button_1,
	"Button_2": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_1_HBoxContainer/Action_Button_2,
	"Button_3": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_1_HBoxContainer/Action_Button_3,
	"Button_4": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_1_HBoxContainer/Action_Button_4,
	"Button_5": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_2_HBoxContainer/Action_Button_5,
	"Button_6": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_2_HBoxContainer/Action_Button_6,
	"Button_7": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_2_HBoxContainer/Action_Button_7,
	"Button_8": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_2_HBoxContainer/Action_Button_8,
	"Button_9": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_3_HBoxContainer/Action_Button_9,
	"Button_10": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_3_HBoxContainer/Action_Button_10,
	"Button_11": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_3_HBoxContainer/Action_Button_11,
	"Button_12": $SKRIMISH_UI/Action_Menu_Margin/Action_Button_Menu/VBoxContainer/Action_Row_3_HBoxContainer/Action_Button_12,
}

@onready var GUI_icons: Dictionary = {
	"back_icon": preload("res://UserInterface/back_Arrow.svg"),
	"blank_icon": preload("res://UserInterface/BLANK_Icon.png"),
	"build_icon": preload("res://UserInterface/build_icon.svg"),
	"delete_icon": preload("res://UserInterface/Delete_Icon.png"),
	"godot_icon": preload("res://UserInterface/icon.svg"),
	"move_icon": preload("res://UserInterface/Move_Icon.png"),
	"stop_icon": preload("res://UserInterface/Stop_Icon.png"),
	"tile_icon": preload("res://UserInterface/tile.svg"),
}

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

func _ready() -> void:
	
	var new_actor = Squad.new(actor_container, actors_Dictionary)
	new_actor.spawn_actor("Engineer")
	
	for button in Action_Button_Menu_Ref:
		Action_Button_Menu_Ref[button].texture_normal = preload("res://UserInterface/BLANK_Icon.png")
	

func _process(delta: float) -> void:
	delta_ref = delta

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

@onready var square_formation_positions:Dictionary = {}

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

# Define the Actor class within the SkirmishMaster script
class Actor:
	var actor_self = preload("res://Assets/GAME_READY/UNITS/HUMANS/unit_static_body_3d.tscn")
	var actor_container: Node3D
	var name: String
	var id: int
	var group_id: int
	var level: int = 1
	var level_progress: int = 0
	var position: Vector3
	var health: int = 120
	var moral: int = 100
	var armour: int = 25
	var speed: int = 15
	var weapon: String
	var faction: String
	var party: String
	var skin: Color

	func _init(_actor_container: Node3D, _name: String, _id: int, _group_id: int, _level: int, _level_progress: float, _position: Vector3, _health: int, _moral: int, _armour: int, _speed: int, _weapon: String, _faction: String, _party: String, _skin: Color):
		actor_container = _actor_container
		name = _name
		id = _id
		group_id = _group_id
		level = _level
		level_progress = _level_progress
		position = _position
		health = _health
		moral = _moral
		armour = _armour
		speed = _speed
		weapon = _weapon
		faction = _faction
		party = _party
		skin = _skin
		
		var actor_GO = actor_self.instantiate()
		actor_GO.name = "Actor_" + str(id)
		actor_container.add_child(actor_GO)
	
	func move(where: Vector3, to: Vector3):
		# Implement move command here
		pass
	
	func attack(who: Actor):
		# Implement attack command here
		pass

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

@onready var move: bool = false

func _physics_process(delta):
	if move == true:
		for actor in context_GameObjects:
			context_GameObjects[actor].velocity = (-context_GameObjects[actor].transform.basis.z * delta) * 200
			context_GameObjects[actor].move_and_slide()
			print("DISTANCE: ", context_GameObjects[actor].position.distance_to(results.position))
			print("RIGHT CLICK POS: ", context_GameObjects[actor].position)
			print("ACTOR POS: ", context_GameObjects[actor].position, "\n")
			
			if context_GameObjects[actor].position.distance_to(results.position) <= 0.1:
				move = false

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

class Squad:
	var actor_container
	var actors_Dictionary
	var ID_Count = 0
	var actor_name = "Actor_"+str(ID_Count)
	var group_ID = 0
	var squad_position = Vector3(0,0,0)
	var faction: String = "Faction_1"
	var party: String = "Faction_1"
	var my_weapon = null

	func _init(_actor_container:Node3D, _actors_Dictionary:Dictionary):
		actor_container = _actor_container
		actors_Dictionary = _actors_Dictionary
	
	var formation: String = "Square"
	
	var squad_dictionary: Dictionary = {}
	
	func spawn_actor(actor_type:String):
		var actor
		match actor_type:
			"Assault":
				actors_Dictionary[actor_name] = Actor.new(actor_container, actor_name, ID_Count, group_ID, 1, 0, squad_position, 120, 150, 50, 15, "rifle", faction, party, Color.YELLOW)
				ID_Count += 1
			"Engineer":
				actors_Dictionary[actor_name] = Actor.new(actor_container, actor_name, ID_Count, group_ID, 1, 0, squad_position, 90, 170, 40, 10, "shotgun", faction, party, Color.GREEN)
				ID_Count += 1
			_:
				print("Invalid actor type")
				return null
		
	func set_formation(type: String):
		var squad_leader = squad_dictionary[0]
		match type:
			"square":
				var actor_offset:int = 5
				var layer_offset:int = 10
				squad_dictionary["Position_1"] = squad_dictionary[0].position
				squad_dictionary["Position_2"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z) # L
				squad_dictionary["Position_3"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z) # R
				squad_dictionary["Position_4"] = Vector3(squad_leader.position.x, 0, squad_leader.position.z + actor_offset) # U
				squad_dictionary["Position_5"] = Vector3(squad_leader.position.x, 0, squad_leader.position.z - actor_offset) # D
				squad_dictionary["Position_6"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z + actor_offset) # LU
				squad_dictionary["Position_7"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z + actor_offset) # RU
				squad_dictionary["Position_8"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z - actor_offset) # LD
				squad_dictionary["Position_9"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z - actor_offset) # RD
				squad_dictionary["Position_10"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z) # LL
				squad_dictionary["Position_11"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z) # RR
				squad_dictionary["Position_12"] = Vector3(squad_leader.position.x, 0, squad_leader.position.z + layer_offset) # UU
				squad_dictionary["Position_13"] = Vector3(squad_leader.position.x, 0, squad_leader.position.z - layer_offset) # DD
				squad_dictionary["Position_14"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z - layer_offset) # UL
				squad_dictionary["Position_15"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z - layer_offset) # UR
				squad_dictionary["Position_16"] = Vector3(squad_leader.position.x + actor_offset, 0, squad_leader.position.z + layer_offset) # DL
				squad_dictionary["Position_17"] = Vector3(squad_leader.position.x - actor_offset, 0, squad_leader.position.z + layer_offset) # DR
				squad_dictionary["Position_18"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z + actor_offset) # LL U
				squad_dictionary["Position_19"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z - actor_offset) # LL D
				squad_dictionary["Position_20"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z + layer_offset) # LL UU
				squad_dictionary["Position_21"] = Vector3(squad_leader.position.x - layer_offset, 0, squad_leader.position.z - layer_offset) # LL DD
				squad_dictionary["Position_22"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z + actor_offset) # RR U
				squad_dictionary["Position_23"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z - actor_offset) # RR D
				squad_dictionary["Position_24"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z - layer_offset) # RR UU
				squad_dictionary["Position_25"] = Vector3(squad_leader.position.x + layer_offset, 0, squad_leader.position.z + layer_offset) # RR DD
			_:
				pass
	
	func generate_actor(from):
		#the is linked to a button and is used to spawn an actor from a building or squad
		
		pass

	func weapon(type):
		match type:
			"rifle":
				my_weapon = "rifle"
			"shotgun":
				my_weapon = "shotgun"
			_:
				pass


#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

func delete():
	
	pass

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

func _input(event):
	if event is InputEventMouseButton:
		mouse_pos = event.position
		rayCast()
		if event.is_action_released("Left_Click"):
			print("Left mouse button pressed")
			if results.size() > 0:
				print(results)
				for group_name in results.collider.get_groups():
					match group_name:
						"Selectable":
							pass
						"Unit":
							context_GameObjects[results.collider.name] = results.collider
							context_GameObject_Group = group_name
							Action_Button_Menu_Ref["Button_1"].texture_normal = GUI_icons["move_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["build_icon"]
							Action_Button_Menu_Ref["Button_4"].texture_normal = GUI_icons["stop_icon"]
							Action_Button_Menu_Ref["Button_9"].texture_normal = GUI_icons["back_icon"]
							Action_Button_Menu_Ref["Button_12"].texture_normal = GUI_icons["delete_icon"]
							print("WAS Unit")
						"Building":
							context_GameObjects[str(results.collider.actor_name)] = str(results.collider.ID_Count)
							context_GameObject_Group = group_name
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["godot_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["build_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["godot_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["back_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["godot_icon"]
							print("WAS Building")
						"Map":
							context_GameObjects.clear()
							context_GameObject_Group = null
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["back_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							print("WAS Map")
						_:
							context_GameObjects.clear()
							context_GameObject_Group = null
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["back_icon"]
							Action_Button_Menu_Ref["Button_3"].texture_normal = GUI_icons["blank_icon"]
					#do button code here
		if event.is_action_released("Right_Click"):
			print("Right mouse button pressed")
			if context_GameObject_Group != null:
				match context_GameObject_Group:
					"Unit":
						for actor in context_GameObjects:
							var round_context = Vector3(round(context_GameObjects[actor].position.x), round(context_GameObjects[actor].position.y), round(context_GameObjects[actor].position.z))
							var round_results = Vector3(round(results.position.x), round(results.position.y), round(results.position.z))
							context_GameObjects[actor].velocity = Vector3(0, 0, -1) * 15
							print("Actor rotation BEFORE 'look_at': ", context_GameObjects[actor].rotation, "\n")
							context_GameObjects[actor].look_at(Vector3(results.position.x, 0, results.position.z))
							if context_GameObjects[actor].position.distance_to(results.position) > 0.3:
								move = true
							#if context_GameObject.position.distance_to(results.position) <= 0.3:
								#move = false
					"Building":
						pass
					_:
						pass

#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

func rayCast():
	var worldspace = camera_ref.get_world_3d().direct_space_state
	var from = camera_ref.project_ray_origin(mouse_pos)
	var to = camera_ref.project_position(mouse_pos, 1000)
	results = worldspace.intersect_ray(PhysicsRayQueryParameters3D.create(from, to))