While prototyping out a recent project, I found it quite easy to make an interesting, dynamic camera with StrangeIoC serving as the backbone. Once setting up the necessary bindings and creating unique Signals that will be dispatched throughout, certain stateful information and a View to perform Unity-specific Camera operations can be achieved with ease.

I’ve decided to split this up into several parts. The first being initial Strange setup and business logic, allowing time for proper unit test coverage; the second focusing on implementing the view in Unity; and perhaps eventually a follow-up on behavior testing the areas the unit tests don’t cover. Unfortunately, the only BDD libraries I’ve seen require an iOS/Android Pro license for .NET Sockets usage.

Further reading assumes you have gone through the wonderful Strange Documentation and have some basic knowledge of inversion-of-control concepts and mixing in Unity scripting:

Demo Scene

Download Sources

Provided along with this series is an updated *.unitypackage including all source and demo files; since distributing this for free, I decided to use the assets and scene from everyone’s favorite 3rd Person Platformer tutorial, created by Unity. If you would like to just view the sources and not sift through the demo assets, they are also available and kept up-to-date on GitHub.

Context Bindings

Starting out with the Context which will hold our camera, I generally follow the Multiple Context example included in Strange and include the camera as part of the GameContext. This way we can share similar behavior such as startup, reset, endgame and other states in any kind of level.

Model Setup

To hold certain state about our camera, we will set up a simple Model to hold information such as its current CameraState (Cinematic or Character), a list of its current CameraWaypoints to smoothly interpolate position and rotation over a duration, and some helper methods.

Signal Setup

Signals differ quite a bit from Events especially in the parameters we can pass around. Here are definitions for all the Signals that will be used throughout, placed in a single file. We will need a way to change between Cinematic and Character state, perform a sequenced operation at the start of the demo, and a way to tell when the initial flythrough completes so we can switch to clamping to the character.

Command Setup

Now that we’ve attached Signals to our Commands when setting up the bindings, we can define what will happen once these are dispatched.

Calling the CameraSequenceSignal will set off the first Command (in order) then when released, the second will dispatch. In the demo, we rely on some timing defined and controlled by Unity, such as taking a duration of time to move and rotate between waypoint-to-waypoint. Since this can be seen as an asynchronous operation, we will need to tell the sequencer to hold off on going to the next Command until we are told to release.

Once the FlythroughCompleteSignal is called from the View, it should release the current Command and go to the next, which simply attaches the camera to the defined target.

At this point, all we need to do is fire our sequenced Signal. This can be done at any time in one’s game, such as a level start scenario, or endgame sequence.

GameLoop Start

For the sake of this demo, as soon as the GameContext initializes, it will attach a GameLoop script by way of the StartSignal to our contextView object. The contextView in this case is the same GameObject that the GameRoot is attached to. Then, the GameLoop can dispatch the sequenced Signal as soon as it receives a Start command; all of this will be handled for us thanks to Strange.

That pretty much covers the business logic side that we will need to set up this camera system. It may seem like a lot at first, but fine-tuning it and switching between states, supplying it with proper state, is all extremely easy now.

Unit Test Coverage

At this point, we can test some specific units that we created in this demo. I won’t bother creating tests for hooking up the bindings and making sure they were bound specifically since that is entirely tested for us in Strange’s unit tests. We would gain no value from doing this again ourselves. Instead the unit tests will prove that each Signal called the Command logic and verify by creating some doubles that assert our specific values.

Test Doubles

I won’t go too far into depth here about how test doubling in Strange should work and what to test. I wrote a blog post on this already. Instead I will provide the proper doubles that are necessary for our tests:

Common SetUp

Since Strange is unit tested itself, we won’t need to unnecessarily re-test areas already covered. Common to all our unit tests will be this SetUp which will instantiate similar bindings including using our test doubles.

CameraStateSignal Test

The first test will make sure that updating our camera’s state property operates correctly by sending the Signal with the state we wish to check and making sure it bubbles up to our View.

CameraSequenceSignal Test

The next test runs the sequenced Signal similar to how we initiated the flow of our demo. It makes sure both Commands are called and asserts that we manually release the first command via our FlythroughCompleteSignal.

This wraps up the Strange side of things. The rest should involve purely Unity-specific scripting which can’t (and shouldn’t) be unit-testable since it deals heavily with input, graphics, and specific pipeline code that can’t be stubbed or mocked out.

View Part II of A Strange Camera System in Unity >>