Custom camera follow code problem (SOLVED)

I’m making a 3D platformer, and I want a camera the follows the player. I can already do this by making the camera a child of the player, but now I want to make the camera orbit the player so I need some custom follow code (I have also tried RenderCam’s follow function, but it seems to ignore the Z axis).

The problem I’m having right now is that the camera always seems to be one frame behind the player, instead of following the player exactly.

camerabug

Here’s the current follow code on the camera:

function on_message(self, message_id, message, sender)
	if message_id == hash("update_pos") then
		local focus_pos = go.get_position(PLAYER_ID)
		local new_pos = focus_pos + vmath.normalize(self.direction) * self.distance
		go.set_position(new_pos)
	end
end

That “update_pos” message is sent just after the player sets its new position in update.

go.set_position(pos + newpos * dt)
msg.post("/camera#orbitcamera", "update_pos")

This seems to happen regardless of whether I update the camera position after the player, or vice versa. What’s the solution here?

2 Likes

Try solution in this thread?

With https://github.com/DanEngelbrecht/LuaScriptInstance

This is of course something that a real solution is needed.

2 Likes

I don’t really understand what’s happening there, what is a “context”? What does it mean to get or set a script instance?

I “fixed” this problem earlier by adding lerp to the camera position, which makes this problem unnoticable. It’s technically solved now, but I’d like to try and understand what’s happening in that library before I edit the title.

2 Likes

The render context is not normally allowed to use the go context. As in, in a render script you can’t call go. functions, same with GUI you can’t call go. functions, and all vice versa. GUI can’t call render., GO scripts can’t call render. or gui. functions.

A way to solve this is to change the script instance to allow you to call functions which normally would not be allowed. Which is something that should be done with caution.

Using smoothing is a good bandage to the problem. You could also have the camera try to smooth toward the direction of the ball moving so that you can see a little further as you move.

1 Like

Heh, we were just talking about this problem in the Rendercam thread. It’s kind of a Defold engine limitation.

Each game object has a Local position (relative to its parent), which is what you set with go.set_position(). They also have an “Absolute”/“World”/“Global” position (summed up from all parent positions) which is used to render them in the right place. The engine only updates objects’ World pos from their Local pos at certain times.

Since your Rendercam camera can be the child of any object in your game, it needs to base its calculations on a World position. So what happens is: you modify the Local position of your player, and then the camera, but Rendercam calculates stuff based on its own World position, before that World position has been updated to reflect the new Local position.

Something to try:

  • Don’t use messages. Messages are delayed. Set your player position and your camera position from a script’s update() function (not in on_message()).
  • Does it work if the camera is a child of the player? That can still work if you add an extra “swing arm” game object to your player. Make the camera a child of this object, offset by the appropriate distance from your player. Then to orbit the camera you just need to rotate the “swing arm” object.
    • (you’ll still need to do this in update(), not on_message().)
4 Likes

That’s brilliant! Way easier than trying to turn a math-heavy Unity orbit camera tutorial into a Defold camera. Here’s the finished camera:

finishedcam

The only change I made was to unparent the swing arm (the camera is still a child of that object) and then use lerp to smoothly move the swing arm’s position to the player position. I’m going to be using this technique a lot, thanks.

8 Likes

This child object approach is also a good technique for 2d objects with sprite components that need to be offset or dynamically corrected, as I don’t think it’s possible to modify the sprite position property during runtime.

3 Likes

What about msg.post("@render:", "use_fixed_projection", { near = -10, far = 10, zoom = 3.5 })? That is being called from a GO script.

The ability to communicate with messages is something they all share.