Tazer Cop is a top down shooter with wave based survival. The player has just the one weapon, but it can be powered up for a brief amount of time with items dropped by the elite cubes.
The game world is set in present day, but Primitive shapes have invaded Earth and assimilated the chav population. You are Tazer Cop, a super Cop with a modified Tazer that allows him to shock the invaders, sending them back to their ships in high orbit.
I have made a vertical slice of the game, which has been coded and setup so that it can be easily built upon and changed for new levels and enemy types. Everything you see I have made by using Maya, Photoshop, Zbrush and Unity.
I began by making all the main building assets in Maya then arranging them so that they resembled a small town. The playing space turned out to be quite large in the end and it changed the camera view I originally had in mind.
I was going to go for a 45 degree top down perspective, but it would mean losing the verticality of the levels upper buildings during play due to the camera clipping through it.
In the end I went for the orthographic view but with a perspective camera looking directly down. This was also easier to code with mouse look controls.
I test all my assets in Unreal to make sure the second UV sets work for light maps. As you can see from the finished level at the top of this page, the boundary became a bit tighter so that the player will never see the void beyond the edge.
Misery Town is completely custom built and every asset is my own creation. I enjoy taking photos of cool textures when I am out and about, despite the strange looks I occasionally get. Much of what you see is from my camera, but a large majority is either hand painted or downloaded from environment textures, royalty free.
I am still working out the in's and out of Unity and getting the best from it visually. I realise that to achieve this, I will need go down the custom shader route, but for now the design is my primary focus.
Score, Wave Number, Total Kills and Kills Left are shown top centre of the screen. This updates in real time.
A radar shows the nearest threats to the player and updates in real time. Due to the size of the level this was an important feature.
Animated beating heart for player health and a Revive capsule details how many lives Tazer Cop has. Health is dropped by common enemy types and additional revives are earnt based on score.
Ammo bar in blue details the players total ammo count. Each shot of the weapon minuses 1 percent on the bar. Ammo regenerates slowly and is capped at 60 if below that number. Streetlamps with lightning symbols are fast regen points the player can replenish 10% ammo from before they go out.
//// Checks what health state the player is in based on when they take damage or get healed ///
//// Player.CS Script that handles taking damage, heart states and when player can revive ///
if (health > 75 && health <= 100)
if (health > 50 && health <= 75)
if (health > 25 && health <= 50)
if (health > 0 && health <= 25)
I thought it would make for a cool design feature, that instead of having just an image of a static heart or collection of hearts like in Zelda, the player has instead an animated heart that changes through various states of injury like the face in Doom based on how low or high their health is in game.
The animator state in Unity allows you to script when the heart should be in certain states. The arrows are there so that when the player collects more health the heart reverses back to a healthier version.
In the extract from my Void Update function from Player.CS, the script above tells the Animator what state it should be playing by cycling through integers. So the gold state as shown in the Animator screenshot I have above is the heart at 100%, because it is the starting default state it has an integer of zero. From there it cycles up from zero to 3. Not shown in the script above is the integer states 4, 5 and 6. These handle states when the player is dead, during a revive state and being revived.
I made and hand drew all the hearts in the sprite sheet in Photoshop. Keeping each heart state at 8 columns made for a nice medium in animation so that it looked quite snappy when beating.
I based the design of Tazer Cops weapon on current Tazer weapons currently out in use by real police forces. I used shadowbox in Zbrush to paint an outline of the shell then beefed it up so that the weapon was still compact but looked like it had a bit more weight to it.
It also needed to look like you could add attachments to it such as laser dots and a scope.
In-game, Tazer Cops ammo meter can be filled by standing near street lamps. The script below details how I achieved this.
To avoid collecting ammo crates, the gun also has a soft regeneration cap up to 60. This regen is much slower.
///////// Attached to the Player Character ////////
void OnTriggerStay (Collider other)
if (other.gameObject.tag == "regenLampAmmo")
//Debug.Log ("Inside Regen Zone");
/////// currentGun inherits the function called in this script Gun.CS //////
public void LampActivate()
if(useAmmo && !isInLampZone)
if(currentAmmo < totalAmmo)
lampActive = true;
//////// StartCoroutine begins this function /////////
isInLampZone = true;
while (lampActive && lampRecharge != maxRecharge && currentAmmo < 100)
superChargeText.renderer.enabled = true;
batteryText.renderer.enabled = false;
currentAmmo += 1.0f;
lampRecharge += 1.0f;
yield return new WaitForSeconds (lampRegenRate);
isInLampZone = false;
superChargeText.renderer.enabled = false;
To break this down. The TriggerOnStay activates when the player collides with an invisble sphere on each streetlamp in the level. This sphere is tagged regenLampAmmo.
If the players ammo is less than 100 then the function inside the gun script is called, which then starts a coroutine that iterates a count of ten not shown above.
So the player has 90 ammo, they stand near a streetlamp, it gives them 10 ammo then stops. If they went near a lamp at 95 ammo, it would stop at 100 and continue at another lamp for a further 5 before that lamp blows.
As an extra layer of design, I coded it so that if you leave the trigger area while recharging, the streetlamps light will blow out and you will miss out on getting the full 10 ammo regenerated. In interview face to face I can show this running as described.
The game also has rapid fire and extra damage power-ups.
The spawn waypoints are depicted above as the purple cubes. In the script for my spawn manager they are in an array so that when it comes to instantiating(spawning) an enemy it randomly picks from the list of 6 possible points in the array.
The green lines are some custom collision volumes to keep the player from exiting the playable space and for preventing enemies from going into the void of space never to be seen again.
Where there are no green lines present, the collision is instead being managed by the asset itself.
As I developed the background story of the primitive shapes, it solved the requirement of needing very low poly and simply animated meshes. Due to the primitives assimilating chavs, I could also give them plenty of character in what they wore and how they looked.
The basic chav is worth the least amount of points, these types have very little jewellery and do not wear hats. They do not drop power ups, but they do have a low drop rate for health.
There is a variant of the basic chav that has a crowbar equipped. They have a better drop rate for health, are worth more points and do slightly more damage.
The Elite chavs are worth the most, and have all the jewellery and accessories. They do more damage to the player and can drop power ups for Tazer Cops gun.
There is a fair few pages of script handling each state, so it would make for some heavy reading and a cup of tea if I showed it all on here.
So to summarise:
1. SpawnManager script randomly picks a spawn point in the level and spawns an enemy chosen from an array
2. What state the enemy is in is dictated by the distance they are from the player.
3. Based on the above step, the enemy will generally start in their patrol state, mostly as a group(they're chavs after all!).
4. If they are in chase range of the player, they will speed up and change animation.
5. Once in attack range they will spin and damage the player.
- Should the player manage to get away, they will revert back through the states as shown by the yellow arrows above.
- If the player has zero health(in the process of reviving or dead), the enemies will move away and do nothing.
- Should the player revive and come back to full health, they will follow step number 2.
It took around 4 months to complete Tazer Cop. This was my first character built and animated from scratch.
Tazer's body and weapon was sculpted and painted in Zbrush then a low res mesh was built over the top using Zbrushes Topology tools. From there the mesh was cleaned up in Maya and exported to XNormals for the normal map and texture information.
Finally I rigged and animated the character inside Maya ready for export to Unity. The rigged image details the final polycount and a rig I built following a Gnomon Workshop tutorial.
These were the main images I used as reference in regards to creating the clothes for Tazer Cop inside of Zbrush.
Once I had sculpted the naked version of my character, I then created low poly meshes in Maya for each item of clothing needed.
With the low poly meshes ready, I exported them back into Zbrush and began to shape and sculpt them to his body.
Any copyright regarding these images were respected and were used as reference only, textures were gathered from environment textures and or painted by myself.
The normal map proved to be the trickiest element to get right. The first pass in XNormals for the most part produced a solid looking normal map, but there was a lot of artifacting present.
When I made the low poly mesh over the top of the high poly one, my plan was to keep the character as one skin as much as possible to avoid problems in Unity; with just the holster, hat and head mesh separate. This worked, but due to the asymmetrical nature of the characters chest it caused some problems in weighting and normal map creation.
I increased the raytrace accuracy within XNormals and carefully revised the low poly version to solve the issue. Doing this again I would approach the initial design differently, with a more symmetrical approach to the chest area, and separate any interesting details into separate meshes.