Tanks 2!

As part of a job application for a games programmer role, I was tasked with following a specification that was given to me to build upon the unity project created in this tutorial. In said spec, I was given a number of tasks, which ranged from very simple (such as limiting the maximum size of the game’s camera so that world boundaries weren’t shown), to tasks far more broad in terms of the desired outcome. An example of the later was a “simple tank customization screen” deliverable.

For the implementation of this idea, I wanted to give the players a large level of choice, while also keeping in tune with the overall aesthetic of the game. Therefore, neither of the most obvious implementations of this, either selecting from a handful of pre-determined colours or using 3 separate RGB sliders, seemed appropriate. In my mind, the former idea seemed too limiting to the players’ choice and almost trivial to implement, while the later seemed too explicit (in terms of data visualisation) and would allow the players’ colour options that might not seem in tune with the toybox aesthetic of the game. I soon realised the solution to this would be an alternative representation of colour to the standard RGB representation that unity uses: HSV. HSV (or Hue Saturation Value) would allow me to limit the player to only 1 dimension of choice, meaning that the player was not bogged down with more information than what was needed for a “simple” customisation screen. This also allowed me to maintain two other dimensions such that all colour options would be cohesive to the overall look of the game.

While considering the layout of this scene, it occurred to me that I could find a more elegant way of having the player selecting their tank’s colour than a simple unity slider. Without fully thinking through the implications of this, I settled on the idea of a ‘radial’ slider around each of the tanks, with the result of the slider’s value being shown in realtime on the tank in the middle.
After multiple failed experiments, I ultimately landed on the following solution. A “hue wheel” parent object for each tank, with an event trigger component which listened for pointer click and drags. These would call a value update method which would query the mouse’s current position in relation to the game object’s transform’s centre. Once this calculation was done, a number of methods are called to update various child objects, such as the position and central colour of the ‘cursor’ child object within the hue wheel, as well as changing the material colours of the tank’s various child render objects, and finally updating the player prefs such that whatever colour is chosen is carried through to the next scene.
As mentioned, alternative solutions were considered before this was settled on, such as having the sliders be world space UI elements, however, this ended up looking rather clumsy and was, overall, needless.

Tanks! UI
Customisation Screen Showcase

Beyond these deliverables, the specification denoted additional consideration would be given to “polish which adds user value inline”. As part of this, I decided to design a minimalistic main menu. The idea was to have the camera rotate around the centre of the level. For this, I created a very simple script for the camera:

void update(){
            transform.RotateAround(target, Vector3.up, Time.deltaTime * rotationSpeed);

After some checks to make sure the camera wouldn’t clip through any of the environment at this radius I moved on to the blur layer. For this, I found a simple GrabPass shader on an old forum thread which worked perfectly for the effect I was looking for and meant I could increase the number of passes in-game (effectively meaning the amount of blur present), allowing me to add further polish that I had in mind further down the line.

I then decided that the title screen still felt a little too static, and as such made another small script to make the title feel a bit more juicy, albeit, without user interaction. For this animation, I simply modulated the scale, x rotation, and x scale, using a sine wave:

float newValue = baseValue + Mathf.Sin(Time.time * frequency) * range;
Tanks! Title
Main Menu Showcase

For the final two details, I created a script in which, from any point during the camera’s orbit, if the scene was advanced (by the player pressing ‘play’), the camera would transition to the position and rotation of the camera in the next scene. This was a simple case of using the Mathf LERP & SLERP functions respectively. Based on how far this process has progressed, the Canvas UI elements alpha levels are updated accordingly. Similarly, the blur shader also needed to be ‘faded out’, however materials cannot be modified in this way, I decreased the ‘size’ parameter of the shader (the number of passes I mentioned earlier) in turn.
The final element of polish I included before submitting was music for the two scenes. This was relatively easy to implement, as I was able to quite painlessly re-purpose an audio manager from a previous project of mine such that the music continued playing once the sceneManager changed scenes. However, I opted to make this a little more interesting, by having two tracks play concurrently (one at full volume, and the other silent), with the latter being a more built upon version of the former track. Then, when the camera began transitioning between songs, I calculated how long this LERP would take, and cross-faded the two tracks over the same amount of time, furthering the illusion of a seamless transition between scenes.

Tanks! Lerp
Camera LERP Showcase

You can find the link to my Git Repo of the final product here (WJSW.xyz/Tanks-2)
and a link to the playable version here (https://wjswebster.github.io/Tanks-2/index.html)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s