This is the final part a multipart discussion of the camera system I have constructed for my experimental RTS game using Unity3d. In Unity3d RTS Camera Part 1: Data Component, I explained the DataComponent script that would be used to contain and provide all the data for the camera so that all the other components can share data easily. I highly suggest that you start there if you have not read it yet, as the Data Component is essential to the entire camera system. In Unity3d RTS Camera Part 2: Zoom and Rotate, I explained how we could use our Data Component to control zoom and rotation.




For this post we’ll explore the last remaining topic: panning, or scrolling, the camera. Only 1 new file need to be created for this final portion, but it contains the longest method we have seen so far, so there is a lot to go over. When we are through, we’ll have a functioning camera system that pans, zooms, and rotates, with a single script to control all of our data.

Panning the Camera

For our final script, we will create a new C# script in the <project root>/Scripts/Camera folder (or where ever you saved your previous scripts) and name it CameraPan.

Class Properties

For this script we only need one property, and that’s a reference to our CameraData component.

The cameraData property is left without a value as we will define this value when the component starts up.

The Start Method

The Start method is provided by Unity3d as a part of Monobehavior. We will use it as our constructor to define the cameraData property.

Since we need the CameraData script to power this script, the Start method tries to get the CameraData object assigned to the camera. If we have forgotten to add the CameraData script to the camera, then we need to add the script to our camera. Once that is complete, and we have a reference to the script stored in our cameraData property, we can call the storeTarget method on the CameraData script, which is explained in Unity3d RTS Camera Part 1: Data Component.

The FixedUpdate Method

In order to have our camera do anything we need to update it periodically. Unity3d provides 2 built-in methods for this, Update and FixedUpdate. Here I have chosen to use FixedUpdate, but you can just as easily use Update if desired.

This will be the largest method we have and will build, but we will go through it section by section so it all makes sense…

Before launching into the long explanation, let me just summarize quickly. All the code above is assessing if the camera should pan in any direction, and if so, it is moving the camera’s target appropriately. Since the camera is a child of the target, the camera will following along with the target as it moves, effectively panning the player’s view of the game world.

Now, how is it doing this?

First, in order to save us some processing, we check if the player is actively attempting to pan the camera. If they are not, there is no reason to do the additional math over and over again, so we return then and there. This is a deliberate short-circuit for the sake of performance.

Once we know the camera should pan, we make sure the camera’s y-position is always above the ground. The DataComponent’s GetGroundHeight() method returns where the ground is, and we set the camera’s target to rise or fall to that position. Notice there is no lerping being done – the position is just set. You can play with this, of course, but I found no reason to do so. I want the camera’s target to always and immediately have the correct y-value, so the target does not, say, gradually emerge from underground.

Next we have two if/if-else blocks. They represent horizontal and vertical movement, respectively, but otherwise do the same thing. Because the camera can rotate we are never guaranteed that moving left means moving negatively on the x-axis, while moving right means moving positively on the x-axis. Instead, based on the camera’s rotation, left and right requires movement on both the x- and z-axis in a ratio relative to the camera’s current facing. This would be incredibly annoying to compute, except that Unity3d provides us with transform.right, which is a normalized Vector3 that figures out that ratio for us if we were to move right. If we multiply it by -1, then it’s what we need to move left.

Knowing what the ratio is, we can multiply the appropriate normalized x and z values by the distance we wish to pan, as defined in our central DataComponent. With minimal fuss, we now have implemented panning horizontally.

To pan vertically, the same logic is performed, substituting transform.down for transform.right. From there the logical is essentially the same.

Now our newPosition variable holds a Vector3 that represents where we want the camera to move, or pan, to. All that remains is to apply that new position to the camera’s target. We can do that by just assigning the position, but this might not make for a very smooth transition. Instead, in that last block we lerp towards the new point, allowing the underlying Unity3d engine to calculate based on our easing value of cameraData.panSpeed * Time.deltaTime  how to move gradually towards the intended point. The camera will move much smoother and feel a little more dynamic this way. Unfortunately, lerping can be a little intensive, so feel free to forgo it if you want to optimize.

And that it is, our camera will now move it’s target, which will in turn pan the camera.

The Whole CameraPan Script

Thanks to the work we did in the DataComponent, the CameraPan script is very straight forward. Add it to the camera object in the Unity3d editor and you should be able to use the keyboard to move the camera, or through positioning the mouse near the edge of the screen.

Conclusion

That does it for my camera system. I’ll admit it is not a perfect system – I still believe there are efficiencies to find and edge cases to account for. I’m still iterating on it a little myself. Nonetheless, it was a good learning experience, and I hope that someone else can gain some insight from what I’ve put together. If there are updates, I’ll post them. Comments are welcome, especially constructive suggestions.

If you missed the first or second parts of this series, you can catch them at Unity3d RTS Camera Part 1: Data Component and Unity3d RTS Camera Part 2: Zoom and Rotate.