Talking about Tipsy Tower game, C#, Game development and Unity3D.
The tutorial series about Tipsy Tower continues with another update, this time using Unity (I told you I am taking it seriously). I added a lot of features to the first prototype, like the zoomable camera – which actually zooms, unlike the one I did with Phaser – a gradient background, a timer which only counts but does not stop the game at the moment, for a testing purpose, a score system and a responsive canvas background. Click to drop a crate. Although most of the concepts have been explained in the completely commented source code, some features like the canvas background and texts would need a video or a series of images to be explained in depth. While I am thinking about the best way to show you how to create a game from scratch with Unity, have a look at the code, I commeted it line by line and you’ll surely learn something from it, especially if you read the first step before digging into this version.crateScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class crateScript : MonoBehaviour {
// boolean variable to tell us if the crate already hit something
public bool hit = false;
// this function is executed when the game object become ivisible, in this case
// when it leaves the stage
void OnBecameInvisible(){
// destroying game object
Destroy (gameObject);
}
// this function is executed once the crate hits something
void OnCollisionEnter2D(Collision2D coll) {
hit = true;
}
}
movingCrateScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movingCrateScript : MonoBehaviour {
// this function is executed at each frame
void Update () {
// since we can't just change the x position of a game object, we have to create a position which is the same
// as the original game object position
Vector3 newPosition = transform.position;
// this is how we can set a tween, using PingPong on a variable (in this case the time),
// so that it is never larger than length and never smaller than 0.
// The returned value will move back and forth between 0 and 4.4f
newPosition.x = Mathf.PingPong (Time.time * 5.0f, 5f) - 2.5f;
// and finally we apply new position to game object's position
transform.position = newPosition;
}
}
MainScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// you need to use this class to access UI elements
using UnityEngine.UI;
public class MainScript : MonoBehaviour {
// crateObject is the physic crate prefab
public GameObject crateObject;
// a variable used only inside this class, for PRIVATE use.
// canDrop is true if the player can drop a crate, false when the player can't
private bool canDrop = true;
// Unity can zoom camera, so we will store into this variable the size of the orthographic projection, that is the level of zoom
private float targetCameraOrtho = 5f;
// this will be a time-based game, so here's a variable to keep track of the time left
public int timeLeft = 60;
void Start(){
// Invoking the method called "tick" (first argument) in 1 (second argument) second, then repeatedly every 1 (third argument) second
InvokeRepeating ("tick", 1, 1);
// calling updateUIText, will write timeLeft value inside "TimeText" text
updateUIText ("TimeText", timeLeft.ToString ());
}
// this function is executed at each frame
void Update () {
// find an object called "movinCrate" and store it into movingCrate variable
GameObject movingCrate = GameObject.Find ("movingCrate");
// checking for player input AND canDrop to be true.
// it means the player can drop a crate
if (Input.GetButtonDown ("Fire1") && canDrop) {
// set canDrop to false
canDrop = false;
// calling cangeAlpha function to set movingCrate's alpha to zero (completely transparent)
changeAlpha (movingCrate, 0f);
// instantiate a crateObject instance and assign it to physicsCrate variable
GameObject physicsCrate = Instantiate(crateObject);
// set physicsCrate position as the same of movingCrate position
physicsCrate.transform.position = movingCrate.transform.position;
}
// declaring an array of game objects
GameObject[] droppedCrates;
// filling the array with all objects with tag "Physics Crate"
droppedCrates = GameObject.FindGameObjectsWithTag("Physics Crate");
// in maxHeight variable we will store the maximum crate height
int maxHeight = 0;
// score is calculated in real time
int score = 0;
// this boolean variable will tell us if all crates have landed or hit something
bool allCratesLanded = true;
// looping through droppedCrates array
foreach (GameObject droppedCrate in droppedCrates){
// looking for crateScript reference
crateScript crateReference = droppedCrate.GetComponent<crateScript>();
// hit is now crateReference.hit
bool hit = crateReference.hit;
// if the crate already hit something...
if(hit){
// getting crate height
int crateHeight = Mathf.RoundToInt ((droppedCrate.transform.position.y + 4.09f) / 0.77f);
// update max crate height
maxHeight = Mathf.Max(maxHeight, crateHeight);
// if crate height is greater than zero... (when falling down the hill, it could be -1)
if (crateHeight > 0) {
// ...update score
score += crateHeight;
}
}
else{
// if the crate did not hit anything yet, then allCratesLanded is false
allCratesLanded = false;
}
}
// calling updateUIText, will write score value inside "ScoreText" text
updateUIText ("ScoreText", score.ToString ());
// if the player can't drop and all crates have landed...
if(!canDrop && allCratesLanded){
// setting canDrop to true again, now the player can drop another crate
canDrop = true;
// setting moving crate alpha to 1
changeAlpha (movingCrate, 1f);
// getting moving crate position
Vector2 currentCratePos = movingCrate.transform.position;
// updating current crate y position
currentCratePos.y = maxHeight * 0.77f + 5 * 0.77f;
// moving the crate by actually applying the transform position
movingCrate.transform.position = currentCratePos;
// change camera zoom according to moving crate vertical position
targetCameraOrtho = 5 + (currentCratePos.y - 3.5f) / 2f;
}
// getting camera instance
Camera camera = Camera.main;
// if we need to update camera zoom...
if (camera.orthographicSize != targetCameraOrtho) {
// zooming in/out moving from current camera ortographic size to target camera orthographic size
camera.orthographicSize = Mathf.Lerp (camera.orthographicSize, targetCameraOrtho, Time.deltaTime * 2);
// once we zoom, we also need to update camera position to keep the ground at the bottom of the stage
Vector3 position = camera.transform.position;
// subtracting 5 (the initial orthographic size) to current ortographic size will do
position.y = camera.orthographicSize - 5f;
// updating camera position
camera.transform.position = position;
}
}
// this function changes the alpha of a game object
void changeAlpha(GameObject sprite, float alpha){
// since we can't just change the alpha, we have to create a color which is the same
// as the original game object color
Color color = sprite.GetComponent<Renderer>().material.color;
// then we change color's alpha
color.a = alpha;
// and finally we apply new color to game object's color
sprite.GetComponent<Renderer>().material.color = color;
}
// this function is called each second
void tick(){
// decreasing time left
timeLeft--;
// calling updateUIText, will write timeLeft value inside "TimeText" text
updateUIText ("TimeText", timeLeft.ToString ());
// if timeLeft is zero...
if (timeLeft == 0) {
// stop invoking the timer
CancelInvoke ();
}
}
// this function will update a UI text
void updateUIText(string textElement, string textToWrite){
// finding a game object called as textElement argument
GameObject canvasElement = GameObject.Find (textElement);
// getting the Text compment inside the game object
Text scoreToDisplay = canvasElement.GetComponent<Text> ();
// updating text content
scoreToDisplay.text = textToWrite;
}
}
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.