Follow node movement but ignore rotation

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

I apologize if this has already been answered or is in the documentation, I’ve been looking in both for a long time but can’t quite find what I’m looking for.

I want my camera to follow at a set distance from my character without rotating. Obviously as soon as make it a child of the player it follows at a set distance but also rotates and as soon as I make it a sibling, or separate it stays completely still.

(If it’s hard to visualize think Crash Bandicoot, the camera never rotates but follows the player.)

(I have the movement as I want it with a non-rotating camera it’s just making the camera follow that’s the sticking point.)

I’m guessing I need to look here.

Set my camera relative to the player. Using a Vector3 offset. Or something along those lines.

Edit: More in comments.

I’ve learnt how to get the exact global transform of the player using GDScript but of course this is no different than making the camera a child of the player in effect. How can I modify the following so it uses the x and y coordinates, changes the z and ignores any angles?

Is there a way to break up the get_global_transform / set_global_transform coordinates?

extends Camera
func _process(delta): 	
  var PlayerLocation = get_node("/root/World/Player").get_global_transform()

nu-fulla | 2019-02-11 11:17

The very bottom of this page talks about seperating the translation portion of Transform coordinates from the rotation portion but I don’t understand how to implement it.

Matrices and transforms — Godot Engine (latest) documentation in English

var t = Transform()
pos = t.xform(pos) # transform 3D position
pos = t.basis.xform(pos) # (only rotate)
pos = t.origin + pos # (only translate)

nu-fulla | 2019-02-11 11:56

:bust_in_silhouette: Reply From: wombatstampede

First, I made some post in the godot developers forum about Physics and Transforms. For general reading:

This part of the post might help you with your question:

mycam.look_at_from_pos(Vector3(mycam.get_translation().x, \
         target.get_translation().y,mycam.get_translation().z), \

This is just the looking direction though. If you want to place the camera at some “2D” direction vector relative to the targets rotation you could split the targets transform.basis.

var target2DDir = Vector3(target.transform.basis.z.x,0, \

This code takes the direction Vector3 of the Z-Axis of the target object. (Which I assume as its “view” direction). Then it extracts the actual x and z coordinates of this axis.

You can take the resulting vector (maybe * -1), normalize it (–> length 1), and multiply it by the required camera distance. Than calculate the camera position by adding this to the target.transform.origin (=translation). If the target looks directly “up” or “down” this would set the camera directly on the target though.

By the way: You can (& should) omit get_node(".") when addressing own properties from the nodes own script. In places where you need an explicit reference to the instance/node (not here) you can use self.

Hope I understood your question

Oh, and if you want to move the camera in a smoother way then there’s Tween and follow_property() as one possibility.

Cool thanks for the response and link. Dealing with Vector3 coordinates and 3D Transforms isn’t coming naturally to me to tell you the truth, I’ve gone back to 2D ones to try and get my head around things first.

nu-fulla | 2019-02-12 16:48

No problem. Dealing with 3D transforms I always find myself making silly pilot-like movements, brain gets messed up, trying to sketch something on paper until i (hopefully) get there.

wombatstampede | 2019-02-12 17:28

Sorry to dumb things way down but what is the proper syntax for .set_global_transform?

When I do:

func _ready():
	var GT = .get_global_transform()

	var zero = GT[0]
	var one = GT[1]
	var two = GT[2]
	var three = GT[3]
	print("Global Transform is ",GT)
	print("X is ", zero)
	print("Y is ", one)
	print("Z is ", two)
	print("Origin is ", three)

I get:

Global Transform is 1, 0, 0, 0, 1, 0, 0, 0, 1 - 0, 1.83918, 2.4662
X is (1, 0, 0)
Y is (0, 1, 0)
Z is (0, 0, 1)
Origin is (0, 1.83918, 2.4662)

^ Says:

Transform |	Transform ( Vector3 x_axis, Vector3 y_axis, Vector3 z_axis, Vector3 origin )

So I thought I would write (if I hypothetically wanted to move a camera to the same place):

get_node("/root/Camera").set_global_transform(Transform (1, 0, 0), (0,1, 0), (0, 0, 1), (0, 1.83918, 2.4662))

But I get an error saying Expected ')' in expression

I can’t find an example of someone actually using .set_global_transform with a string of coordinates written.

It works if I just do :


But not if I enter the actual characters of GT , either verbatim or in the syntax the docs say.

nu-fulla | 2019-02-13 06:15

get_node("/root/Camera").set_global_transform( \
  Transform (Vector3(1, 0, 0), \
    Vector3(0,1, 0), Vector3(0, 0, 1), Vector3(0, 1.83918, 2.4662) \
   ) \

But you can also set/change parts of a spatials (or camera) transform:

 $"/root/Camera".global_transform.basis.x = Vector3(1,0,0)

(although setting a single basis vector generally makes no sense) or

 $"/root/Camera".transform.origin.x += 1.5

wombatstampede | 2019-02-13 07:19

I started back at trying to fix this. If I do the following it prints the coordinates roughly were I want the camera to be, the same as the player but with only the x translate modified.
extends Camera

func _process(delta():

	var playerlocation = get_node("/root/World/Player").get_global_transform()
	print (playerlocation * Vector3 (2, 0, 0), Vector3 (0, 0, 0), Vector3 (1, 0, 0), Vector3 (0, 1, 0))

But I can’t create a variable of it to actually use and apply to a camera I keep getting “Expected ‘)’ in expression” no matter how I use the quotes.

var cameralocation = (playerlocation * Vector3 (2, 0, 0), Vector3 (0, 0, 0), Vector3 (1, 0, 0), Vector3 (0, 1, 0))

nu-fulla | 2019-03-15 22:17