Learn Godot 4 by Making a 2D Platformer — Part 10: Game Camera

christine - Jul 27 '23 - - Dev Community

*You can find the links to the previous parts at the bottom of this tutorial.

So far, just like Donkey Kong, our game uses the default camera that captures the entire game map. This means we can see everything at once. Every 2D platformer has a different type of camera. Some follow the player, and others scroll across the screen.

The type of camera that you end up choosing for your game depends on the experience that you are trying to build for your player base. Cameras that move quickly and capture small areas work well in games or levels where you are trying to build intensity, whereas slower cameras that capture larger areas build a more relaxed gameplay experience. The size, focal point, and speed of the camera depend on your end goal.

Since we are building our game off of inspiration from Donkey Kong, we don’t need to change our camera, but because we also want to be unique, we will go through three different ways to create cameras in Godot.


WHAT YOU WILL LEARN IN THIS PART:

  • How to work with a Camera2D node.
  • How to animate a Camera’s offset values.
  • How to estimate and define camera limits.

FIXED CAMERA

With a fixed camera, the camera captures either the entire screen or large chunks of the game map. The player can then be seen and moved inside this chunk. The camera will follow the player linearly until the player reaches the end of the screen or the chunk. In our game, our entire game map — or chunk — is being captured.

One example is Donkey Kong:

Godot 2D Platformer

The game is already capturing the entire window of our Main scenes — and therefore we won’t need to add a camera to our scene to serve as our fixed camera.

Godot 2D Platformer

PLAYER FIXED CAMERA

With a player-fixed camera, the camera is set to follow the player’s centered position. This means that the camera’s relative position depends on the position of the player

One example is Mega Man:

Godot 2D Platformer

To add a fixed camera to our player, we need to add a Camera2D node to our Player scene. This node forces the screen (current layer) to scroll following the Player scene. This makes it easier (and faster) to program scrollable scenes than manually changing the position of CanvasItem-based nodes.

Godot 2D Platformer

If you run your scene now, and your player runs around the map, the camera should be focused on them.

Godot 2D Platformer

We can move the camera “closer” to the player by changing its Zoom value in the inspector panel.

Godot 2D Platformer

If you run your scene now, your camera should be zoomed in on the player!

Godot 2D Platformer

If you ran around your map, you would’ve noticed that the camera captures the grey background that is beyond our game’s border. We don’t want our camera to capture those areas, instead, we want the camera to stop when it reaches the outer limits of our map. To do this, we will need to change our Camera2D node’s limits. This will limit the left, right, top, and bottom scroll limit in pixels. You can change your limits in your Inspector panel underneath “Limit”.

Godot 2D Platformer

Godot 2D Platformer

To get the value of these limits, you can drag off of the left and right ruler in your Main scene to get the coordinate values of the edges of your game’s border.

Left Limit

Godot 2D Platformer

Right Limit

Godot 2D Platformer

Top Limit

Godot 2D Platformer

Bottom Limit

Godot 2D Platformer

This is what I ended up with:

Godot 2D Platformer

Now if you run your scene, your camera should follow your player and it should stop when reaching the outer edges of your game borders!

Godot 2D Platformer

Godot 2D Platformer

OFFSET FIXED CAMERA

Sometimes we want our camera to only follow the player after exceeding a certain window as opposed to always snapping at the player. This will give the player some space before scrolling the camera back in focus, which allows us to see things that are in front of us. We can do this by changing our camera’s offset value. This is the camera’s relative offset which will allow us to look around.

One example is Mario Bros:

Godot 2D Platformer

If you already have a Camera2D node, disable it in the Inspector panel by de-selecting the Enabled property.

Godot 2D Platformer

Add a new Camera2D node. We also want to animate our camera to slowly move left or right depending on our player’s direction, so also add an AnimationPlayer node.

Godot 2D Platformer

Create two new animations in your Animations panel, call them “move_left” and “move_right”.

Godot 2D Platformer

Godot 2D Platformer

For both, add a new Property Track animation.

Godot 2D Platformer

Connect it to your Camera2D (your new camera, not the disabled one).

Godot 2D Platformer

Select the offset property, since we want to have our camera in a position that isn’t centered on our player.

Godot 2D Platformer

Change the length of your animation to how quickly you want your camera to move sides (transition). I’m going with a test value of 0.5. Then insert a keyframe at the start and end of your animations.

Godot 2D Platformer

Godot 2D Platformer

Now, at the first value of your move_left keyframe (0), we need to change our offset values. I want my camera offset to be 100 pixels to the right, and -50 pixels up.

Godot 2D Platformer

Godot 2D Platformer

Then at the second value of your move_left keyframe (0.5), we need to change our offset values to the starting values of our move_right animation. I want my camera offset to be -100 pixels to the left, and -50 pixels up.

Godot 2D Platformer

At the first value of your move_right keyframe (0), we need to change our offset values. I want my camera offset to be -100 pixels to the right, and -50 pixels up.

Godot 2D Platformer

Godot 2D Platformer

Then at the second value of your move_right keyframe (0.5), we need to change our offset values to the starting values of our move_left animation. I want my camera offset to be 100 pixels to the left, and -50 pixels up.

Godot 2D Platformer

I also want our camera to be a bit zoomed in, so change the Zoom value to a larger value such as “2” (this is optional). We’ll have to change the limits of our camera in our code since the limits will depend on the offset of our camera — since the camera’s position will be different in each direction.

Godot 2D Platformer

We also want our camera to transition smoothly, so enable the camera’s “Position Smoothing” property which will smoothly move the camera towards its target position at position_smoothing_speed. You can change this speed to how quickly you want the camera to transition or follow your player.

Godot 2D Platformer

We also want our transition snapping to be smoother in our animation. We can do this by changing the interpolation mode in our animations. Interpolation tells Godot how to calculate the frame values between keyframes.

These interpolation modes are supported:

  • Nearest: Set the nearest keyframe value.

  • Linear: Set the value based on a linear function calculation between the two keyframes

  • Cubic: Set the value based on a cubic function calculation between the two keyframes

We want to change our interpolation mode from Linear to Cubic for both move_left and move_right animations.

Godot 2D Platformer

In our Player script, we need to create new variables that will capture our player’s current and last directions. We will use these directions to determine whether or not our move_left or move_right animation should play.

    ### Player.gd

    extends CharacterBody2D

    #player movement variables
    @export var speed = 100
    @export var gravity = 200
    @export var jump_height = -110

    # Keep track of the last direction (1 for right, -1 for left, 0 for none)
    var last_direction = 0
    # Check the direction of the player's movement
    var current_direction = 0
Enter fullscreen mode Exit fullscreen mode

If our player’s current_direction is 1, they will be facing right, and if it is -1, they will be facing left. Our player will be facing right at the start of the game, so we have to set the current_direction to be facing right at the start of the game.

    ### Player.gd

    #older code

    func _ready():
        current_direction = -1
Enter fullscreen mode Exit fullscreen mode

Now we’ll need to update this current_direction value continuously throughout our game loop depending on our player’s x velocity value. In a 2D game, when the x component of velocity is positive, it typically indicates movement to the right, and vice-versa to the left. We’ll update this variable in our process() function.

    ### Player.gd

    #older code

    func _process(delta):
        if velocity.x > 0: # Moving right
            current_direction = 1
        elif velocity.x < 0: # Moving left
            current_direction = -1
Enter fullscreen mode Exit fullscreen mode

If our current_direction is different from our last direction, we will play our animation based on our direction value (1 or -1). We also need to update our last direction to be the same as our current direction. This eliminates duplicate transitions, so if we are facing right and we are pressing our right input the move_right animation won’t play again until we change direction.

    ### Player.gd

    #older code

    func _process(delta):
        if velocity.x > 0: # Moving right
            current_direction = 1
        elif velocity.x < 0: # Moving left
            current_direction = -1

        # If the direction has changed, play the appropriate animation
        if current_direction != last_direction:
            if current_direction == 1:
                # Play the right animation
                $AnimationPlayer.play("move_right")

            elif current_direction == -1:
                # Play the left animation
                $AnimationPlayer.play("move_left")

            # Update the last_direction variable
            last_direction = current_direction
Enter fullscreen mode Exit fullscreen mode

We also need to set our limits depending on our direction. You’ll need to test this out for each limit (top, bottom, left, and right) when you’re facing both left and right.

    ### Player.gd

    #older code

    func _process(delta):
        if velocity.x > 0: # Moving right
            current_direction = 1
        elif velocity.x < 0: # Moving left
            current_direction = -1

    # If the direction has changed, play the appropriate animation
        if current_direction != last_direction:
            if current_direction == 1:
                # Play the right animation
                $AnimationPlayer.play("move_right")
                #limits
                $Camera2D.limit_left = -110
                $Camera2D.limit_bottom = 705
                $Camera2D.limit_top = 40
                $Camera2D.limit_right = 1068

            elif current_direction == -1:
                # Play the left animation
                $AnimationPlayer.play("move_left")

                #limits
                $Camera2D.limit_left = 90
                $Camera2D.limit_bottom = 705
                $Camera2D.limit_top = 40
                $Camera2D.limit_right = 1268

            # Update the last_direction variable
            last_direction = current_direction
Enter fullscreen mode Exit fullscreen mode

Your code should look like this.

Now if you run your scene, your camera should follow your player, change direction, and it should stop when reaching the outer edges of your game borders! If your transition is still too sharp, then make your animation length a bit longer to allow for a smoother transition.

Godot 2D Platformer

Godot 2D Platformer

Congratulations on creating your game camera (if you opted to go for a camera that isn’t fixed to your main scene)! In the next part, we’ll be setting up our secondary enemies who will throw and spawn boxes at us on our platform levels.

Now would be a good time to save your project and make a backup of your project so that you can revert to this part if any game-breaking errors occur. Go back and revise what you’ve learned before you continue with the series, and once you’re ready, I’ll see you in the next part!


Next Part to the Tutorial Series

The tutorial series has 24 chapters. I’ll be posting all of the chapters in sectional daily parts over the next couple of weeks. You can find the updated list of the tutorial links for all 24 parts of this series on my GitBook. If you don’t see a link added to a part yet, then that means that it hasn’t been posted yet. Also, if there are any future updates to the series, my GitBook would be the place where you can keep up-to-date with everything!

Godot 2D Platformer


Support the Series & Gain Early Access!

If you like this series and would like to support me, you could donate any amount to my KoFi shop or you could purchase the offline PDF that has the entire series in one on-the-go booklet!

The booklet gives you lifelong access to the full, offline version of the “Learn Godot 4 by Making a 2D Platformer” PDF booklet. This is a 451-page document that contains all the tutorials of this series in a sequenced format, plus you get dedicated help from me if you ever get stuck or need advice. This means you don’t have to wait for me to release the next part of the tutorial series on Dev.to or Medium. You can just move on and continue the tutorial at your own pace — anytime and anywhere!

Godot 2D Platformer

This book will be updated continuously to fix newly discovered bugs, or to fix compatibility issues with newer versions of Godot 4.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .