How to Make Video Games 3

How to Make Video GamesWelcome back to How to Make Video Games! This time I’ll finish up the Pong game. If you’ve watched the previous parts you’ve learned all about : Collision Detection, Animation, AI Controlled Competitors, Physics, Keyboard Input, Unity User Interfaces, Splash Screens, Sound Effects, Background Music, Build Settings and more.

All of the code used can be found below and here are the sounds and artwork used. Up next I’ll make the most profitable arcade game in history Space Invaders!!!

If you like videos like this consider donating $1 on Patreon

[googleplusone]

Code for Pong

AIPaddle.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AIPaddle : MonoBehaviour {

	// Reference to the ball
	public Ball theBall;

	// Default ball speed
	public float speed = 30;

	// lerp is used to smooth out movement over time
	// 
	public float lerpTweak = 2f;

	// Reference to the Rackets Rigidbody component
	private Rigidbody2D rigidBody;

	// Use this for initialization
	void Start () {

		// Get reference to the attached Rigidbody
		// component
		rigidBody = GetComponent<Rigidbody2D> ();
	}

	void FixedUpdate () {

		// Check if the ball y position is > racket y position
		if (theBall.transform.position.y > transform.position.y)
		{
			Vector2 dir = new Vector2(0, 1).normalized;

			// Lerp receives 2 vectors and smoothes the movement over time
			rigidBody.velocity = Vector2.Lerp(rigidBody.velocity, dir * speed, lerpTweak * Time.deltaTime);
		}
		else if (theBall.transform.position.y < transform.position.y)
		{
			Vector2 dir = new Vector2(0, -1).normalized;
			rigidBody.velocity = Vector2.Lerp(rigidBody.velocity, dir * speed, lerpTweak * Time.deltaTime);
		}
		else
		{
			Vector2 dir = new Vector2(0, 0).normalized;
			rigidBody.velocity = Vector2.Lerp(rigidBody.velocity, dir * speed, lerpTweak * Time.deltaTime);
		}
	}

}

Ball.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// Needed to manipulate the UI
using UnityEngine.UI;

public class Ball : MonoBehaviour {

	// Ball default speed
	public float speed = 30;

	// Reference to the balls Rigidbody component
	private Rigidbody2D rigidBody;

	// Reference the AudioSource for the Ball
	private AudioSource audioSource;

	// Use this for initialization
	void Start () {

		// Get reference to the attached Rigidbody
		// component
		rigidBody = GetComponent<Rigidbody2D> ();

		// Calculate velocity for the ball
		rigidBody.velocity = Vector2.right * speed;
	}

	// Called when the ball collides with anything
	void OnCollisionEnter2D(Collision2D col){

		// col provides info on the object the ball hit
		// If it is the left paddle do this
		if ((col.gameObject.name == "LeftPaddle") || (col.gameObject.name == "RightPaddle")) {
			handlePaddleHit (col);
		}

		if ((col.gameObject.name == "WallBottom") || (col.gameObject.name == "WallTop")) {

			// Call for SoundManager to play the wall sound
			SoundManager.Instance.PlayOneShot (SoundManager.Instance.wallBloop);
		}

		if ((col.gameObject.name == "LeftGoal") || (col.gameObject.name == "RightGoal")) {

			// Call for SoundManager to play the goal sound
			SoundManager.Instance.PlayOneShot (SoundManager.Instance.goalBloop);

			if (col.gameObject.name == "LeftGoal") {

				increaseTextUIScore ("RightScoreUI");
					
			} else if (col.gameObject.name == "RightGoal") {

				increaseTextUIScore ("LeftScoreUI");

			}

			// Change the balls position on the game board to its starting
			// position
			transform.position = new Vector2(-1.133788f, 0.1743597f);
		}
	}

	// Calculate where the ball hits the paddle by dividing
	// the ball's y coordinate by the paddles height
	// If the ball hits above the midpoint ricochet up
	// and vice versa
	float ballHitPaddleWhere(Vector2 ball, Vector2 paddle,
		float paddleHeight){
		return (ball.y - paddle.y) / paddleHeight;
	}

	void handlePaddleHit(Collision2D col){

		// Pass the balls position, the paddles position,
		// the height of the paddle
		float y = ballHitPaddleWhere (transform.position,
			col.transform.position,
			col.collider.bounds.size.y);

		// Calculate direction of ball
		// A vector is a line pointing from an origin
		// to a point x, y
		// Magnitude is the length of the line
		Vector2 dir = new Vector2();

		// If (0,1) is straight up and down is (0, -1), 
		// normalized would change our vector into a value 
		// between 0 and 1
		if (col.gameObject.name == "LeftPaddle") {
			dir = new Vector2 (1, y).normalized;
			Vector2 dir2 = dir = new Vector2 (1, y);
			Debug.Log ("Dir : " + dir + "Dir2 : " + dir2);
		}

		if (col.gameObject.name == "RightPaddle") {
			dir = new Vector2 (-1, y).normalized;
		}

		// Change the velocity / direction of the ball
		// You assign a vector to velocity here
		rigidBody.velocity = dir * speed;

		// Call for SoundManager to play paddle sound
		SoundManager.Instance.PlayOneShot (SoundManager.Instance.hitPaddleBloop);
	}

	// Increases the score the the text UI name passed
	void increaseTextUIScore(string textUIName){

		// Find the matching text UI component
		var textUIComp = GameObject.Find(textUIName)
			.GetComponent<Text>();

		// Get the string stored in it and convert to an int
		int score = int.Parse(textUIComp.text);

		// Increment the score
		score++;

		// Convert the score to a string and update the UI
		textUIComp.text = score.ToString();
	}


}

ContinuePlayingMusic.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ContinuePlayingMusic : MonoBehaviour {
	
	// Update is called once per frame
	void Update () {

		// Don't destroy the background music when a new
		// scene loads
		DontDestroyOnLoad(gameObject);
	}
}

MovePaddle.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MovePaddle : MonoBehaviour {

	// Speed rackets move
	public float speed = 30;

	void FixedUpdate(){

		// GetAxisRaw returns a value representing whether
		// W or Up (1), S or Down (-1), or Nothing (0)
		// are being pressed
		float vertDirection = Input.GetAxisRaw ("Vertical");

		// Set the velocity of the racket in the vertical direction
		// Velocity will be movement direction * speed
		GetComponent<Rigidbody2D> ().velocity = new Vector2 (0, vertDirection) * speed;
	}

}

SoundManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SoundManager : MonoBehaviour {

	// Holds the single instance of the SoundManager that 
	// you can access from any script
	public static SoundManager Instance = null;

	// All sound effects in the game
	// All are public so you can set them in the Inspector
	public AudioClip goalBloop;
	public AudioClip lossBuzz;
	public AudioClip hitPaddleBloop;
	public AudioClip winSound;
	public AudioClip wallBloop;

	// Refers to the audio source added to the SoundManager
	// to play sound effects
	private AudioSource soundEffectAudio;

	// Use this for initialization
	void Start() {

		// This is a singleton that makes sure you only
		// ever have one Sound Manager
		// If there is any other Sound Manager created destroy it
		if (Instance == null) {
			Instance = this;
		} else if (Instance != this) {
			Destroy (gameObject);
		}

		AudioSource theSource = GetComponent<AudioSource> ();
		soundEffectAudio = theSource;

	}

	// Other GameObjects can call this to play sounds
	public void PlayOneShot(AudioClip clip) {
		soundEffectAudio.PlayOneShot(clip);
	}
}

SplashScreen.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// Used to switch scenes
using UnityEngine.SceneManagement;

public class SplashScreen : MonoBehaviour {

	// The next scene to load
	public string sceneToLoad;

	// Time to pause before loading next scene in seconds
	public int secTillSceneLoad;

	// Use this for initialization
	void Start () {

		// Call function OpenNextScene after a set number of seconds
		Invoke("OpenNextScene", secTillSceneLoad);
	}
	
	// Update is called once per frame
	void OpenNextScene () {

		// Load defined scene
		SceneManager.LoadScene(sceneToLoad);

	}
}

Leave a Reply

Your email address will not be published. Required fields are marked *