Mini-Projects from the Recorded Video Training Archive
Tutorial
Beginner
3 Hours55 Mins
Unity Technologies
Summary
A collection of tutorials originally delivered live covering the creation of small games using older versions of Unity (4.x). Includes steps for making a 2D catch game, a Breakout-style game, and more.
Topics we'll cover
Mini Tutorials
Language
English
Recommended Unity Versions
4.5
Tutorial
Mini-Projects from the Recorded Video Training Archive
1.
2D Catch Game - Pt 1
As an introduction to using Unity's 2D functionality and a sneak peek at the upcoming uGUI system, in this class we will be making a simple catch game using sprites and 2D physics. This will be a walk-through of the game from scratch, including coding all of the main scripts. This session is intended for beginners who have a only a basic familiarity with Unity and are interested in making games in 2D. Tutor: Adam Buckner
Download the assets for this tutorial [Here].

2.
2D Catch Game - Pt 2
As an introduction to using Unity's 2D functionality and a sneak peek at the upcoming uGUI system, in this class we will be making a simple catch game using sprites and 2D physics. This will be a walk-through of the game from scratch, including coding all of the main scripts. This session is intended for beginners who have a only a basic familiarity with Unity and are interested in making games in 2D. Tutor: Adam Buckner
Download the assets for this tutorial [Here].

3.
2D Catch Game - Pt 3
As an introduction to using Unity's 2D functionality and a sneak peek at the upcoming uGUI system, in this class we will be making a simple catch game using sprites and 2D physics. This will be a walk-through of the game from scratch, including coding all of the main scripts. This session is intended for beginners who have a only a basic familiarity with Unity and are interested in making games in 2D. In Part 3, we will add exploding bombs that reduce our score, adding a splash screen and start buttons and more! This will be a short session followed by an open Q&A Tutor: Adam Buckner
Download the assets for this tutorial [Here].

4.
2D Catch Game - Q&A / AMA
This is the Post Session Q&A / AMA that took place after Part 3, which includes questions about Part 3, the entire catch game, 2D, atlases, bone driven 2D animation and more. Tutor: Adam Buckner

5.
Couch Wars: Local Multiplayer Basics
In this live training session we will look at adding local two player coop play to the existing 2D Platformer project which is available on the asset store. We will also add support for controller input, in this case setting up XBox 360 controllers on a Mac.
###PlayerControl###

csharp

using UnityEngine; using System.Collections; public class Enemy : MonoBehaviour { public float moveSpeed = 2f; // The speed the enemy moves at. public int HP = 2; // How many times the enemy can be hit before it dies. public Sprite deadEnemy; // A sprite of the enemy when it's dead. public Sprite damagedEnemy; // An optional sprite of the enemy when it's damaged. public AudioClip[] deathClips; // An array of audioclips that can play when the enemy dies. public GameObject hundredPointsUI; // A prefab of 100 that appears when the enemy dies. public float deathSpinMin = -100f; // A value to give the minimum amount of Torque when dying public float deathSpinMax = 100f; // A value to give the maximum amount of Torque when dying private SpriteRenderer ren; // Reference to the sprite renderer. private Transform frontCheck; // Reference to the position of the gameobject used for checking if something is in front. private bool dead = false; // Whether or not the enemy is dead. private Score score1; // Reference to the Score script. private Score score2; // Reference to the Score script. private int playerNum; void Awake() { // Setting up the references. ren = transform.Find("body").GetComponent<SpriteRenderer>(); frontCheck = transform.Find("frontCheck").transform; score1 = GameObject.Find("Score1").GetComponent<Score>(); score2 = GameObject.Find("Score2").GetComponent<Score>(); } void FixedUpdate () { // Create an array of all the colliders in front of the enemy. Collider2D[] frontHits = Physics2D.OverlapPointAll(frontCheck.position, 1); // Check each of the colliders. foreach(Collider2D c in frontHits) { // If any of the colliders is an Obstacle... if(c.tag == "Obstacle") { // ... Flip the enemy and stop checking the other colliders. Flip (); break; } } // Set the enemy's velocity to moveSpeed in the x direction. rigidbody2D.velocity = new Vector2(transform.localScale.x * moveSpeed, rigidbody2D.velocity.y); // If the enemy has one hit point left and has a damagedEnemy sprite... if(HP == 1 && damagedEnemy != null) // ... set the sprite renderer's sprite to be the damagedEnemy sprite. ren.sprite = damagedEnemy; // If the enemy has zero or fewer hit points and isn't dead yet... if(HP <= 0 && !dead) // ... call the death function. Death (); } public void Hurt(int playerWhoShotMe) { // Reduce the number of hit points by one. HP--; playerNum = playerWhoShotMe; } void Death() { // Find all of the sprite renderers on this object and it's children. SpriteRenderer[] otherRenderers = GetComponentsInChildren<SpriteRenderer>(); // Disable all of them sprite renderers. foreach(SpriteRenderer s in otherRenderers) { s.enabled = false; } // Re-enable the main sprite renderer and set it's sprite to the deadEnemy sprite. ren.enabled = true; ren.sprite = deadEnemy; // Increase the score by 100 points if (playerNum == 1) score1.score += 100; else score2.score += 100; // Set dead to true. dead = true; // Allow the enemy to rotate and spin it by adding a torque. rigidbody2D.fixedAngle = false; rigidbody2D.AddTorque(Random.Range(deathSpinMin,deathSpinMax)); // Find all of the colliders on the gameobject and set them all to be triggers. Collider2D[] cols = GetComponents<Collider2D>(); foreach(Collider2D c in cols) { c.isTrigger = true; } // Play a random audioclip from the deathClips array. int i = Random.Range(0, deathClips.Length); AudioSource.PlayClipAtPoint(deathClips[i], transform.position); // Create a vector that is just above the enemy. Vector3 scorePos; scorePos = transform.position; scorePos.y += 1.5f; // Instantiate the 100 points prefab at this point. Instantiate(hundredPointsUI, scorePos, Quaternion.identity); } public void Flip() { // Multiply the x component of localScale by -1. Vector3 enemyScale = transform.localScale; enemyScale.x *= -1; transform.localScale = enemyScale; } }

LayBombs

using UnityEngine; using System.Collections; public class LayBombs : MonoBehaviour { [HideInInspector] public bool bombLaid = false; // Whether or not a bomb has currently been laid. public int bombCount = 0; // How many bombs the player has. public AudioClip bombsAway; // Sound for when the player lays a bomb. public GameObject bomb; // Prefab of the bomb. public string bombButton = "Fire2_P1"; private GUITexture bombHUD; // Heads up display of whether the player has a bomb or not. void Awake () { // Setting up the reference. bombHUD = GameObject.Find("ui_bombHUD").guiTexture; } void Update () { // If the bomb laying button is pressed, the bomb hasn't been laid and there's a bomb to lay... if(Input.GetButtonDown(bombButton) && bombCount > 0) { // Decrement the number of bombs. bombCount--; // Play the bomb laying sound. AudioSource.PlayClipAtPoint(bombsAway,transform.position); // Instantiate the bomb prefab. Instantiate(bomb, transform.position, transform.rotation); } // The bomb heads up display should be enabled if the player has bombs, other it should be disabled. bombHUD.enabled = bombCount > 0; } }

Gun

using UnityEngine; using System.Collections; public class Gun : MonoBehaviour { public Rigidbody2D rocket; // Prefab of the rocket. public float speed = 20f; // The speed the rocket will fire at. public string gunButton = "Fire1_P1"; private PlayerControl playerCtrl; // Reference to the PlayerControl script. private Animator anim; // Reference to the Animator component. void Awake() { // Setting up the references. anim = transform.root.gameObject.GetComponent<Animator>(); playerCtrl = transform.root.GetComponent<PlayerControl>(); } void Update () { // If the fire button is pressed... if(Input.GetButtonDown(gunButton)) { // ... set the animator Shoot trigger parameter and play the audioclip. anim.SetTrigger("Shoot"); audio.Play(); // If the player is facing right... if(playerCtrl.facingRight) { // ... instantiate the rocket facing right and set it's velocity to the right. Rigidbody2D bulletInstance = Instantiate(rocket, transform.position, Quaternion.Euler(new Vector3(0,0,0))) as Rigidbody2D; bulletInstance.velocity = new Vector2(speed, 0); } else { // Otherwise instantiate the rocket facing left and set it's velocity to the left. Rigidbody2D bulletInstance = Instantiate(rocket, transform.position, Quaternion.Euler(new Vector3(0,0,180f))) as Rigidbody2D; bulletInstance.velocity = new Vector2(-speed, 0); } } } }

PlayerHealth

using UnityEngine; using System.Collections; public class PlayerHealth : MonoBehaviour { public float health = 100f; // The player's health. public float repeatDamagePeriod = 2f; // How frequently the player can be damaged. public AudioClip[] ouchClips; // Array of clips to play when the player is damaged. public float hurtForce = 10f; // The force with which the player is pushed when hurt. public float damageAmount = 10f; // The amount of damage to take when enemies touch the player public SpriteRenderer healthBar; // Reference to the sprite renderer of the health bar. private float lastHitTime; // The time at which the player was last hit. private Vector3 healthScale; // The local scale of the health bar initially (with full health). private PlayerControl playerControl; // Reference to the PlayerControl script. private Animator anim; // Reference to the Animator on the player void Awake () { // Setting up references. playerControl = GetComponent<PlayerControl>(); //healthBar = GameObject.Find("HealthBar").GetComponent<SpriteRenderer>(); anim = GetComponent<Animator>(); // Getting the intial scale of the healthbar (whilst the player has full health). healthScale = healthBar.transform.localScale; } void OnCollisionEnter2D (Collision2D col) { // If the colliding gameobject is an Enemy... if(col.gameObject.tag == "Enemy") { // ... and if the time exceeds the time of the last hit plus the time between hits... if (Time.time > lastHitTime + repeatDamagePeriod) { // ... and if the player still has health... if(health > 0f) { // ... take damage and reset the lastHitTime. TakeDamage(col.transform); lastHitTime = Time.time; } // If the player doesn't have health, do some stuff, let him fall into the river to reload the level. else { // Find all of the colliders on the gameobject and set them all to be triggers. Collider2D[] cols = GetComponents<Collider2D>(); foreach(Collider2D c in cols) { c.isTrigger = true; } // Move all sprite parts of the player to the front SpriteRenderer[] spr = GetComponentsInChildren<SpriteRenderer>(); foreach(SpriteRenderer s in spr) { s.sortingLayerName = "UI"; } // ... disable user Player Control script GetComponent<PlayerControl>().enabled = false; // ... disable the Gun script to stop a dead guy shooting a nonexistant bazooka GetComponentInChildren<Gun>().enabled = false; // ... Trigger the 'Die' animation state anim.SetTrigger("Die"); } } } } void TakeDamage (Transform enemy) { // Make sure the player can't jump. playerControl.jump = false; // Create a vector that's from the enemy to the player with an upwards boost. Vector3 hurtVector = transform.position - enemy.position + Vector3.up * 5f; // Add a force to the player in the direction of the vector and multiply by the hurtForce. rigidbody2D.AddForce(hurtVector * hurtForce); // Reduce the player's health by 10. health -= damageAmount; // Update what the health bar looks like. UpdateHealthBar(); // Play a random clip of the player getting hurt. int i = Random.Range (0, ouchClips.Length); AudioSource.PlayClipAtPoint(ouchClips[i], transform.position); } public void UpdateHealthBar () { // Set the health bar's colour to proportion of the way between green and red based on the player's health. healthBar.material.color = Color.Lerp(Color.green, Color.red, 1 - health * 0.01f); // Set the scale of the health bar to be proportional to the player's health. healthBar.transform.localScale = new Vector3(healthScale.x * health * 0.01f, 1, 1); } }

6.
Creating a Basic Platformer Game
In this live training session we're going to prototype a simple platformer game. We'll cover player movement, create a simple level and add collectible objects.
###SimplePlatformController###

csharp

using UnityEngine; using System.Collections; public class SimplePlatformController : MonoBehaviour { [HideInInspector] public bool facingRight = true; [HideInInspector] public bool jump = false; public float moveForce = 365f; public float maxSpeed = 5f; public float jumpForce = 1000f; public Transform groundCheck; private bool grounded = false; private Animator anim; private Rigidbody2D rb2d; // Use this for initialization void Awake () { anim = GetComponent<Animator>(); rb2d = GetComponent<Rigidbody2D>(); } // Update is called once per frame void Update () { grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground")); if (Input.GetButtonDown("Jump") && grounded) { jump = true; } } void FixedUpdate() { float h = Input.GetAxis("Horizontal"); anim.SetFloat("Speed", Mathf.Abs(h)); if (h * rb2d.velocity.x < maxSpeed) rb2d.AddForce(Vector2.right * h * moveForce); if (Mathf.Abs (rb2d.velocity.x) > maxSpeed) rb2d.velocity = new Vector2(Mathf.Sign (rb2d.velocity.x) * maxSpeed, rb2d.velocity.y); if (h > 0 && !facingRight) Flip (); else if (h < 0 && facingRight) Flip (); if (jump) { anim.SetTrigger("Jump"); rb2d.AddForce(new Vector2(0f, jumpForce)); jump = false; } } void Flip() { facingRight = !facingRight; Vector3 theScale = transform.localScale; theScale.x *= -1; transform.localScale = theScale; } }

SpawnPlatforms

using UnityEngine; using System.Collections; public class SpawnPlatforms : MonoBehaviour { public int maxPlatforms = 20; public GameObject platform; public float horizontalMin = 7.5f; public float horizontalMax = 14f; public float verticalMin = -6f; public float verticalMax = 6; private Vector2 originPosition; void Start () { originPosition = transform.position; Spawn (); } void Spawn() { for (int i = 0; i < maxPlatforms; i++) { Vector2 randomPosition = originPosition + new Vector2 (Random.Range(horizontalMin, horizontalMax), Random.Range (verticalMin, verticalMax)); Instantiate(platform, randomPosition, Quaternion.identity); originPosition = randomPosition; } } }

PlatformFall

using UnityEngine; using System.Collections; public class PlatformFall : MonoBehaviour { public float fallDelay = 1f; private Rigidbody2D rb2d; void Awake() { rb2d = GetComponent<Rigidbody2D>(); } void OnCollisionEnter2D (Collision2D other) { if (other.gameObject.CompareTag("Player")) { Invoke ("Fall", fallDelay); } } void Fall() { rb2d.isKinematic = false; } }

SpawnCoins

using UnityEngine; using System.Collections; public class SpawnCoins : MonoBehaviour { public Transform[] coinSpawns; public GameObject coin; // Use this for initialization void Start () { Spawn(); } void Spawn() { for (int i = 0; i < coinSpawns.Length; i++) { int coinFlip = Random.Range (0, 2); if (coinFlip > 0) Instantiate(coin, coinSpawns[i].position, Quaternion.identity); } } }

PickupCoin

using UnityEngine; using System.Collections; public class PickupCoin : MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () { } void OnTriggerEnter2D (Collider2D other) { if (other.gameObject.CompareTag("Player")) Destroy(gameObject); } }

Reset

using UnityEngine; using System.Collections; public class Reset : MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () { } void OnTriggerEnter2D (Collider2D other) { if (other.gameObject.CompareTag("Player")) Application.LoadLevel(Application.loadedLevel); } }

7.
Creating a Breakout Game for Beginners
In this live training session we look at creating a Breakout style game including basic game mechanics, user interface and a game manager script.
###Paddle###

csharp

using UnityEngine; using System.Collections; public class Paddle : MonoBehaviour { public float paddleSpeed = 1f; private Vector3 playerPos = new Vector3 (0, -9.5f, 0); void Update () { float xPos = transform.position.x + (Input.GetAxis("Horizontal") * paddleSpeed); playerPos = new Vector3 (Mathf.Clamp (xPos, -8f, 8f), -9.5f, 0f); transform.position = playerPos; } }

Ball

using UnityEngine; using System.Collections; public class Ball : MonoBehaviour { public float ballInitialVelocity = 600f; private Rigidbody rb; private bool ballInPlay; void Awake () { rb = GetComponent<Rigidbody>(); } void Update () { if (Input.GetButtonDown("Fire1") && ballInPlay == false) { transform.parent = null; ballInPlay = true; rb.isKinematic = false; rb.AddForce(new Vector3(ballInitialVelocity, ballInitialVelocity, 0)); } } }

GM

using UnityEngine; using System.Collections; using UnityEngine.UI; public class GM : MonoBehaviour { public int lives = 3; public int bricks = 20; public float resetDelay = 1f; public Text livesText; public GameObject gameOver; public GameObject youWon; public GameObject bricksPrefab; public GameObject paddle; public GameObject deathParticles; public static GM instance = null; private GameObject clonePaddle; // Use this for initialization void Awake () { if (instance == null) instance = this; else if (instance != this) Destroy (gameObject); Setup(); } public void Setup() { clonePaddle = Instantiate(paddle, transform.position, Quaternion.identity) as GameObject; Instantiate(bricksPrefab, transform.position, Quaternion.identity); } void CheckGameOver() { if (bricks < 1) { youWon.SetActive(true); Time.timeScale = .25f; Invoke ("Reset", resetDelay); } if (lives < 1) { gameOver.SetActive(true); Time.timeScale = .25f; Invoke ("Reset", resetDelay); } } void Reset() { Time.timeScale = 1f; Application.LoadLevel(Application.loadedLevel); } public void LoseLife() { lives--; livesText.text = "Lives: " + lives; Instantiate(deathParticles, clonePaddle.transform.position, Quaternion.identity); Destroy(clonePaddle); Invoke ("SetupPaddle", resetDelay); CheckGameOver(); } void SetupPaddle() { clonePaddle = Instantiate(paddle, transform.position, Quaternion.identity) as GameObject; } public void DestroyBrick() { bricks--; CheckGameOver(); } }

Bricks

using UnityEngine; using System.Collections; public class Bricks : MonoBehaviour { public GameObject brickParticle; void OnCollisionEnter (Collision other) { Instantiate(brickParticle, transform.position, Quaternion.identity); GM.instance.DestroyBrick(); Destroy(gameObject); } }

DeadZone

using UnityEngine; using System.Collections; public class DeadZone : MonoBehaviour { void OnTriggerEnter (Collider col) { GM.instance.LoseLife(); } }

TimedDestroy

using UnityEngine; using System.Collections; public class TimedDestroy : MonoBehaviour { public float destroyTime = 1f; // Use this for initialization void Start () { Destroy (gameObject, destroyTime); } }

8.
Creating a Casual Jewel Mining Game
In this live training session we look at creating a casual jewel mining game where the player clicks to fire a hook and drag in jewels or rocks before a timer runs out.
###Gun###

csharp

using UnityEngine; using System.Collections; public class Gun : MonoBehaviour { public GameObject claw; public bool isShooting; public Animator minerAnimator; public Claw clawScript; void Update () { if (Input.GetButtonDown("Fire1") && !isShooting) { LaunchClaw(); } } void LaunchClaw() { isShooting = true; minerAnimator.speed = 0; RaycastHit hit; Vector3 down = transform.TransformDirection(Vector3.down); if(Physics.Raycast(transform.position, down, out hit, 100)) { claw.SetActive(true); clawScript.ClawTarget(hit.point); } } public void CollectedObject() { isShooting = false; minerAnimator.speed = 1; } }

Claw

using UnityEngine; using System.Collections; public class Claw : MonoBehaviour { public Transform origin; public float speed = 4f; public Gun gun; public ScoreManager scoreManager; private Vector3 target; private int jewelValue = 100; private GameObject childObject; private LineRenderer lineRenderer; private bool hitJewel; private bool retracting; void Awake () { lineRenderer = GetComponent<LineRenderer>(); } void Update () { float step = speed * Time.deltaTime; transform.position = Vector3.MoveTowards (transform.position, target, step); lineRenderer.SetPosition(0, origin.position); lineRenderer.SetPosition(1, transform.position); if (transform.position == origin.position && retracting) { gun.CollectedObject(); if (hitJewel) { scoreManager.AddPoints(jewelValue); hitJewel = false; } Destroy(childObject); gameObject.SetActive(false); } } public void ClawTarget (Vector3 pos) { target = pos; } void OnTriggerEnter (Collider other) { retracting = true; target = origin.position; if (other.gameObject.CompareTag("Jewel")) { hitJewel = true; childObject = other.gameObject; other.transform.SetParent(this.transform); } else if (other.gameObject.CompareTag("Rock")) { childObject = other.gameObject; other.transform.SetParent(this.transform); } } }

ScoreManager

using UnityEngine; using System.Collections; using UnityEngine.UI; public class ScoreManager : MonoBehaviour { public int score = 0; public int targetScore = 400; public Text scoreText; public Text timeText; public int timePerLevel = 30; public GameObject youWon; public GameObject gameOver; private float clockSpeed = 1f; void Awake () { scoreText.text = ("Score: " + score + "/" + targetScore); InvokeRepeating("Clock", 0, clockSpeed); } void Clock() { timePerLevel--; timeText.text = ("Time: " + timePerLevel); if (timePerLevel == 0) { CheckGameOver(); } } public void AddPoints(int pointScored) { score += pointScored; scoreText.text = ("Score: " + score + "/" + targetScore); } void CheckGameOver() { if (score >= targetScore) { Time.timeScale = 0; youWon.SetActive(true); } else { Time.timeScale = 0; gameOver.SetActive(true); } } }

SpawnJewels

using UnityEngine; using System.Collections; public class SpawnJewels : MonoBehaviour { public int xRange = 10; public int yRange = 3; public int numObjects = 16; public GameObject[] objects; // Use this for initialization void Start () { Spawn (); } void Spawn() { for (int i = 0; i <= numObjects; i++) { Vector3 spawnLoc = new Vector3 (Random.Range (-xRange, xRange), Random.Range (-yRange, yRange), 0); int objectPick = Random.Range (0, objects.Length); Instantiate(objects[objectPick], spawnLoc, Random.rotation); } } }