Cinematic Camera

Needy

In the process of my game, I started to think about an advanced camera system. I wanted to define camera bounding boxes in which a certain type of camera is active. But this was not enough for me as I wanted them stacked. And I wanted to attach these camera bounding boxes as well on moving targets like enemies.

But… Why?

Well, I was thinking of a cool intro where the hero falls down a deep hole. I wanted to zoom close in the beginning and zoom out in the middle part and zoom in on the landing. Furthermore, I wanted to overlay camera bounding boxes to zoom in on certain objects or when I enter or leave a room or level. I was as well thinking of a centered camera for a squared room to see everything in it and as soon I leave this room I wanted my follow camera back. So it’s complicated. And then I thought OK would be cool to have a zoom-in if enemies approach me to give that more focus and this camera bounding box has to follow the enemy… of course.

So it’s all about the cinematic effects I guess.

Whaaa… How?

I think the best is a visualization of my idea.

I tried to describe it in the level itself. The long light blue bounding box across the full room contains a follow camera and is on the bottom of the stack that’s why it’s numbered with a ‘0’. The middle camera bounding box is darker blue and is on top of the following camera and contains a centered camera, which means inside this box the camera will not follow the character but point to the center of the bound box. This box has the number ‘1’ and is on top of the number ‘0’. On top of this, we have a yellow bounding box with a zoomed-in centered camera with the number ‘2’. The higher the number of a bounding box camera the higher its priority. On the right, we see a yellow bounding box with a follow camera with a different zoom.

Ok Show Me!

Now in action

This is pretty neat isn’t it?

And Still… How Did You Do That

OK, I try to explain it with some pseudo-code. Let’s assume we have all the camera bounding boxes and their camera type. Furthermore, we can load these camera types on the fly.

public void updateCamera(float tpf, Vector2 playerPosition) {
    stream()
            .filter(cam -> cam.getAabb().contains(playerPosition))
            .sorted(Comparator.comparingInt(CameraAabbData::getOrder).reversed())
            .findFirst()
            .filter(cam -> cam.getMyCamera() != currentCam)
            .ifPresent(cam -> {
                LOG.debug("Enter camera area with cam data type: " + cam.getType() + " properties: " + cam.getProperties());
                if (cam.getMyCamera() == null) {
                    cam.setMyCamera((MyCamera) feather.instance(cam.getType()));
                }
                currentCam = cam.getMyCamera();
                currentCam.setAabb(cam.getAabb());
                currentCam.setProperties(cam.getProperties());
            });
    currentCam.update(tpf);
}

So in short

  • We check if the player is in the camera AABB
  • We sort the camera AABB due to its order
  • We just take the first, which means the top one (it’s ordered)
  • The next check is to avoid that we set the camera properties on every frame
    • And if there is a camera AABB we check if we already loaded the code (caching)
    • We set the current camera and its properties
  • Last but not least we update the current camera

The object “cam” is just a data holder and often referred as a DTO.

Christian Liesch

Software Developer

4.5 2 votes
Article Rating

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments