Camera that follows spaceship

Godot Version

4.4.1

Question

Hi folks,

I am trying to create a camera script that follows a spacecraft but with a slight delay or “swing” to it. I’m going for a more cinematic style almost as if the camera is another ship following close behind. I’ve watched about a million tutorials, scoured the docs and studied some other projects but nothing I’ve found really has the feel of what I’m looking for.

I can get the camera to follow the ship with only a few lines of code using transforms and it works fine for now but I am having trouble getting the “swing”. I understand the concept of transforms well enough but I’m terrible at implementing these concepts in code.

Here is the code that moves the camera as well as the node tree structure

	transform = target.get_global_transform_interpolated()

	transform.basis.z = lerp(transform.basis.z, target.transform.basis.z, rotation_damping * delta)
	transform.basis.x = lerp(transform.basis.x, target.transform.basis.x, rotation_damping * delta)
	transform.basis.y = lerp(transform.basis.y, target.transform.basis.y + offset, rotation_damping * delta)

# Nodes
CameraRig (script)
|_ SpringArm3D
   |_ Camera3D

# This is so I can have better control over the cameras movement and access the transform property of the Node3D
	

The trouble it more or less stays locked to the ships movement with only a little sway to it. Is this the completely wrong approach or could I add some tweaks to achieve what I want to do?

Thanks in advance for your help!

I have no idea, just throwing ideas…

I tried doing something similar for my game. I used a tween for that, with non-linear curve. I did get the initial result, however, there are many problems in when targets change direction, for example, so it all came out a bit janky in the end.

But I’m also thinking, what if you just set the movement speed based on what the target movement speed was in the past, like 1 second or 0.5 seconds ago? So target starts speeding away, and the camera takes a bit to follow up.

I had thought of the time-based approach but I wasn’t finding a good way to implement it. Perhaps I could have a variable that is assigned the position of the target periodically and then apply that transform to the camera node a set number of milliseconds afterwards using a multiple of delta.

I’ll need to do more docs reading on this I think! Still curious to hear other ideas on this.

My thought is that you might have an easier time creating what you want instead of simulating it. In other words, the game has a physics engine - let it do the heavy lifting. So I would do something like this:

Spaceship — ConeTwistJoint3D — RigidBody3D — ConeTwistJoint3D — RigidBody3D — Camera

  1. Make the first RigidBody3D have a CollisionShape3D with either a ray or long thin cylinder.
  2. Make the PhysicsMaterial for the first RigidBody3D: Friction = 0.5, Bounce = 0.75, Absorbent = true
  3. For RigidBody3D two just make it a small sphere and make the Camera3D a child of it.

I have no idea how to use a ConeTwistJoint3D because I’ve never used joints, but there are tutorials out there.

2 Likes

I like this idea. I was already experimenting with realistic spaceship controls using a RigidBody3D. This good be a good approach.

I’ll try it out and report back!

1 Like

Hard to answer.
Godot has no SpringArm3D damping values. I have no idea where they get their simulation from.
Ran some tests. The spring arm does in fact work in one direction. It looks like it works at least for one axis.
Meaning you’re going to be involved in a terrible balancing act. Because you need a spring arm for the X, Y and Z axis.
Like I said the spring arm here only has length margins. That’s all. Sorry.

1 Like

I think someone might have used the matrix for that.
which i decided to test nevertheless.
i’m not really sure if the computer is going to survive 31 * 200
at least this time

So I found a solution that works for now. I need to fiddle with it a bit more but it’s the look I am going for.

If anyone is curious here is the code:

	rig_pos = target.transform.interpolate_with(transform, 0.99)
	
	transform = lerp(rig_pos, target.transform, 0.5 * delta)

I have no idea how or why the interpolate function does what I want it to do so if anyone knows I’d be interested to learn why.

1 Like

I tried using physics bodies and joints but it didn’t quite work out. The camera basically flailed all over the place. I managed to get it functional by clamping down it’s motion on a couple of axes but the solution I found above is cleaner.

Thanks for your help! I learned a lot.

2 Likes

I kind of figured out what the text wanted. So the spring arm is a square.

If I make a level for it. And make it collide with a floor or static shape for example with a spinning parent.
It actually collapses, or rather it will compress the spring arm. That’s really all it’s good for. I wouldn’t know I would use it.
Thanks.

Oops. I actually rushed and used a box for that test. It’s a shape 3D. Actually can be anything.