Activity: Create a scene, add a 3D character controller from the asset store, a simple terrain, and have some cubes with simple audio sounds plus with physics the player can bounce around against
Are you familiar with all the following in Unity:
- Unity Hub
- Unity Interface
- Unity GOs and Components
- Example of materials and basic cube components
- Example of AudioSource Component (+ audio asset) + Audio Listener on camera
- Using Unity Documentation (API)
- Scene Organisation: Parents and Children
- Prefabs
- Console Editor
- Package Manager and Asset Store
- Bring in an FP or TP character controller and terrain
- Adding camera to a character
- Rigidbody and Physics
- Collisions
- Simple scripting of behaviour
- Building a game
_______________
To the right is a folder of Introduction to Unity basics broken up into .mp4 clips. They were an ad hoc recording of the kind of things I nay go through in class, so you can refer to them later.
The total combined length is 1:32:00 minutes, with individual clips varying from a couple of minutes to the longest one on scripting, #16, which clocks out at about 16 minutes.
If watching online, you may want to click on the cog and set the viewing to HD, so the text is crisp :)
NOTE: these videos are for individual student use, not for distribution.
Unity also has its own intro videos, linked to the right, as does Sebastian Lague, an excellent developer with some excellent resources online:
For example, a chest you need a lock pick skill to open, a random dice roll to open, lock skill increases on levelling.
Proper planning and documentation must be demonstrated with:
- Flowcharts showing your game's logic
- Pseudo code
- In-line code comments
Your project must demonstrate understanding and application of:
- Variable declaration
- Variables being set on the basis of conditions being met at runtime
- Converting (casting) variables from type to another (e.g. int to float)
- Variables being set or modified by other variables at runtime
- Variables being set to random values
- Use of operands (such as +, -, /, *, =, ==)
- Use of if then else statements in your code
- Debugs to test the value of variables at runtime
- camelCase naming conventions
- A basic win/loss condition that ends/restarts the game (i.e. game loop)
In-class review of relevant concepts around variables, operators and other basics (see slides for a summary)
Variables
There are many different types of variables (or vars), and each will store only one specific type of data:
int: hold whole numbers, e.g. 0, 1, 2
floats: hold numbers with a decimal point, i.e. floating point numbers, such as 3.56, 1.23, which often have an f after them in Unity, e.g. 3.4f, to distinguish them from int vars when it's not clear, e.g. 2f.
string: hold a series of ASCII characters
bools: are either true or false;
You need to name vars properly, e.g. with meaningful names like myString, myHealth that follow camel case.
public variables are accessible by the entire script plus visible in the Unity Inspector, while private variables are only accessible within the script aka class and not visible in the Unity Inspector.
Declaring/setting variables
In Unity you declare variables by stating if it is public or private, stating its data type, then stating its name, e.g:
public int myHealth;
You can set a variables value when you declare it, e.g.:
public int myHealth = 6;
Or, if it is a public variables, you can set it in the Inspector when the script is attached to a GameObject. What you enter in the Inspector will override any assignment set when the variable is declared, but will be overriden if you subsequently set the variable in script, e.g.
myHealth = 10;
Commenting code
You need to comment code to explain what it does, both for yourself and other people in a team: this is invaluable when you come back to old code and need to modify/extend it!
// for single lines
/* */ for multiple lines
Random numbers
You often need to produce a random number within a specific range in games, to create probability (and simulate dice rolls, if it's an RPG!). You can create random int and float values within a minimum and maximum range:
Random.Range (int)
public int myInt;
myInt = Random.Range(0,11)
This will give us a whole number between 0-10 .
Random.Range (float)
public float myFloat;
myFloat = Random.Range(0f,10f)
This will give us a decimal number between 0.0-10.0 i.e. 6.75f. If we didn’t include the f in our min and max of the Random.Range, then it will only return a whole number i.e. 6.
If statements / if else statements / if else if else statements
If statements check to see if certain statements are true, and use 'operators' to do so:
use < or > when checking if a variable is less than or greater than a value
use = when assigning variables a value
use == when comparing/checking a variable's value
use ! to check a variable is NOT a certain valuable
use && to set a condition whereby two or more conditions are true
if (health <= 0 && alive == false && !dying)
{
Debug.Log ("The character has died!");
}
if else statements and if else if else statements are simply if statements with more control over a series of possible conditions, and highly useful for controlling the flow of actions: e.g. you might change the colour of a player's health bar to green, yellow, orange or red using an if else if else statement checking if the player's health is within specific ranges.
if (health > 90)
{
/*set health bar to green, e.g. referring to a UI element's color */
}
else if (health > 60)
{
// set health bar to yellow
}
else if (health > 30)
{
// set health bar to orange
}
else
{
// set health bar to red
}
In-class review of relevant concepts around functions (see slides for a summary)
Functions:
A function is simply a series of instructions that either are called automatically at certain times (e.g. when the game starts, or each frame, or when explicitly 'called' within a script - or by a different script).
For example, we may have a script called health that declares a variable for health and has three functions: one that handles what happens when damage is taken, one that handles what happens when injuries are healed, and one that handles the character/object's death.
Execution order:
When Unity runs, it 'executes' its scripts and functions in a specific sequence, i.e.:
Editor Mode: it will execute any code related to being in the Unity editor (as opposed to in an executable .exe build file)
Start up: it will execute Start() statements
Updates: e.g. it will execute Update() statements each frame
Rendering: e.g. it will handle rendering of 3D objects in the scene/play view
GUI: e.g. it will deal with any UI elements on top of the scene/play view such as OnGUI()
Teardown: e.g. destroying objects, e.g. OnDestroy()
Knowing the execution sequence is important as we need to know WHEN a line of code is going to be executed, and use default functions to do so:
Start(): anything in this function will happen the moment that script first is loaded in the scene.
Update (): anything in this function will happen EVERY FRAME. This is the engine that drives many scripts.
OnDestroy(): anything in this function will execute when the script/gameObject it is attached to is destroyed
function parameters
When you create a function, you declare the parameters it receives when called and returns when it is finished. You can imagine a bunch of people (aka functions) and as scripts talk to one another they throw a ball (aka variable) back and forth. For example, a bullet GameObject may collide with a player GameObject, and a script on that bullet may want to pass its int damage value (e.g. 5 damage) to int health variable on the player (which will then need to check if the player is injured/dead).
Whenever you see 'void' in a function, it simply means that function is not returning a value.
Scope and privacy of variables/functions
Both variables and functions may be public or private, which affects which other scripts/functions can see and access them. This is important to avoid scripts/functions accidentally changing one another's variables when you do not want them to!
Remember a public variable declared in a script is 'global' and can be accessed by any other script or function and will be editable in the Unity Inspector.
A private variable can only be accessed by the script that declares it, and will not be visible in the Unity Inspector.
When a variable is declared within a function, it only exists and can be modified in/by that function. When the function ends, the variable is cleared from memory.
Note: You also have static variables and functions that are not only global, but there is only one instance of them. For example, you usually would only want one GameManager.cs in your game, so that would be a good candidate for being static, or you may only have one character in a game and its properties may be static.
variable casting
Sometimes you may need to 'convert' variables from one data type to another. This is called 'casting' and is usually fairly straightforward, although not all data types are compatible, , e.g. turning a float to an int is common, but you can't turn a string into a float as they are too different.
float myAwesomeFloat = 5.5f;
int someInt = (int) myAwesomeFloat; // this would = 5;
Activity: You may use the in-class activities from the previous weeks to stand in for Brief 2 as long as you meet the brief requirements. However you also can:
Use the template provided to create up to 10 hero and 10 monster prefabs of your own to add into the game, plus write pseudocode for a different battle resolution (e.g. instead of a flat random value, add conditions for specific weapons, armour, or circumstances, like location of the battle).
Your planning must include a technical design document (TDD), which provides flowcharts and pseudocode, and your project must include comments.
Your project must demonstrate understanding and application of:
- The coding functionality used in Brief 1 (variables and basic game logic)
- Proper use of functions, functions with parameters, and return functions
- Use of either for, foreach or while loops
- Script cross-referencing (e.g. getting data or calling a function from another script)
- The use of lists or arrays in your code
- Instantiating a game object from a collection (e.g. array or list)
- Looping through the items in a collection
- Getting a random object from a collection
- Argument out of range exceptions
- Null / Null References
A simple example would be a game in which two sides are randomly generated from a list of character classes.
Each round they interact e.g. talk or fight, and if defeated are removed from the team. When one team has no
members the other team is declared the winner, whereupon a combat log is generated to show each interaction,
the status of the teams each round, and the final outcome.
Note: If you have finished brief 2, make sure your brief pages are finished with a postmortem, and begin getting feedback from others.
GitHub Repository to download template files:
https://github.com/GarethLockett/GAD170.2-Brief2-class-GameScripting-is-so-OOP-2019.2
In-class review of relevant concepts around functions (see slides for a summary)
Scripts referencing other scripts
Scripts routinely need to interact with one another, e.g. when a door may need to check to see if a character trying to open it possesses the key in its inventory. Three common ways to do this are:
Creating a variable that refers to the script, and assign it in the inspector:
public ScriptName someScript;
During run-time, use GetComponent() to find a script of a specific type attached to a specific game object
GetComponent<ScriptName>() :
Using the Find function, to search child objects for a script of a specific type (this is slower, and not usually recommended):
FindObjectOfType<ScriptName>():
Arrays:
Arrays are just variables that hold multiple variables. A simple example would be an array that indicates the status of players in a 4 player game (i.e. to see if they are playing/not playing the game each could have a bool called isPlaying that is true or false).
Arrays usually declared with a fixed length, and importantly when referring to items in an array they start at 0 and end at one LESS than the number in the array (e.g. array of 10 items is item 0 to 9)
Create an array
public string[] mySuperAwesomeArray;
public SomeClass[] mySuperAwesomeClassArray;
Set/Add item to array
myArray = new int[]{ 10, 5, 4, 6 }; // the {} lets us put some value inside our array.
Check item in array
myArray[0]; // This will access the value inside element 0 of my array i.e. 10.
Remove item from array by recreating it
myArray = new int[]{ 10, 4};
Get length of array
myArray.Length;
Get random element from an array
myArray[Random.Range(0, myArray.Length)];
Lists
Lists are very similar to arrays, but are designed to be easy to add to/extend. A simple example would be a player's inventory, which would have items regularly added to or removed.
Create a list
myList = new List<DataType>(); :
Check item in list
myList[0]; // This will access the value inside element 0 of my list i.e. 10.
Add item to list
myList.add(6); // Will add 6 as a new element at the end of our list.Remove item from list
Get length of list
myList.Count;
Get random element
myList[Random.Range(0, myList.Count)];
Out of range Errors
If you try to check an item that doesn't exist in a list or array, e.g. you try to check the name of a 10th item in a list that only contains 6 items, you will get an out of range error.
looping through arrays/lists with for statements
for(int i=0; i<myArray.Length; i++)
{
// Does this action 3 times and logs out the number each time.
Debug.Log(i);
}
for(int i=0; i<myList.Count; i++)
{
// Does this action 3 times and logs out the number each time.
Debug.Log(i);
}
looping through arrys lists with foreach
foreach(int i in myIntArray)
{
Debug.Log(i);
}
while loops
Int i =0;
While( i > 4)
{
Debug.Log(“i win”);
}
Object-oriented progamming (OOP)
Old programming used to just be one or more large 'god' scripts that stored references to objects and handled everything, e.g. Basic.
Object oriented programming has a compiler/editor that allows you to create virtual objects, like GameObjects, and add scripts to them. The scripts on these objects operate independently, making them less liable to inadvertently affect one another, but also can communicate.
Everything you have done in Unity scripting is object-oriented because you are using GameObjects!
classes, composition, and inheritance
All scripts are classes, i.e. a collection of variables and instructions. By default all unity scripts inherit from class Monobehaviour, which is Unity's base class that includes functions like Update(), OnTriggerEnter() etc that you can use automatically.
However you can nest classes, e.g. create a class within a script, that holds its own variables and instructions.
You are using a 'composition' approach when a GameObject is powered up by adding scripts to it, e.g. a Character GameObject has move.cs , health.cs and fire.cs scripts attached, and this gives it the ability to move, take damage/die, and cause damage.
You are using an 'inheritance' approach when you create a class within a script and create a variable that 'inherit' its datatypes from that class, e.g. you create a class called 'car' with variables for its name, its GameObject, its health, its speed etc, then create a new variable of car that can have its own instances of these values.
public class car
{
string name;
GameObject chassis;
int health;
float speed;
}
public car corvette;
You also are using inheritence when you create a script that inherits an entire other scripts functions, e.g. you create script called CarMotor.cs with variables for the motor's properties plus functions to make the engine work, then create a new script called CorvetteEngine that (instead of inheriting from MonoBehaviour) inherits from CarMotor all its variables and functions, but also can add to them.
public class CorvetteEngine : CarMotor;
Unity-specific functions
Since your Unity scripts 'inherit' from Monobehaviour by default, you have access to some specific unity scripting functions, e.g. regarding input, collisions, triggers.
Inputs
Input.GetKeyDown() - only checks once when the button is pressed down.
Input.GetKey() - Checks/Executes as long as the button is pressed.
Input.GetKeyUp() - only checks when the key is released.
Public KeyCode button;
if(Input.GetKeyDown(button))
{
// Do something
}
Collisions
OnCollisionEnter: When the collision occurs.
OnCollisionStay: When the collision keeps occuring.
OnCollisionExit: when we exit the collision.
void OnCollisionEnter(Collision col)
{
// Do something on collision.
}
Triggers
OnTriggerEnter: When the trigger is first passed in.
OnTriggerStay: When the object is still inside the trigger.
OnTriggerExit: when we exit the trigger.
void OnTriggerEnter(Collider other)
{
// Do something now something has passed into the collider.
}
'this' keyword:
This simply refers to the script that includes the this term
// an enemy could destroy itself by saying
Destroy (this.gameObject)
Activity: Note you can make whatever genre of game you want to for this brief as long as it includes the requirements below, e.g. a 3rd person 3D platformer, a top down view hack and slash dungeon crawl, or a simple first person shooter, but by default:
Extend your work from earlier briefs to create a game level that includes players, NPCs that move/interact, a time constraint, a number of pick-ups, and a door/machine/other object that register and respond when specific interactions have taken place.
For example: you are on a spaceship that is being attacked and you need to find allies and avoid enemies while picking up fresh resources to open doors/re-charge a generator to turn on the shields before the ship is destroyed.
You must create a C# Unity game project that extends your understanding of Object-Oriented Programming (OOP), including:
The coding functionality used in Briefs 1 (variables and basic game logic) and Brief 2 (object-oriented programming (OOP) techniques)
The ability to design and construct a simple, explorable, interactive blockout environment
Identifying the events required for your interactive experience (approved by your facilitator, e.g. health pick-ups, damage zones, avoiding projectiles),
Proper use of collisions and/or triggers associated with those events (e.g. OnTriggerEnter() or OnCollisionEnter()),
The implementation of a simple event system that responds to those collisions and/or triggers (e.g. Unity
Events, or delegates with listeners).
Create/revise your project plan for project 3.
Make a todo list: what scripts do you need to find or make, which one will you do first?
Your project plan should include:
1. A list of objects in your game world.
2. A list of the behavior and characteristics of each object in your game world.
3. A list of how you intend the objects to interact and what consequences will arise from the interaction of objects with different behavior and characteristics.
4. A list of ideas of how you will use code to create the mechanics.
5. A list of how you will use code to get objects to interact by communicating between component scripts.
Start finding example scripts that can help you create the behaviours that you need.
Over the next few weeks we will look at:
Repeating anything you feel you need refreshers on!
NavMesh for character/enemy movement
Enums and State Machines for enemy AI
UnityEvents
Getting/Setting variables
If you are eager and ahead of things, you may build your level with probuilder and look at some resources regarding NavMesh:
Building Navmesh: https://docs.unity3d.com/Manual/nav-BuildingNavMesh.html
NavMesh patrol script: https://docs.unity3d.com/Manual/nav-AgentPatrol.html
Find tutorial videos or example scripts that will give you the knowledge you need to code each of the mechanics that you have planned for your game.
For each planned mechanic, make sure that you have found resources that will show you how to create this mechanic with code.
Your solutions may be messy or hacked together. This is OK at this stage of development. Over future weeks we will refine this. In future classes we will give example that show more effective ways to code more common game functionality and how to code elegant relationships between objects.
3. Make sure that you have watched all the resource videos and read all the resource slides that were provided in week 0.