{"id":1067,"date":"2015-01-19T09:37:11","date_gmt":"2015-01-19T09:37:11","guid":{"rendered":"http:\/\/www.nikola-breznjak.com\/blog\/?p=1067"},"modified":"2015-08-10T06:56:48","modified_gmt":"2015-08-10T06:56:48","slug":"advanced-space-shooter-in-unity3d","status":"publish","type":"post","link":"https:\/\/nikola-breznjak.com\/blog\/codeproject\/advanced-space-shooter-in-unity3d\/","title":{"rendered":"How to build an advanced space shooter in Unity3D"},"content":{"rendered":"<p>Followed\u00a0<a href=\"http:\/\/unity3d.com\/learn\/tutorials\/projects\/space-shooter\">this<\/a>\u00a0official tutorial on how to build an advanced space shooter in Unity3D, my own version on\u00a0<a style=\"color: #bc360a;\" href=\"https:\/\/github.com\/Hitman666\/AdvancedSpaceShooter\">GitHub<\/a>, and you can\u00a0<a style=\"color: #bc360a;\" href=\"http:\/\/nikola-breznjak.com\/_testings\/Unity\/AdvancedSpaceShooter\/\">see it in action here<\/a>\u00a0(WSAD to move, mouse click to shoot).<\/p>\n<ol>\n<li>Create a new 2D project, download and import the assets from\u00a0<a href=\"https:\/\/www.assetstore.unity3d.com\/en\/#!\/content\/13866\">https:\/\/www.assetstore.unity3d.com\/en\/#!\/content\/13866<\/a><\/li>\n<li>Save a scene in _Scenes folder and name it <em>Main<\/em><\/li>\n<li>File -&gt; Build settings -&gt; Web player -&gt; Switch platform<\/li>\n<li>Player Settings&#8230; &#8211; define the size<\/li>\n<li>Reorder the layout the way you want but remember to save it by clicking the <strong>Layout<\/strong> button in the top right corner<\/li>\n<li>Drag <strong>Vehicle_play<\/strong> from the <strong>Assets-&gt;Model<\/strong> folder to the <strong>Hierarchy<\/strong>\n<ol>\n<li>Rename to <em>player<\/em>, reset transform origin<\/li>\n<li>Add component -&gt; Physics -&gt; Rigidbody and\u00a0deselect <strong>Use Gravity<\/strong><\/li>\n<li>Add component -&gt; Physics -&gt; Capsule collider, change direction to\u00a0Z-Axis and adjust position of X, and check\u00a0Is Trigger<\/li>\n<li>Click on the <strong>y<\/strong> gizmo of the camera and adjust again<\/li>\n<li>In this example the Capsule collider would suffice, but we can add Mesh collider and this is very detailed but we can also drag a predefined Mesh collider from Models folder to Mesh collider -&gt; Mesh variable which is less detailed but sufficent and better than the Capsule collider\n<ol>\n<li>To see the mesh collider turn off the Mesh renderer<\/li>\n<\/ol>\n<\/li>\n<li>Add Prefabs -&gt; VFX -&gt; Engines -&gt; engines_player to the player object<\/li>\n<\/ol>\n<\/li>\n<li>Reset camera transform origin\n<ol>\n<li>set transform Y to 10, Z to 5 (so that the ship starts at the bottom)<\/li>\n<li>set rotation X to 90<\/li>\n<li>Set Projection to <strong>ortographic<\/strong><\/li>\n<li>Set Size to 10<\/li>\n<li>Set Clear flags to Solid Color<\/li>\n<li>Background black<\/li>\n<\/ol>\n<\/li>\n<li>Edit -&gt; Render settings &#8211; property Ambient light set to Black (0,0,0,255) to effectively turn it off<\/li>\n<li>Lights\n<ol>\n<li>Main light\n<ol>\n<li>Hierarchy -&gt; Create -&gt; Directional light (based on rotation!, not position) and rename\u00a0accordingly<\/li>\n<li>Reset origin position<\/li>\n<li>Set Rotation X = 20, Y = &#8211; 115<\/li>\n<li>Intensity = 0.75<\/li>\n<\/ol>\n<\/li>\n<li>Fill light\n<ol>\n<li>Duplicate the Main light\u00a0and rename accordingly<\/li>\n<li>Rename to Fill light<\/li>\n<li>Reset its rotation only<\/li>\n<li>Set Rotation Y = 115<\/li>\n<li>Set Color to some shade of blue<\/li>\n<\/ol>\n<\/li>\n<li>Rim light\n<ol>\n<li>Duplicate the Fill light\u00a0and rename accordingly<\/li>\n<li>Reset origin position<\/li>\n<li>Color White<\/li>\n<li>Rotation Y = 65,\u00a0X = -15<\/li>\n<li>Intensity = 0.25<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<\/li>\n<li><span style=\"line-height: 1.5;\">Object organization<\/span>\n<ol>\n<ol>\n<li>Create new empty object (ctrl + shift + n)<\/li>\n<li>Rename to Lights<\/li>\n<li>Rest\u00a0transform origins<\/li>\n<li>Move the whole Lights object out of the way by setting the position Y = 100<\/li>\n<\/ol>\n<\/ol>\n<\/li>\n<li><span style=\"line-height: 1.5;\">Background<\/span>\n<ol>\n<li>Hierarchy -&gt; Create -&gt; 3D object -&gt; <strong>Quad<\/strong>;\u00a0rename accordingly<\/li>\n<li>Reset transform origin<\/li>\n<li>Set rotation X = 90<\/li>\n<li>Remove the Mesh Collider component<\/li>\n<li>Drag Assets -&gt; Textures -&gt; tile_nebula_green to the Quad object<\/li>\n<li>Scale X = 15, Y = 30<\/li>\n<li>Shaders; difuse &#8211; mat, specular &#8211; glossy,<strong> unlit -&gt; texture<\/strong> is the one we will use since this makes it independent of the lighting system (it displays the image originally as it looks)<\/li>\n<li>Position Y = -10 because it otherwise overlaps with 0,0,0 player object position<\/li>\n<\/ol>\n<\/li>\n<li>Moving the player ship\n<ol>\n<li>In the Assets folder create folder <strong>Scripts<\/strong><\/li>\n<li>Click on the player and Add Component -&gt; Script -&gt; name it <em>PlayerController<\/em><\/li>\n<li>Drag the created script file to the Scripts folder<\/li>\n<li>You have Update and FixedUpdate. We will use since we are dealing with physics.<\/li>\n<li><\/li>\n<li>\n<pre class=\"lang:default decode:true\">#pragma strict\r\npublic var speed = 12;\r\n\r\nfunction FixedUpdate () {\r\n\tvar moveHorizontal = Input.GetAxis(\"Horizontal\") ;\r\n\tvar moveVertical = Input.GetAxis(\"Vertical\");\r\n\t\r\n\trigidbody.velocity = Vector3(moveHorizontal, 0, moveVertical) * speed;\t\r\n}<\/pre>\n<\/li>\n<li>Input.GetAxis returns a number from 0 to 1 that&#8217;s why you have to multiply<\/li>\n<li>At this point the player ship can go out of the play area, to fix this, use the Mathf.Clamp function:\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\npublic class Boundary extends System.Object {\r\n\tpublic var zMin : float;\r\n\tpublic var zMax : float;\r\n\tpublic var xMin : float;\r\n\tpublic var xMax : float;\r\n}\r\n\r\npublic var speed = 10;\r\npublic var boundary : Boundary; \r\n\r\nfunction FixedUpdate () {\r\n\tvar moveHorizontal = Input.GetAxis(\"Horizontal\") ;\r\n\tvar moveVertical = Input.GetAxis(\"Vertical\");\r\n\t\r\n\trigidbody.velocity = Vector3(moveHorizontal, 0, moveVertical) * speed;\t\r\n\t\r\n\trigidbody.position = Vector3(\r\n\t\tMathf.Clamp(rigidbody.position.x, boundary.xMin, boundary.xMax),\r\n\t\t0,\r\n\t\tMathf.Clamp(rigidbody.position.x, boundary.zMin, boundary.zMax)\r\n\t);\r\n}<\/pre>\n<\/li>\n<li><strong>extends System.Object<\/strong> is used to Serialize the object to be able to be used within other object and visible in the inspector<\/li>\n<li>To add <em>tilting<\/em> when moving:\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\npublic class Boundary extends System.Object {\r\n\tpublic var zMin : float;\r\n\tpublic var zMax : float;\r\n\tpublic var xMin : float;\r\n\tpublic var xMax : float;\r\n}\r\n\r\npublic var speed = 10;\r\npublic var boundary : Boundary; \r\npublic var tilt = 4;\r\n\r\nfunction FixedUpdate () {\r\n\tvar moveHorizontal = Input.GetAxis(\"Horizontal\") ;\r\n\tvar moveVertical = Input.GetAxis(\"Vertical\");\r\n\t\r\n\trigidbody.velocity = Vector3(moveHorizontal, 0, moveVertical) * speed;\t\r\n\t\r\n\trigidbody.position = Vector3(\r\n\t\tMathf.Clamp(rigidbody.position.x, boundary.xMin, boundary.xMax),\r\n\t\t0,\r\n\t\tMathf.Clamp(rigidbody.position.z, boundary.zMin, boundary.zMax)\r\n\t);\r\n\t\r\n\trigidbody.rotation = Quaternion.Euler(0, 0, rigidbody.velocity.x * - tilt);\r\n}<\/pre>\n<\/li>\n<\/ol>\n<\/li>\n<li>Bullets\n<ol>\n<li>Create a new empty object rename to Bolt<\/li>\n<li>Reset transform<\/li>\n<li>Create Quad, reset transform, rename VFX<\/li>\n<li>Add VFX as Child of the Bolt<\/li>\n<li>Rotate X = 90<\/li>\n<li>Drag Textures -&gt;\u00a0fx_lazer_orange_dff to it<\/li>\n<li>Shader -&gt; Particles -&gt; Additive (you can also use Mobile version)<\/li>\n<li>Add component -&gt; Physics -&gt; Rigidbody, deselect Use gravity<\/li>\n<li>Remove the VFX Mesh collider<\/li>\n<li>Select Bolt and add Capsule colider<\/li>\n<li>Change radius and Direction to Z-axis<\/li>\n<li>Check the <em>Is Trigger<\/em>\u00a0checkbox<\/li>\n<li>Add script to Bolt object, name it Mover<\/li>\n<li>Make it a Prefab<\/li>\n<li>Delete it from Hierarchy<\/li>\n<\/ol>\n<\/li>\n<li>Firing Bullets\n<ol>\n<li>PlayerController.js:\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\npublic class Boundary extends System.Object {\r\n\tpublic var zMin : float;\r\n\tpublic var zMax : float;\r\n\tpublic var xMin : float;\r\n\tpublic var xMax : float;\r\n}\r\n\r\npublic var bullet : GameObject;\r\n\r\npublic var speed = 10;\r\npublic var boundary : Boundary; \r\npublic var tilt = 4;\r\npublic var waitPeriod = 0.05;\r\nprivate var nextFire : float;\r\n\r\nfunction FixedUpdate () {\r\n\tvar moveHorizontal = Input.GetAxis(\"Horizontal\") ;\r\n\tvar moveVertical = Input.GetAxis(\"Vertical\");\r\n\t\r\n\trigidbody.velocity = Vector3(moveHorizontal, 0, moveVertical) * speed;\t\r\n\t\r\n\trigidbody.position = Vector3(\r\n\t\tMathf.Clamp(rigidbody.position.x, boundary.xMin, boundary.xMax),\r\n\t\t0,\r\n\t\tMathf.Clamp(rigidbody.position.z, boundary.zMin, boundary.zMax)\r\n\t);\r\n\t\r\n\trigidbody.rotation = Quaternion.Euler(0, 0, rigidbody.velocity.x * - tilt);\r\n}\r\n\r\nfunction Update(){\r\n\tif (Input.GetButton(\"Fire1\") &amp;&amp; Time.time &gt; nextFire){\r\n\t\tnextFire = Time.time + waitPeriod;\r\n\t\tInstantiate(bullet, Vector3(rigidbody.position.x, 0, rigidbody.position.z), Quaternion.identity);\r\n\t}\r\n}<\/pre>\n<\/li>\n<li>Drag the bullet prefab to the bullet variable on the player script<\/li>\n<\/ol>\n<\/li>\n<li>Cleaning up\n<ol>\n<li>Create Cube, rename Boundary<\/li>\n<li>Reset transform origin and place it around the whole game<\/li>\n<li>Turn off Mesh Renderer<\/li>\n<li>Is Trigger on Box collider<\/li>\n<li>Remove the renderer<\/li>\n<li>Add script <em><em>Destroy:<br \/>\n<\/em><\/em><\/p>\n<pre class=\"lang:default decode:true\">function OnTriggerExit(other : Collider)\r\n{\r\n    Destroy(other.gameObject);\r\n}<\/pre>\n<\/li>\n<\/ol>\n<\/li>\n<li>Enemies\n<ol>\n<li>Create an empty game object &#8211; <em>Asteroids<\/em><\/li>\n<li>Reset transform origin, move a bit away along the Z axis<\/li>\n<li>Drag the Asteroid model from the Models folder and place it as a child of the <em>Asteroids<\/em> empty game object &#8211; RTO (reset transform origin from now on)<\/li>\n<li>Click on the EGO (empty game object) and add Physics -&gt; Rigidbody<\/li>\n<li>Deselect Use Gravity<\/li>\n<li>Add -&gt; Physics -&gt; Capsule collider<\/li>\n<li>Add Script:\n<pre class=\"lang:default decode:true\">public var tumble : float;\r\n\r\nfunction Start () {\r\n\trigidbody.angularVelocity = Random.insideUnitSphere * tumble;\r\n}<\/pre>\n<\/li>\n<li>AngularVelocity &#8211; how fast the object is <strong>rotating<\/strong><\/li>\n<li>Remove the <strong>AngularDrag<\/strong> which eventually slows the asteroid to a halt (drag &#8211; <em>trenje for all you Croatian readers<\/em>)<\/li>\n<li>Add script DestroyByContact:\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\nfunction OnTriggerEnter (other : Collider) {\r\n\tif (other.tag == \"Boundary\"){\r\n\t\treturn;\r\n\t}\r\n\t\t\r\n\tDestroy(other.gameObject);\r\n\tDestroy(gameObject);\r\n}<\/pre>\n<\/li>\n<li>Add Tag Boundary to\u00a0<em>Boundary<\/em><\/li>\n<\/ol>\n<\/li>\n<li>Explosions\n<ol>\n<li>\u00a0Adjust the DestroyByContact script:\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\npublic var asteroidExplosion : GameObject;\r\npublic var playerExplosion : GameObject;\r\n\r\nfunction OnTriggerEnter (other : Collider) {\r\n\tif (other.tag == \"Boundary\"){\r\n\t\treturn;\r\n\t}\r\n\t\r\n\t\/\/it will create an explosion on the same position as our asteroid\r\n\tInstantiate(asteroidExplosion, transform.position, transform.rotation);\r\n\t\r\n\tif (other.tag == \"Player\"){\r\n\t\tInstantiate(playerExplosion, other.transform.position, other.transform.rotation);\r\n\t}\r\n\t\r\n\tDestroy(other.gameObject);\r\n\tDestroy(gameObject);\r\n}<\/pre>\n<\/li>\n<li>Drag the needed explosions from the VFX folder<\/li>\n<li>Drag the Mover script to the Asteroid and set speed to -5<\/li>\n<li>Drag Asteroid to a <strong>Prefab<\/strong> folder<\/li>\n<li>Delete it from Hierarchy<\/li>\n<\/ol>\n<\/li>\n<li>Game Controller\n<ol>\n<li>Create EGO\u00a0and rename accordingly<\/li>\n<li>Set tag to <em>GameController<\/em><\/li>\n<li>Add script:\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\npublic var enemy : GameObject;\r\npublic var spawnValues : Vector3;\r\n\r\n\r\nfunction Start () {\r\n\tSpawnWaves();\r\n}\r\n\r\nfunction SpawnWaves(){\r\n\t\r\n\tvar spawnPosition = Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);\r\n\tvar spawnRotation = Quaternion.identity;\r\n\t\r\n\tInstantiate(enemy, spawnPosition, spawnRotation);\r\n}<\/pre>\n<\/li>\n<li>Outside set values for spawnValues to 6, 0, 18<\/li>\n<\/ol>\n<\/li>\n<li>Add wave of enemies\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\npublic var enemy : GameObject;\r\npublic var spawnValues : Vector3;\r\npublic var enemyCount : int;\r\npublic var waitForEnemy : float;\r\npublic var waitForPlayer : float;\r\npublic var waveWait : float;\r\n\r\nfunction Start () {\r\n\tSpawnWaves();\r\n}\r\n\r\nfunction SpawnWaves(){\r\n\tyield WaitForSeconds(waitForPlayer);\r\n\t\r\n\twhile (true){\r\n\t\tfor (var i=0; i&lt;enemyCount; i++){\r\n\t\t\tvar spawnPosition = Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);\r\n\t\t\tvar spawnRotation = Quaternion.identity;\r\n\t\t\r\n\t\t\tInstantiate(enemy, spawnPosition, spawnRotation);\r\n\t\t\tyield WaitForSeconds(waitForEnemy);\r\n\t\t}\r\n\t}\r\n\t\r\n\tyield WaitForSeconds(waveWait);\t\r\n}<\/pre>\n<\/li>\n<li>Destroying explosion animations\n<ol>\n<li>Add new script <em><em>DestroyByTime<br \/>\n<\/em><\/em><\/p>\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\npublic var aliveTime : float;\r\nfunction Start () {\r\n\tDestroy(gameObject, aliveTime);\r\n}<\/pre>\n<\/li>\n<li>Set\u00a0this script on all of the explosion prefabs<\/li>\n<li>Set AliveTime to 2<\/li>\n<\/ol>\n<\/li>\n<li>Audio\n<ol>\n<li>Drag the Audio files to appropriate Explosion Prefabs<\/li>\n<li>For a weapon_player &#8211; drag it to a Player object in Hierarchy and remove the Play on Awake<\/li>\n<li>Update the PlayerController script to:\n<pre class=\"lang:default decode:true\">function Update(){\r\n\tif (Input.GetButton(\"Fire1\") &amp;&amp; Time.time &gt; nextFire){\r\n\t\tnextFire = Time.time + waitPeriod;\r\n\t\tInstantiate(bullet, Vector3(rigidbody.position.x, 0, rigidbody.position.z), Quaternion.identity);\r\n\t\t\r\n\t\taudio.Play();\r\n\t}\r\n}<\/pre>\n<\/li>\n<li>Drag music_background to GameController<\/li>\n<li>Select <em>Loop<\/em> and <em>Play on Awake<\/em><\/li>\n<li>Adjust the volumes\n<ol>\n<li>Player\u00a00.5<\/li>\n<li>Game Controller 0.5<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<\/li>\n<li>Displaying score\n<ol>\n<li>Create -&gt; UI -&gt; Text, rename to ScoreText<\/li>\n<li>Set correct Rect Transform<\/li>\n<li>In the GameController script add:\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\npublic var enemy : GameObject;\r\npublic var spawnValues : Vector3;\r\npublic var enemyCount : int;\r\npublic var waitForEnemy : float;\r\npublic var waitForPlayer : float;\r\npublic var waveWait : float;\r\n\r\npublic var scoreText : UnityEngine.UI.Text;\r\nprivate var score : int;\r\n\r\nfunction Start () {\r\n\tscore = 0;\r\n\tupdateScore();\r\n\tSpawnWaves();\r\n}\r\n\r\nfunction SpawnWaves(){\r\n\tyield WaitForSeconds(waitForPlayer);\r\n\t\r\n\twhile (true){\r\n\t\tfor (var i=0; i&lt;enemyCount; i++){\r\n\t\t\tvar spawnPosition = Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);\r\n\t\t\tvar spawnRotation = Quaternion.identity;\r\n\t\t\r\n\t\t\tInstantiate(enemy, spawnPosition, spawnRotation);\r\n\t\t\tyield WaitForSeconds(waitForEnemy);\r\n\t\t}\r\n\t}\r\n\t\r\n\tyield WaitForSeconds(waveWait);\t\r\n}\r\n\r\nfunction updateScore(){\r\n\tscoreText.text = \"Score: \" + score;\r\n}\r\n\r\nfunction IncreaseCount(){\r\n\tscore ++;\r\n\tupdateScore();\r\n}<\/pre>\n<\/li>\n<li>In the DestroyByContact:\n<pre class=\"lang:default decode:true \">#pragma strict\r\n\r\npublic var asteroidExplosion : GameObject;\r\npublic var playerExplosion : GameObject;\r\nprivate var gameController : GameController;\r\n\r\nfunction Start(){\r\n\tvar gameControllerObject : GameObject = GameObject.FindWithTag(\"GameController\");\r\n\tif (gameControllerObject != null){\r\n\t\tgameController = gameControllerObject.GetComponent(GameController);\r\n\t}\r\n\telse{\r\n\t\tDebug.Log(\"oops\");\r\n\t}\r\n}\r\n\r\nfunction OnTriggerEnter (other : Collider) {\r\n\tif (other.tag == \"Boundary\"){\r\n\t\treturn;\r\n\t}\r\n\t\r\n\t\/\/it will create an explosion on the same position as our asteroid\r\n\tInstantiate(asteroidExplosion, transform.position, transform.rotation);\r\n\t\r\n\tif (other.tag == \"Player\"){\r\n\t\tInstantiate(playerExplosion, other.transform.position, other.transform.rotation);\r\n\t}\r\n\t\r\n\tgameController.IncreaseCount();\r\n\t\r\n\tDestroy(other.gameObject);\r\n\tDestroy(gameObject);\r\n}<\/pre>\n<\/li>\n<li>Drag the ScoreText object to form the reference to it in the GameController<\/li>\n<\/ol>\n<\/li>\n<li>Ending the game\n<ol>\n<li>Create an empty game object and rename it to <em>DisplayText<\/em><\/li>\n<li>Rest transform origin<\/li>\n<li>Add ScoreText to it (drag the Canvas containing it)<\/li>\n<li>Create new UI -&gt; Text (rename to <em>RestartText<\/em>), and place it in the upper right corner<\/li>\n<li>Create new UI -&gt; Text (rename to GameOverText)<\/li>\n<li>Update the script to:\n<pre class=\"lang:default decode:true\">#pragma strict\r\n\r\npublic var enemy : GameObject;\r\npublic var spawnValues : Vector3;\r\npublic var enemyCount : int;\r\npublic var waitForEnemy : float;\r\npublic var waitForPlayer : float;\r\npublic var waveWait : float;\r\n\r\npublic var scoreText : UnityEngine.UI.Text;\r\npublic var restartText : UnityEngine.UI.Text;\r\npublic var gameOverText : UnityEngine.UI.Text;\r\n\r\nprivate var restart : boolean;\r\nprivate var gameOver : boolean;\r\n\r\nprivate var score : int;\r\n\r\nfunction Start () {\r\n\trestart = false;\r\n\tgameOver = false;\r\n\t\r\n\trestartText.text = \"\";\r\n\tgameOverText.text = \"\";\r\n\t\r\n\tscore = 0;\r\n\tupdateScore();\r\n\tSpawnWaves();\r\n}\r\n\r\nfunction Update(){\r\n\tif (restart){\r\n\t\tif (Input.GetKeyDown(KeyCode.R)){\r\n\t\t\tApplication.LoadLevel(Application.loadedLevel);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction SpawnWaves(){\r\n\tyield WaitForSeconds(waitForPlayer);\r\n\t\r\n\twhile (true){\r\n\t\tfor (var i=0; i&lt;enemyCount; i++){\r\n\t\t\tvar spawnPosition = Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);\r\n\t\t\tvar spawnRotation = Quaternion.identity;\r\n\t\t\r\n\t\t\tInstantiate(enemy, spawnPosition, spawnRotation);\r\n\t\t\tyield WaitForSeconds(waitForEnemy);\r\n\t\t}\r\n\t\t\r\n\t\tif (gameOver){\r\n\t\t\trestartText.text = \"R to restart\";\r\n\t\t\trestart = true;\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\t\r\n\tyield WaitForSeconds(waveWait);\t\r\n}\r\n\r\nfunction updateScore(){\r\n\tscoreText.text = \"Score: \" + score;\r\n}\r\n\r\nfunction IncreaseCount(){\r\n\tscore ++;\r\n\tupdateScore();\r\n}\r\n\r\nfunction GameOver(){\r\n\tgameOver = true;\r\n\tgameOverText.text = \"Game over!\";\r\n}<\/pre>\n<\/li>\n<li>Drag the text object to form a reference in GameController object<\/li>\n<li>Update the DestroyByContact with:\n<pre class=\"lang:default decode:true\">if (other.tag == \"Player\"){\r\n\t\tInstantiate(playerExplosion, other.transform.position, other.transform.rotation);\r\n\t\tgameController.GameOver();\r\n\t}<\/pre>\n<\/li>\n<\/ol>\n<\/li>\n<li>Deploy the game\n<ol>\n<li>File\u00a0-&gt; Build settings<\/li>\n<li>Web Player<\/li>\n<li>Build<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Followed\u00a0this\u00a0official tutorial on how to build an advanced space shooter in Unity3D, my own version on\u00a0GitHub, and you can\u00a0see it in action here\u00a0(WSAD to move, mouse click to&hellip;<\/p>\n","protected":false},"author":1,"featured_media":1160,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,41],"tags":[],"class_list":["post-1067","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codeproject","category-unity3d"],"_links":{"self":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/1067","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/comments?post=1067"}],"version-history":[{"count":7,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/1067\/revisions"}],"predecessor-version":[{"id":2030,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/1067\/revisions\/2030"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media\/1160"}],"wp:attachment":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media?parent=1067"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/categories?post=1067"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/tags?post=1067"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}