I wrote a script to follow the target from behind in the distance. Can it be done more easily?

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

Here are my code with comments:

extends Spatial
var min_distance = 5
var max_distance = 10
func _process(delta):
	var target = get_node("../ObjectB")
#	get global transforms
	var target_t: Transform = target.get_global_transform_interpolated()
	var own_t: Transform = get_global_transform_interpolated()
#	get offset (direction and length) from target (origin) to follower position
	var offset = own_t.origin - target_t.origin
#	if offset length is not within minimum and maximum distances
	if offset.length() > max_distance:
		offset = offset.normalized() * max_distance
	if offset.length() < min_distance:
		offset = offset.normalized() * min_distance
#	normalize offset to know only direction
	var normalized_offset = offset.normalized()
#	get dot product of same two vectors to know the angle between them
#	(z axis points to the same direction as object's face)
	var dot = target_t.basis.z.dot(normalized_offset)
#	get cross product of z axis and offset and normalize it
#	to know in which direction rotate offset vector 
#	(order of operation matters)
	var normal = normalized_offset.cross(target_t.basis.z).normalized()
#	cross product will return (0,0,0) if two vectors are aligned
#	and it won't be possible to use the reslut of the cross product as axis
	if normal != Vector3.ZERO:
#		get rad angle from the result of the dot product
#		and rotate offset along normal axis
#		(if rotate not with additional PI, offset and z axis will be aligned 
#		and follower will be in front of target, because offset is a vector
#		from target position to follower position)
		offset = offset.rotated(normal, PI + acos(dot))
#	find new follower position by adding vector facing follower to target position
	var new_position: Vector3 = target_t.origin + offset
#	gradually move to new position
	new_position = lerp(own_t.origin, new_position, 0.05)
#	change follower position and rotation
	look_at_from_position(new_position, target_t.origin, Vector3.UP)

I am new to Godot. Is there a built-in tool or some option for that? I wrote it for a camera, changing the Godot’s vehicle example.

I haven’t looked much at your code, but I definitely wouldn’t do that get_node() call inside _process(). That result won’t change, so there’s no reason to waste cycles looking it up in every frame. Look it up once (likely in _ready() or as an onready var) and use it as necessary.

jgodfrey | 2023-01-17 16:20

Perhaps it could be made easier with RemoteTransform node. Can You elaborate some more on how this following is supposed to work in your project ?

Inces | 2023-01-18 14:10

A camera follows a car in some allowed distance range. And there is an angle where camera starts react if the car’s direction changes. I didn’t add it in the code above, but I achieved this with this additional check “if normal != Vector3.ZERO && acos(dot) < PI - max_behind_angle”. The lerp function gives a lag when the camera starts react if the car moves or rotates, and this gives more natural movements. Of course, the most simple solution is to set the camera as a child to the car, but it looks bad. Ideally the distance between the camera and the car should change according to speed of the car. But I haven’t implemented this yet, because maybe there is a much simpler solution to make a following camera with some node.

RinAkumetsu | 2023-01-18 15:10

hehe, sorry, this sounds complicated enough to require complicated 3d math and few lines of code :slight_smile:
RemoteControl or childing camera to some Pivot with some tweaks would eventually be easy and simple sollution, but You would never be able to improve this sollution the way You are designing now

Inces | 2023-01-18 20:31