Skip to content

Godot Camera2D

I wanted to consolidate Camera2D-specific notes since Godot Engine is already out of control. 👀

If you have camera smoothing enabled and want to change the position of the camera without smoothing, you may be tempted to do this:

Camera.PositionSmoothingEnabled = false;
Camera.Position = whatever;
Camera.PositionSmoothingEnabled = true;

This doesn’t work because the smoothing takes place over time, but more importantly, this is exactly why ResetSmoothing exists!

Camera.Position = whatever;
Camera.ResetSmoothing(); // 👍

There is one case I found where I do need to turn off smoothing and enable it later, and it’s when using both camera smoothing and physics interpolation.

Camera.PositionSmoothingEnabled = false; // if you don't turn this off, the camera will seemingly slide to the new position
Camera.Position = Player.GlobalPosition;
Camera.ResetPhysicsInterpolation();
await node.ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);
Camera.PositionSmoothingEnabled = true;

Note: if physics interpolation is still causing the camera to take multiple frames to move, look at [[Physics interpolation#Another cause AnimationPlayer or AnimationTree, or Tween]].

Goal: get zooming to work like it does in Google Maps where the camera zooms on the mouse cursor. Normally, cameras in Godot zoom on their center, not some target’s center.

The theory behind this is that you want to perform the following steps:

  • Center the camera on the mouse, that way the mouse’s position and the camera’s center are the same.
  • Zoom in.
  • Move the camera so that it’s centered on the mouse’s screen coordinates. Remember: the mouse won’t have moved during this time.
# (this code all goes in a Camera2D node. Make sure you set anchor = Camera2D.ANCHOR_MODE_DRAG_CENTER)
# Center camera on mouse
global_position += get_local_mouse_position()
# Zoom now that we have our new center
zoom = new_zoom_value
# Move the camera back to where the mouse used to be
global_position -= get_local_mouse_position()

Gotchas:

  • Make sure you’re not binding this to both the key up and down of an input, or this won’t work. E.g. I had code just checking for MOUSE_BUTTON_WHEEL_UP, which caused two events to be fired per frame. Presumably Godot didn’t run its own internal update of a transform somewhere, so the correct zoom/positioning code on my end led to incorrect results.
  • This method used to work in Godot 3, but it doesn’t work in Godot 4 and I can’t figure out why. Godot inverted how zooming works (in Godot 3, bigger numbers meant you were zooming out), but I still couldn’t get it to work even with that in mind.

Jittery camera movement when hitting boundaries

Section titled “Jittery camera movement when hitting boundaries”

I ran into an issue when making Skeleseller where I put camera-update code in _PhysicsProcess instead of _Process. As a result, people with high-refresh-rate monitors ran into issues with panning to the sides of the map or zooming in and out to the maximum extents.

I just needed to use the correct _Process method to accommodate refresh rates.

GetCamera2D (kw: get_camera_2d) returns null

Section titled “GetCamera2D (kw: get_camera_2d) returns null”

E.g.

When this happened to me, I was doing GetTree().Root.GetCamera2D(), and it was returning null. It turns out that it’s because I had a scene tree like this:

  • Root
    • SubViewportContainer
      • SubViewport
        • Camera2D
        • ElementWithAScriptTryingToGetTheCamera

The problem is that my active camera is in a SubViewport, but GetTree().Root will return the rootmost node, not your SubViewport. To fix this, just call GetViewport().GetCamera2D(), and it’ll get the nearest viewport ancestor.