Tears are made of camera zoom

The size of the camera can be used to set the mood for the player. Look at this picture:

close-space-man
Guy in space

And then this picture:

far-space-man
Lonely guy in space. Don’t you feel bad for him?

Note the emotional impact! Now that you understand the great value of controlling camera zoom, let’s talk about how I implemented it in our game.

We want our level designers to have the tools to control camera zoom for different areas, like in the image below.

camera
A zoomed-out area and a more narrow section with a zoomed-in camera.

To accomplish this I created a node prefab that holds the target zoom and a trigger collider. This is what they look like in the editor:

editor.png

The player has a script which keeps track of the latest node that it collided with, and slowly moves the zoom of the camera towards the target zoom.

Generic is good

music zones.png
What if Pokémon had the same song for the entire game?

To set the mood for the game we have a spooky ambience looping in the background. But listening to the same song for the entire game will distract the player and force them to buy our OST. This means we want to switch ambience for different areas. But doesn’t the camera nodes sound similar to what we want to do here?

Turns out there are a bunch of stuff that could use the same system as the camera, including checkpoints and events (Like playing a sound or activating a fish).

Node controller UML diagram.png

I refactored the camera node and controller to two abstract classes, which can be derived into the specific functionalities. The node controllers only reacts to the nodes with the same tag as the searchTag member, so a camera controller doesn’t try to use a music node.

Most of the logic should happen in the Node, but if required, the controller can override Update() for example. This is kind of dangerous though, because overriding the function could destroy the implementation if it doesn’t call the base function. To make this safer we could provide abstract functions for the derived classes (like OnSwitch()) and make the important logic private. The searchTag member should also be refactored into something that enforces the user to provide the specific tag.

By using this interface I’ve mass produced node systems for different uses. Let’s end this post by looking at the beautiful result!

all nodes.png
All the checkpoints and music/camera/event nodes

About Erik Säll

2016 Programming