Wednesday, 30 December 2015

AI, Instantiation/ Destruction of an Object and Player Feedback/ Damage using Object Properties and Loops in my Unity Game

Today's blog post will cover examples of:

-AI
-Instantiation
-Destroying an object
-Visual and physical player feedback
-Damage
-Object properties/ physics behaviours
-And Loops

In my Unity game.

To begin: I have an intelligent Dinosaur enemy that incorporates AI, instantiation and the destruction of a harmful projectile, and also this instantiated fireball damages the player, which then shows visual feedback to the player as a damage warning and physical feedback where it knocks back the player in the direction they were moving, back onto the safer platform. This Dinosaur enemy is incredibly creative compared to many typical platformer enemies, and shows a range of techniques that have been incorporated into its AI. I also have a spikes game object as another way to injure the player, which are much more static than the Dinosaur enemy as they simply sit in place and hurt the player if the Bird touches them. I added these two as there needs to be more than one way for the player to get hurt in the game, since the Dino enemy alone would get boring, so there needs to be variety in the dangers of my game world (another way to strike a sense of fear and tension are the bottomless pits in my game if the player falls off the stage, talked about earlier in the collision detection blog post, these pose a much higher risk to the player. As if they fall down a hole they must restart the whole level since that's common convention many 2d platformers follow, whereas they can take 2 points of damage from the Dino/Spikes before the bird dies).

As an example of artificial intelligence used in my Unity game, I included an enemy Dinosaur with a very distinct attack pattern: Where when the player gets close (within a set distance inside the game object's properties, this means that I can freely change the wake range for any instance of a Dinosaur in the game, and it will attack from that set distance), the Dino will jump up out of the ground and surprise the player. When hiding only its eyebrows pop out of the ground as a clue to the more observant player, and when it wakes up the Dino then shoot fireballs at the Bird through instantiation (the fire rate and fireball speed can also be adjusted) that you must dodge or you'll take one point of damage. It is intelligent in the fact that the Dino can hide again when the player goes too far away, and it even turns around if the player goes either side of it. And since the player purposely can't kill the enemies, the game is much more stealth-based than the traditional platformer games. Here's an example of the code that allows it to work and a picture of the Dinosaur's sprite (created by me in Photoshop):


Sample of the Dino's code:

' {

distance = Vector3.Distance(transform.position, target.transform.position);

if(distance < wakeRange) //If the distance (as a numerical value) to the Bird is smaller (closer) than the wakeRange value (set to 6 in the Dino's properties inside the Inspector View), then wake up the Dino
{

awake = true;
Attack(lookingRight);

}

if(distance > wakeRange) //If the distance is bigger (further away) than the wakeRange, make the Dino continue to, or go back to, sleep
{

awake = false;

}

}'


This script basically checks to see the Bird's position from the Dino, and then compares it to the value set for the 'Wake Range' variable. If the player's number is smaller than the Wake Range, then they are nearby and the Dino can wake up then shoot. If the number is higher, then the Bird is still too far away and the Dino will carry on sleeping. I added this into the game as it helps make the AI feel more alive and cunning, and adds a good layer of strategy to the game where the player can't just blindly charge through a level since there are hidden traps to watch out for!

Also as an example of debugging I've used for my Unity game, I had to debug it since the Dino is supposed to be able to spot the player and jump out of hiding, but was never able to spawn a fireball to damage the player with. Meaning it couldn't injur the player at all! I used 'Debug.Log ("TEST");' for the Dino Turret to find the big problem, as that line of code writes 'TEST' into the console when it's been triggered depending on the portion of the C# code it's situated in. So I wrote it in the section of every major element of the code; such as detecting the player, rising up after spotting them, the bird colliding with it's collision cones to spot them and the attacking portion of the code. And I finally found the problem to lie in the attacking portion of the code, as the text 'TEST' printed into the console on every other step, showing it works fine, but didn't work for the attacking function. It meant that somewhere between the bird colliding with the Dino's field of vision, and instantiating a projectile to hurt the player, something went wrong. I got it to eventually instantiate fireball by adding the attack code after the Dinosaur wakes up (rather than in the attacking section that it references), as shown below:


Debugging code for the Dino waking up, and how Debug.Log helped find the problem:

'if(distance < wakeRange) //If the distance (as a numerical value) to the Bird is smaller (closer) than the wakeRange value (set to 6 in the Dino's properties inside the Inspector View), then wake up the Dino { awake = true; Attack(lookingRight);
Debug.Log("TEST"); }'


The Debug.Log message that I received in the Unity Console when everything is working as intended. The debug code essentially goes just below the section of your code you want to debug, so for example when you put it in the collision section of the code, if the player ever collides with that object, this message will appear in the console, so you know everything is working well! 


The Dinosaur originally was just going to wake up when the player approached from a set distance, and actually attack when the player touches the small collider cones either side of it as its field of view. I eventually scrapped this idea however, since it was visually strange for the Dino to jump up and stare-down the player, even being in possession of a ranged attack, but only choose to shoot the Bird when it gets much closer. I feel the final product for the Dino was a much better outcome, and even though the sprite of the Dino is completely static (which was created by me in Photoshop, as compared to many other sprites I've used in this project that are sourced royalty free online from Open Game Art), it is still actually animated using the Unity Animator, so that it jumps in and out of the ground using a spritesheet that is also made by me. The code for the collider cone went largely unused in the end, but still exists in the game, here's an extract of it to show how it works:


Collision cone code sample:

' void OnTriggerEnter2D(Collider2D col) //Conditional statements to decide what to do when the player comes in range
{
if(col.gameObject.tag == "Player") //See if the trigger that collides with the cone is the Bird or not, since it's tagged with 'Player'
{

if(isLeft)
{
dinoTurretAI.Attack(false); //Player is in the left trigger, not right and isLeft defaults to false
}

else
{
dinoTurretAI.Attack(true); 
}
}
}'

Essentially how it works is if the Bird (the only game object with the tag of 'Player', assigned in the Unity inspector used to make that game object individual, or part of a set that your code can reference), collides with the trigger cone either side of the Dino, then it will signal to attack, otherwise by default the attack script is set to false so the Dino doesn't constantly open fire. I changed this in the end for the better, as the code that runs now is more optimised to play since it only needs to run in one script, and not two.

The Dino's colliders, note the two cone shaped trigger boxes on either side of it. These used to be its 'line of sight'.


Next up is damage in my game. Both the Fireballs shot out of the Dino and Spikes will damage the player, who has a maximum health of 2 (I did this because they originally had 5 health, but upon testing the game felt too easy with 5 hit-points and posed less of a challenge. Where with 2 pieces of health the difficulty is there, but it's still slightly forgiving since it gives the player small amount of room for error and isn't completely brutal to play compared to if they only had 1 chance). It essentially removes 1 from the Bird's current health variable (which automatically sets itself to 2 when the game starts, since that's the value of the max health variable and the current health will continually drop from that number in-game). Here's the damage code they both share which is inside the 'Player' script, which essentially checks to see that if the object which collides with the Bird is tagged with 'Spike' or 'Bullet', and then it applies the damage to them by reducing the value of the Bird's current health (I put all of the collision scripts with various objects that hurt the Bird together in the Player script, as it simply saves space and is easier to find than a searching through lots of different scripts to find each object that can hurt the player):



Damage code upon collision with the Bird:

' public void OnTriggerEnter2D(Collider2D col){ //Much simpler and efficient damage code in just a few lines, where if the player collides with the object tagged with 'Spike', do damage to them
if (col.gameObject.tag == "Spike") {
curHealth -= 1; //Remove 1 piece of health from the player, so they take 2 hits to die (as the max is 2)
anim.Play ("Bird_Damage", -1, 0f); //gameObject.GetComponent<Animation>().Play ("Bird_Hurt"); //After the collision play the bird's hurt animation as visual feedback to the player that they have just been hit

//Player knockback from spikes 1
StartCoroutine (Knockback (0.02f, 250, transform.position)); //Time it takes to get the knockback is 0.02 seconds, with a power of 350. It affects the position of the player. Coroutine function is used as it's the only way you can start an IEnumerator function that's in the Player script. For testing I originally had StartCoroutine(player.Knockback(0.02f, 250, player.transform.position));, but after many errors in the console I removed the player text as I didn't need to reference a script the code is already in.

}

if (col.gameObject.tag == "Bullet") { //Same code but for the fire shot out by Dinos instead
curHealth -= 1;
anim.Play ("Bird_Damage", -1, 0f);

StartCoroutine (Knockback (0.02f, 250, transform.position));

Destroy (GameObject.FindWithTag("Bullet")); //When collided with destroy the game object tagged with 'Bullet' (which is the fireball)

}
}'

I originally had a separate damage script for the Spikes and Fireball, but as mentioned previously it was just much more convenient to keep them all together under one 'OnTriggerEnter' script. Which is why both of these objects are so similar, and even share the same public void as the collectable Coins I talked about previously! The Spikes and Fireball collisions contain code that play the Bird's 'damaged' animation and knock them back after being triggered, which is a form of visual and physical feedback I talk about with the knockback script. Also the Fireball has an extra line of code which is designed to destroy itself once it collides with the Bird, which is explained in further detail when I talk about instantiation.

 (These are the Fireball and Spike sprites used in my game, which match the pixel art style very well.)



Whenever the player takes damage, I have also included visual and physical feedback to the player so they are aware they've taken damage, in order to alert them and say what just happened was bad without directly saying it every time. When the Bird is damaged in-game, they will then show a 'shocked' expression (since the lore of my character is that they change colour and appearance depending on how they're feeling) and violently flash yellow looking shocked, then turn red looking angry, using the Unity Animator as a form of visual feedback to the player to show that what happened was a negative thing. (The code to play this animation is included in the Fireball and Spikes collision code.) I did this over-the-top animation through a form of games design that teaches the player by showing, not telling the player to watch out everytime they're hit after the initial tutorial.

Since I felt this was not enough, if the player gets hit they'll also fly backwards in the opposite direction they were moving in, so if they walk off a platform onto spikes they'll be flung backwards onto a safe surface as a safety-net type of feature (but the code is rigged so if the player lands directly on the spikes after a high jump, they'll die. It knows if the player walked off onto it or jumped onto it depending on the horizontal movement speed), to give them another chance before they have to restart the whole level again because of a mistake. Here's the an extract of my C# script for the knockback player feedback code using a loop (and how it modifies my Bird object's properties and physics behaviour depending on the movement speed):


Bird knockback code 2 (the 1st part is in the collision section of the script):

'//Player knockback from spikes 2
public IEnumerator Knockback(float knockDur, float knockbackPwr, Vector3 knockbackDir){ //Dur is how long the force is added, power is the force strength and direction is the agnle the bird will fly when hit

float timer = 0; //Counting the time

rb2d.velocity = new Vector2 (rb2d.velocity.x, 0);

while( knockDur > timer) { //When the knock duration is grater than the time on the timer

timer+=Time.deltaTime; //Counts using seconds and adds to the timer

rb2d.AddForce(new Vector3(knockbackDir.x * -100, knockbackDir.y + knockbackPwr, transform.position.z)); //Apply a force of knockback to the rigid body. To do this get the knockback in the opposite direction the bird is moving across the x axis, and plus the knockback power on the y axis for a constant upwards push. Z doesn't get used as it's a 2d game. The spikes are also slightly rigged, in the fact if a player is careless and just walk off the edge onto the spikes, they'll be bounced back onto the platform as a safety net feature, whereas if they purposedly jump down directly on top of the spikes, they will be killed instantly in-game

}

yield return 0; //A yield return is needed to end an IEnumerator loop

}'

This code uses a counting function to loop the code, in order to constantly repeat the code in a loop, so the Spikes can knockback at a constant distance on the Y axis, and uses negative numbers to push the player backwards along the X axis. It does this over a set period of time and repeats the code constantly. The code essentially counts up with the delta time line (which counts at exactly 1 second relative time) until it's greater than the timer value set in the Unity Inspector of the Spikes game object and it means the Spikes can apply the force to the Bird by modifying the object's properties, changing its physics behaviour and launches away them depending on the Bird's current situation/ position. The yield return is used to stop the looping code. All of this is done for a reason, to add a more varied feel to the Bird's knockback and not just have them get flung back in exactly the same way everytime, but instead add variety to it. The code also works to get the Bird knocked back onto a platform safely, as if they approach the Spikes at a faster speed then they're knocked back further to compensate for the time they spend travelling in the air, which is shown by the line that knocks the Bird back by -100, which is times in the opposite direction.


The Fireball game object itself is designed to instantiate into existence from the game objects attached to the Dino, called either ShootPointLeft or ShootPointRight, and destroy itself when it collides with the player. This is both to balance the game and for optimisation purposes. If the fireball didn't destroy itself when it hurt the player then they could be damaged twice in succession, causing the player to die instantly from their low health and the game would feel unfair to play. It also optimised the game because if each fireball that spawned didn't get destroyed, eventually if the Dino kept shooting there could be potentially hundreds of fireballs running at once which would slow down the game dramatically on PCs that are geared less towards gaming. This is following professional industry practises, since having projectiles get destroyed after they've served their purpose and now clog up the game's memory is a standard procedure in most games. Here is the code the Dino's script uses to spawn a Fireball into the game when attacking on the left: (The code for attacking left is identical but just reversed without the exclamation mark inside the conditional if statement.)


Portion of attacking code to instantiate Fireball:

' bulletTimer += Time.deltaTime; //Cooldown code, the timer increases by 1 every second. And if the timer is greater than or equals to the shoot interval, aim at the player

if (bulletTimer >= shootInterval)
{

Vector2 direction = target.transform.position - transform.position; //Direction the Dino will shoot (towards the player as they are the target), the code will return a direction
direction.Normalize();

if (!attackingRight) //Instantiation code for the left of the Dino, spawning the fireball into the game to hurt the player

{
GameObject bulletClone;
bulletClone = Instantiate(bullet, shootPointLeft.transform.position, shootPointLeft.transform.rotation) as GameObject; //Spawns the projectile to the left of the Dino (at the ShootPoint's position), and casts the fireball as a game object into the game world
bulletClone.GetComponent<Rigidbody2D>().velocity = direction * bulletSpeed; //Once the bullet clone (clone of the real object) is created, set the fireball's rigid body velocity in the direction of the player at the speed set by the variable (100)

bulletTimer = 0; //The code will loop, by counting up again and restarting the timer, and once it's reached the shoot interval, the Dino will spit out another fireball. Rinse and repeat, as the Dino shouldn't be able to shoot 100 bullets a second for example

}'

Basically this code is another example of using Loops in my prototype. A loop is incredibly useful here so the code can constantly run at a fixed rate until the conditional statement requirements stop being met (so if the Bird goes out of range). The code is designed to think: if the Bird is to the left of the Dino, instantiate a Fireball Bullet from the Prefab assigned in the Inspector (I use these to spawn multiple objects that have the same properties as each other, and it's also useful for placing Coins like I mentioned before). The Bullet clone is named bulletClone, and is coded to shoot in the direction and angle of the target (which is the Bird when assigned in the Inspector), and is spawned as an in-game object. When the Bullet is shot the timer will reset to 0, looping the code again and thus counting back up until the shoot interval value is met (so in this case in 1.8 seconds as assigned in the Inspector), and once it counts up to 1.8 seconds the Dinosaur will shoot out another Fireball, reset the timer and start all over again.

1.8 seconds was specificity chosen as upon testing with various values, it felt the most balanced. It means that the Dino isn't brutally unfair in difficulty, shooting out so many Bullets that you just can't avoid them, but it still shoots out enough consistently to be a real threat and allows the player to gradually learn the attack patterns, and eventually predict exactly when the next Fireball will instantiate and dodge accordingly. It's why I'd rather have a set shooting interval than say, a random shot every 1-3 seconds, as it it would take away some of the skill factor in my game. The Dinos hiding out of sight and shooting out Fireballs through the act of surprise is generally a great way to show off their personality within the limitations of the game. Since they don't move about very much as a way to show the species is lazy, and they even choose to fly around in airships that are dotted around the game (the sprite was made by me in Photoshop, shown below), rather than just choosing to walk.

The airship sprite that was created by me. It acts as a background element, but also as a prop to set-up the game's story (since it's the first thing you see when the game begins, as you're dropped out of a Dinosaur's airship to be stranded in the desert).

Okay! Now that I've covered every coding element from the introduction list, here are some images of the Dino running the code in-game that I discussed earlier in this blog post (the Spikes damage the Player in the same way the Fireballs do, so they're only shown below the Bird in the pictures), and each image is a step-by-step process of what happens, and each have an arrow pointing towards the main focus of the code in that picture as a visual cue! These pictures also work as proof that all my code is running as expected!

The Dinosaur is hiding underground because the Bird is out of sight. Note the eyebrows poking out of the ground as a clue to its location.

The Bird comes within the 'Wake Range' distance and the Dino plays the animation where it jumps out of the ground, ready to attack the player.

The Dino instantiating a Fireball every 1.8 seconds, at a movement speed of 5. This Bullet then heads towards the Bird's initial location (so it's possible to dodge out of the way), while also gradually falling downwards due to me adding a slight value of 0.1 to the gravity in the Fireball Prefab's Rigidbody component, affecting its Physics Behaviour to fall much slower than the player, adding a realistic spin on the game since fire is made of gas, which is naturally very light). This falloff is to keep the player on their toes, as it means if the Dino shoots a Fireball upwards the player must be careful to not get hit by it on the way back down!
The fireball collides with the Bird, dealing damage and applying the visual (flashing special effects and animation) and physical (horizontal and vertical knockback) feedback.

More knockback as the Bird continues to fly further backwards (as the Dino continuously fires Fireballs after the first one has been destroyed), and has changed its expression from 'shocked' to 'angry' as the animation progresses before defaulting to the regular idle animation again.


My research into these various topics in my individual research blog posts helped me greatly during the development of the content I've talked about in this blog post. For example my research into AI helped me layout my Dinosaur's decision making process, using a bit of fuzzy logic with conditional statements, as each part of the code can be segmented out step-by-step depending on the current scenario. Likewise for destroying the Fireball, the 'Destroy(gameObject);' line that I used as an example for researching the destruction of an object was also fitted into my game during the collision section, only it specifically destroys the game object with a tag.

To follow onto this I originally used a damage system similar to the example I showed in that research post. However throughout the game's development I feel using the max health and current health system I have now is a lot more versatile than the example I provided (since if I wanted to I could make the Bird spawn in a certain level with a lower amount of health after a story sequence). Also the script I use now is much more optimised, and after originally testing with the first damage code as a basis it didn't work as intended, whereas  the code I have now is also a lot more efficient to run, since it simply requires one line of code in every object collider section of the player script for the appropriate object I want to damage the player. (That one line is 'curHealth -= 1;').

Arrays, Sound, Collision Detection and Handling, Collectable Objects and Displaying Output (Score) in my Unity game prototype

Today's blog post will cover examples of:

-Arrays
-Sound
-Collision Detection/ Handling
-Behaviours/ Properties of objects modified in the code
-Collectable Objects (Coins)
-And Displaying a Text Output (Score)

In my Unity game.


Firstly, I used arrays and sounds in the game (all SFX and music used are royalty free and sourced from http://incompetech.com/music/ and http://www.freesfx.co.uk/) to organise certain sound effect variables together which use the same variable type (in this case being references to similar components), and the arrays thus allow my code to run more efficiently. In this case I was organising separate sound effects, since the Bird character's game object has more than one audio source component attached (each containing a different sound, which are sounds for jumping/double jumping and collecting a Coin). Here's the C# code I wrote to play my sounds inside the main player script:

Sound variables:

'public AudioSource[] sounds; //Organising all my different sound effects into arrays with []
public AudioSource jump; //Sounds for the Bird jumping and collecting a coin. These AudioSource components both attached to the Bird game object, but are assigned separately in the Bird's Inspector view, and are called by the variable's name
public AudioSource coin;'

Getting the components at the start:

'void Start () {
sounds = GetComponents<AudioSource>(); //Gets the audio source component attached to the Bird character and loads it into memory, so it can play the sounds in the array's collection (a jumping and collecting a coin sound effect) when they're referenced in their seperate sections
jump = sounds[0];
coin = sounds[1];
'

Playing the sound at the same time as jumping:

'{
rb2d.AddForce(Vector2.up * jumpPower); //Add the force of 150 (the jump power variable) in the upwards direction to the Bird's rigid body, so the player can jump!
canDoubleJump = true; //When grounded, you can double jump again
jump.Play();
}'

The sound code (using arrays) are organised into three different sections since they must be in their proper places, and wouldn't function if everything was bundled together in one area. The arrays both as a variable and within the 'void Start' function help organise my sounds (since you can't rename game object components, you must instead organise them, in my case in a numerical order). Arrays basically help streamline all of your variables using [square brackets] in one compact collection. So once the game loads with 'void Start' the component will be instantly loaded into memory, ready to be played at anytime needed (or else the game wouldn't be referencing the audio source component attached to the Bird game object). Then, wherever I want to play the sound in my code, I'll add it using 'soundVariableName.Play();', so in the case above, with the code for my Bird jumping. So it'll apply a force upwards when the user presses Space, set the ability to double jump as 'true', and play the jumping sound once (since looping is disabled in the Unity editor).

The Bird's sound settings, note the audio source component and also the two sound effects attached to the main player script.

I also had background music in the game, which is different in all three levels of the game and the main menu. One level is set in the desert, one outside the forest and one in the forest, as the Bird tries to get back home. And the music I chose is appropriate for the level's theme and fits the atmosphere well, with the desert/ outside the forest music being the same tune with different instruments, which adds a strong feeling of progression and fits the theme. Whereas the forest theme is a remixed version of 'In the Hall of the Mountain King, by Edvard Grieg', which also fits the theme well showing the Bird's desperation trying to get home and the fact the last level is the toughest to beat. The main menu music on the other hand is calming and peaceful titled 'Pamgaea', in order to calm the player before the game begins. All of this music wad added to the game by creating a simple, blank game object, adding an audio source component to it, attaching the song of choice for each level and ticking the 'play on wake' and 'loop' boxes (so it starts when the game begins and repeats over and over).

The game object that plays music's settings.


Now I'll talk about collision and collision handling in my Unity game. Essentially every intractable game object in the game's levels (like the Bird, platforms, enemies, coins, etc) have box and physics colliders attached to them as components. Objects that the Bird will hit and not stop moving after hitting them (like coins and fireballs that vanish after a collision) are marked as 'is trigger' in the inspector, in order for them to trigger the corresponding code in the player script to run. Whereas other things like platforms and enemies are not, since the Bird has a rigidbody2d component attached to it, which means Unity simulates the physics (like gravity) and collisions for you. This means that any sprite I add to the game, I can add a custom collider to it (either a box, circle or custom-shaped polygon collider) and the Bird will be able to walk on it. However I wanted to add custom friction to these platforms, since I wanted to refine the game's mechanics and make it feel more precise to play, with a few lines of C# code in the player script (shown below) so the Bird stops faster when the player stops moving, and a custom physics material attached to every platform that simulates the friction. Here's the code that goes hand-in-hand for the Bird's friction (where all it does is if grounded = true (where the Bird is on the floor), then ease/ slowdown the horizontal movement speed for the Bird's rigidbody):

Friction code:

' //Fake friction to stop Bird sliding around after moving and when grounded, and easing the x speed of the player (make sure I apply the Ground Physics Material to every platform the player stands on to work with this code)
if (grounded)
{

rb2d.velocity = easeVelocity; //Resets the new variable easeVelocity making it equal to the current velocity

}'

Selecting a huge range of platforms in the game, note the red arrow, which shows that every piece of land has the ground physics material attached to it.


Now I will talk about bottomless pits in the game, which also make great use of the collision with the Bird. Essentially there is a giant game object (tagged with 'Pit') stretched out under every level with a trigger collider attached to them. And now the code it uses also couldn't be simpler (shown below, as a great way to streamline and optimise my code to a professional standard), basically whenever the player falls down a hole off the stage, the Bird will collide with the bottomless pit game object, and the Bird is constantly checking to see if it's collided with any object tagged with 'Pit', so when this all comes together it simply runs the 'Die' line of code that restarts the level. It's very simple and efficient!

Falling down a pit code:

'if (col.gameObject.tag == "Pit") {

Die ();


}'

Next up for collision events I created falling platforms for the Unity prototype. Where they's basically platforms that the player can stand on, but after 0.5 seconds the platform will fall, and if it's over a bottomless pit it will be tough to get off in time before you fall to your doom. I wanted to add these to spice up the challenge in the game, and make the player act more carefully when playing and not just blindly charge through the levels. Instead now they'll have to stop and asses the situation as they play. How these platforms work in-game with the code (shown below) is simple: They are easy to recognise by being thin and lightly coloured compared to the regular terrain in the levels, but also don't stick out like a sore thumb with a bad colour-scheme and ruin the suspense I'm trying to build in the game. Essentially the code modifies the platform's 2b2d kinematics, toggling the platforms rigid body on (which defaults to off) after the bird has been colliding with the platform for a certain amount of time (in this case, 0.5 seconds). So when the 2b2d (rigidbody2d) is enabled, Unity's physics will affecr the platform, so it will fall downwards due to gravity. I chose this specific time because during testing I found that if there is a longer limit the player can easily walk across the platform and jump off in time, but any shorter and the platform would fall too fast and be something many players will struggle to react too, making the game more frustrating to play than challenging.

Falling platform code:

'private Rigidbody2D rb2d;

//Float (For the time the Platform takes to fall)
public float fallDelay;

void Start() //Get the Platform's rigidbody when the get loads
{
rb2d = GetComponent<Rigidbody2D> ();
}

void OnCollisionEnter2D(Collision2D col) //If the object that colldies with the Platform is the Bird (tagged with 'Player')
{
if (col.gameObject.tag == "Player")
{
StartCoroutine(Fall()); //Begin the IEnumerator loop to make it fall when the Bird collides with/lands on the platform
}
}

IEnumerator Fall()
{
yield return new WaitForSeconds (fallDelay); //After a certain amount of time (the fall delay is set to 1, inside the Inspector of the Falling Patform)
rb2d.isKinematic = false; //The gravity will now affect it and the Platform will fall, as physics will now affect the game object

yield return 0; //Ends the IEnumerator loop

}'

The bird landing on a floating platform.
After a short delay the platform registers this collision and begins to fall down into the bottomless pit.

Now moving on from custom tags and collisions I have collectable coins in my game (and every instance of this game object also has the custom tag of 'coin', for the same reason as the bottomless pit game object tagged 'pit', so various objects can have various functions as the bird hits them). These coins act as the game's main collectable and as a secondary win condition for the game since you can try to get as many as you can, and some are hidden in places to encourage exploration, so that you can try to get as a high score as possible (the sprite for the coin is from OpenGameArt.org and sourced royalty-free). The coin game object instances throughout the levels are all based off of one main coin object, that is stored in a prefab that can place as many duplicates as I need. This is an example of me following professional working standards, as with that one prefab in my Unity project files I can create as many duplicate coins in my level as I like while creating the game, and can edit them all at once. This way I don't have to copy and paste each coin into my game at a time, or select them all manually if I want to change anything in the inspector view, so this is very good time management in the long run.

During the player's journey to the door at the end of each level, these coins are scattered about everywhere, and they also have a gameplay advantage. I can also use coins to assist the player as they play the game, like subtly drawing a path to the goal, lining up a discrete trail to a secret area and even use them as a guide for a tricky section of a level (positioning them in such a way the player knows when to double jump up a ledge, for example). The coins also lend themselves well to my game's design, as throughout the three levels of the game I will put less and less of them into the levels, starting off with an abundance of them and finishing with coins being pretty rare. This is because as they player plays through the game their skills also increase, and that means less coins are needed to help the player and they can start thinking for themselves.

I have put a portion of the script for the coins below. How it works is simple: When the Bird collides with one, it will play a 'ding' sound (so the player definitely knows it's been collected, and it starts to become an iconic sound to them) destroy that instance of the game object (so the player can't collect the same coin twice) and add 1 to the game's score (which starts at 0 when the first level of the game loads, since there's no reason to have any more than that at the start). It adds 1 to the score by changing the text input field within the 'game master' script in the game master object, which handles all of the text in the game (such as the text the door uses to draw text too). The score can also carry over from level to level, and the code does this by getting the value of the current score in the integer variable 'points' from the previous level, and setting it to that value using the built-in PlayerPrefs setting in Unity.


Coin collecting sample code:

' if (col.gameObject.tag == "Coin") { //If the bird touches a coin, despawn that coin (so they can't collect it again), then increase the value of the points total by 1

Destroy(col.gameObject);
gm.points += 1;
coin.Play(); //Then, similarly to the jumping sound, play the coin sound affect inside the second audio source component

}'


Writing the current score sample code:

'void Start() //Check if the score has saved before starting a new level so it can be carried over
{
if (PlayerPrefs.HasKey ("Score"))
{
if (Application.loadedLevel == 1) //If we are on the first level of the game, then we do not want to load the previous score and reset it instead!
{
PlayerPrefs.DeleteKey ("Score");
points = 0;
}

else //If it isn't the first level, then assign the score that is already located inside the integer points variable
{
points = PlayerPrefs.GetInt ("Score");
}
}
}'

The bird about to collide with a line of coins, note that the score is currently set to 0 as none have been obtained yet.
The Bird jumping over the bottomless pit onto the next platform, passing through a line of coins on the way (which have been destroyed and removed from the game once collected). Note that the score now reads '3', as a total of 3 coins have currently been collected by the player.


The main character Bird's tail also has a big collision box but it's set to 'is trigger', this was changed later on in the game's development, so it can still pick up coins and get hurt by enemies, but not physically collide with or get stuck on platforms. As it upon testing it felt unfair that the bird has such a large hitbox behind him while platforming, so it was modified making enemy attacks still tough to avoid, but jumping over terrain more manageable, as with a huge hitbox on the tail navigating the game's levels was more tedious at times as the bird sometimes hit overhanging platforms and got stuck in tight spaces. So now the collision boxes are more forgiving and squared shaped, to match the tiled nature of the game.

Different body parts of the bird (like the body, legs and tail) all have separate colliders associated with them, each inside empty game objects as children components to the Bird as the main parent game object. This way I can give them all individual properties, and in this case, set the Bird's tail to be a trigger (annotated above) so the large size doesn't get in the way when platforming, but can still both help and hinder the player.

Likewise with me using collision above, there's also a game mechanic that takes advantage of the Bird character's well-positioned collision boxes, a maneuver that I call 'the hook'. This gameplay function doesn't use any code, instead it works by using the gap between two of the Bird's collision boxes to 'grab' onto an edge where you'll get stuck to it after landing. You can still move away if you don't want to jump (but that may usually lead to you moving into a bottomless pit and restarting the level), however you're able to jump off the ledge to land safely onto the platform next to it, and also gain a bit more vertical height in the process. It's also set-up so it's easy to do, as the Bird automatically 'grabs' onto the edge of the platform if you jump into it and aren't going to land on the ground properly. It's a great safety net type of feature that was included to make my game more accessible to a casual audience, without completely punishing a mistake with the player falling to their death. However the hook also works well for a more hardcore audience, as it adds another layer of depth and strategy to the game while also adding in another skill that speedrunners can use to play through my game quickly and effectively. Here are some images demonstrating how it works below:

A demonstration of the bird's colliders in the Unity editor (they are the three green boxes). The red arrow points to the 'ledge' where there's a space between the collision boxes, and the bird can use this to 'grab' onto ledges and jump up from them.
A picture showing the hook in action, the bird 'grabs' onto the ledge when you jump into it and the player can then jump off of it to gain extra height

I also added a timer to the game (that was suggested in the end-user review when people filled out my survey for the game). This timer is in every level and counts down from 3 minutes (180 seconds) to 0, if it reaches 0 the bird dies and the game will restart. I added this in order to add a sense of urgency to the game, since it's a driving force that pushes you forward. It helps add another layer of depth to my game and can make it more comparable to more professional games in the industry (like Mario or Sonic). In order to also appease the casual ordinance of my game too, since the timer makes the game harder, the timer also pauses with the rest of the game when you pause the game with the Escape key, meaning if it ever gets too hectic for the player you can take a break an come back to the level you were stuck on with a clearer mind. Here's an extract of the timer code and how it works:

Timer code extract:

'

                        if (timer > 0.1) {
                                    timer -= Time.deltaTime;
                                    inttimer = (int)timer;
                                    timerText.text = inttimer.ToString () + " Seconds Left!";
                        }
                                    else{

                                    Application.LoadLevel(Application.loadedLevel);
                                               
'

Essentially the timer counts down from 180 (as assigned in a float variable since the timer can be more precise using decimal points in its value, but it still displays the timer as an int (whole number) to not overcomplicate things and not distract the player with a changing time every 0.1 seconds). And all the time the timer is above 0.1 in value (as said by the if statement), it will continue to count down and change the displayed text every second. However, if the score is below 0.1, restarts the game and kill the bird. I did this because if the score never ended it would just continue counting down into negative numbers, which isn't what the score is intended to do.
The time at 177 seconds, just after the game has loaded

The time is now at 174 seconds, as it slowly counts down to 0
My research beforehand was incredibly useful for me when it came to these topics. For example, when I was looking up types of sound in Unity, I converted all of my sound files into audio clips when they were attached to their relevant audio source components, and used the audio.play code in my script to run the jump and coin sounds. This meant I could easily import the sound clips into Unity, and quickly add the relevant code in. My research of arrays also assisted me in Unity, using square brackets and listing my Player's sounds in numerical order really helped clean up the code but to also optimise it, so I could call different variable names like 'coin' and 'jump' in my audio playing section of the code whenever I needed them to play the relevant sound effect at the right time.

I also researched collision detection previously, which meant I had a greater understanding of separating out collision functions to objects with certain custom tags (like my 'coin', as the example used 'bullet' to hurt instead of help the player). It also expanded my understanding of collision just being when two colliders hit each other, it triggers code to run. This meant I could also implement the coins that draw text on the screen, as I understood to create a separate collision function that contains the code I want to run (so in this case, destroy the game object after's it has fulfilled its purpose).

Monday, 14 December 2015

How I handled Conditional Statements and Events (like Menus and Player Input) in my game

Today's blog post will cover examples of:

-Conditional Statements
-Events
-Menus
-And Player Input

In my Unity game.

To get started: I've used various conditional statements (using if commands), to make decisions in my C# code, which can be decided upon by a player's input. This is to help the game decide when every piece of code should be applied, as if the game just applied code at the start and not when appropriate conditions are met most games would not function very well at all (since the player would activate every possible command for every scenario at once). For example, here's an extract of my code that uses if statements for some of the game's physics, to decide if the player should flip left, right, or jump, and then it calls to the respective lines of code elsewhere in the script to follow through with the command:


If statements:

if (Input.GetAxis ("Horizontal") < -0.1f)
{
transform.localScale = new Vector3 (-1, 1, 1); //Flips player horizontally for when you're moving left, Vector 3 represents 3d movement and space using the X, Y and Z axis
}

if (Input.GetAxis ("Horizontal") > 0.1f)
{
transform.localScale = new Vector3 (1, 1, 1); //For when you're moving right
}

if (Input.GetButtonDown ("Jump")) //If you press space, the bird will jump! Check if grounded before you can jump again.
{

Essentially the code breaks down IF any of these three situations should happening, depending on the situation. So for example, the last few lines handle the code where if the player presses the 'Jump' key on their keyboard (set in Unity as Spacebar for when the player presses down the key as input), the game should execute the jump command (where the code to execute the command is positioned elsewhere in the Player script as a reference). Next, if the player moves either left or right along the horizontal X axis (and it classes moving as going at a speed past 0.1, which only occurs when the player presses left or right on their keyboard, which in turn adds a force to the player's rigid body using the code of rb2d.AddForce with a speed set by the speed and maxSpeed variables), then the code should flip the bird character's sprite to match the direction they should be facing in reality when moving that way. This works because the 1, 1, 1 used in the code stand for X, Y and Z size of the main character. So having -1 as the first number turns the bird's scale in the opposite direction until changed again).

I set it up like this because it streamlines the C# code to the player's three main attributes, and it means as the main player script continues to expand it will be easier to locate where everything is in the code and not lose track of everything. And also it's necessary to flip the bird in the direction it's facing when moving, as it would break the player's immersion with the game otherwise to have it walking backwards every time the player wants to move left! The game very much has a focus on horizontal movement, since the main character is a bird they can jump over huge distances when moving left or right along the x axis, however he has a purposely limited jump height on the y axis, to enforce the fact that the bird can't fly very well and has difficulty getting up to high places. Here's an image of the bird facing both directions in-game, and also jumping in the air (with different animations for idle, walking and jumping using Unity's built-in animator), showing the working code in action:
Facing right

Facing left

Jumping

Another example of player input resulting in an event in the game is the Door game object. This is the primary win condition for the game: reach the door at the end of each level, which takes you to the next level, until you finish the game and get the Bird back home. Essentially in-game when the player gets close to it it will display a message on the screen saying how to enter (pressing the 'E' key), and when the player does it will load the next level of the game. If the player leaves the trigger area it instead prints text onto the screen that breaks the 4th wall and reads: 'What? where are you going!?', which adds to the charm of the game with a light-hearted nature, and isn't intrusive to the player as it appears when they reach the end of the stage anyway with nowhere else to go (how the text is actually drawn on the screen will be talked about in the score blog post as it follows a similar procedure). Here is a portion of the code that the door uses to get the player's input, and two images showing it in action:


Door object script sample:

' void OnTriggerEnter2D(Collider2D col)
{

if (col.gameObject.tag == "Player") //If the player game object (tagged 'Player') collides with the Door, print the text onto the screen. And if they press E while inside the triggerbox, load the next level of the game

{
gm.inputText.text = ("Press (E) to Enter!"); //Load up the text continuously on the screen until stated otherwise
{
if (Input.GetKeyDown ("e"))
{

Application.LoadLevel("Scene2");

}
}
}'


Before the Bird hits the Door
After the Bird its the Door

The code essentially reads where when the Bird collides with the Door's trigger box (and it will only respond to the Bird, as it is tagged with 'Player' in the Unity Inspector, as we don't want enemy projectiles hitting the Door and automatically loading the next level!), if they press the E key, then load up the next level in the game. This is specified in the brackets (so in this case it's 'Scene2') and allows me to separate levels into different Unity Scenes, and not have everything in the game placed in one scene and have the whole viewport get very cluttered. Plus it's also just more efficient and easier to load up a new level, as you don't have to manually find out the in-editor coordinates for each starting location this way!


Next up for in-game events is making my game draw a HUD (heads-up display) onto the screen. A good example of this is my game's pause menu, where when the player presses the escape key (set with Unity's custom keys under Edit - Project Settings - Input), the whole game freezes and a menu game object appears until the player clicks a button on-screen, or presses the escape key to close it. The code is placed in a separate PauseMenu script (following professional working practises by separating out code and naming things correctly), and this script is attached to the game's camera object and is designed to pop-up over the whole screen by following the camera (otherwise when the player pauses the game, the game would freeze, but the pause menu would only appear where I placed it and not in front of the player at all times). Here's a large extract of the code for the pause menu:


Pause menu script sample:

"void Start(){ //Gets called in at the start of the game

PauseUI.SetActive (false); //Means that the pause screen doesn't load the moment the game begins, it gets triggered later on

}

void Update(){ //Update function

if (Input.GetButtonDown ("Pause")) { //If the pause button is pressed by the player, bring up the Pause UI. The pause button is set to the Esc key, under Unity's Edit - Project Settings - Input tab

paused = !paused; //Paused is the opposite of pause (variable), as it's toggling my boolean that is by default false (or off). So if it's false, then the variable will be true.

}

if (paused) { //If you pause the game

PauseUI.SetActive(true); //If you pause the game by pressing the button, bring up the pause menu UI
Time.timeScale = 0; //Set the game time to 0 if paused, which freezes everything and stops the game from running which allows the player to click on a button

}

if (!paused) { //If the game isn't paused

PauseUI.SetActive(false); //If the game isn't paused
Time.timeScale = 1; //Set the time back to normal running time and continue playing the game. 1 is full speed and 0 is stopped, so any o.x speed between these values will actually slow the game down instead!

}"

Essentially the game loads with the pause menu set to false and not appear on screen (I did this on purpose, as otherwise the game would always load with the menu on the screen and render the game unplayable! Since you wouldn't be able to see anything!). Afterwards whenever the player presses the 'Esc' key it will change the pause menu to be true, and not false. Since the pause menu UI is constantly following the camera and is just invisible, being set to true makes it appear to the user. However this isn't just how it works, I also wrote the code to see if the game is pause, set the game's time scale (essentially the running speed), to 0, which freezes the entire game. This is on purpose, as if the player freezes the game and it keeps running, it's normally to take a break, so if the game kept running they could easily be killed by an enemy or fall to their death if they pause mid-jump. Afterwards the code is copied using an if statement and set in reverse, to check and see if the game isn't paused, and to set the game speed to 1 again (fullspeed) and continue playing.

There are various other quality of life effects I added to the pause menu to make it more interesting and convenient, like adding a dark-but transparent (to still see the game in the background) canvas behind the pause menu buttons to make the player's options stand out more from the backdrop, and also have a form of physical feedback to the player so they know that the game has truly stopped (which is a professional industry standard technique commonly used in pause menus for platformer games like Super Mario Galaxy, and has become a universally used trope in UI design). Also to add to my game's charm I added some more images of my bird that I created in the Digital Graphics assignment, since the bird's design is to change appearance and colour depending on how it's feeling I added a cute sprite of the bird thinking (representing the player choosing a menu option), and a picture of the bird sleeping (to represent the player taking a break). Here are a few more screenshots, this time of the pause menu in action as it freezes the player mid-jump to show time stopping:

The game unpaused

The game paused, note the darker background behind it
As you can see from the screenshots the menu has four options: Continue, Restart, Main Menu and Quit. These all act as you'd expect, where continue sets the pause menu to false and sets time to 1, restart loads the level that's already loaded into memory, main menu loads a separate Unity scene that can act as a main menu and the default scene that Unity loads at the start of the game, and quit simply terminates the program. There are various options here to suit the player's needs, and were added to make the game fit a more professional standard and include all the various features you'd expect a pause menu to include in this day and age. The code for each button is shown below:



Pause menu button functions:

//Button functions for all four of them
public void Continue(){ //All the buttons can access these functions, so it must be a public variable

paused = false; //If the continue button is clicked, unpause the game (ensure camera object is added to the 'On Click' section of all the buttons, as it can draw up a list of all the custom actions I've made for each individual button

}

public void Restart(){

Application.LoadLevel(Application.loadedLevel); //Restarts by loading the same level again. The code says that Unity should load a level, and the level it should load is the one that is already loaded

}

public void MainMenu(){

Application.LoadLevel(0); //Loads the scene with an index number of 0, which is the scene of the main menu so the player can quit back it it

}

public void Quit(){

Application.Quit (); //Literally just closes the game when the button is pressed

}

I also have a main menu in the game, which has a dedicated Unity scene just for it, and this menu is the first thing that opens when the player loads up the game. It's designed to be visually pleasing, with a logo (made by me in Photoshop, and the game is now titled 'Pippy The Bird!') that animates to grow and shrink slowly. It also has a scrolling background of the desert the Bird will be travelling through for a while to get home (the effect is made by duplicating the background image, setting it as a repeatable texture, applying it to a quad game object as a texture and adding code to it by offsetting the vector 2 horizontally at a speed of 0.3). The menu also has two transparent silhouettes of the Bird's expressions as it's trying to get home on both sides of the screen. The main menu also has four buttons with separate functions in a script (listed below), in order to add a lot of choice for the player before they start the game. These buttons are: starting the game, loading the test level (both of these use similar lines of code as the pause menu since they work the same way), how to play (which toggles a canvas box to appear and vanish again, with text inside it explaining the rules of the game, this helps give the player an idea of how to play before the game even begins) and lastly a quit button (this also uses the same code as the pause menu, which quits the game when clicked). Here is the C# code used in the main menu's script:


Main menu variables and functions:

'{
//Variables to reference the canvas game object (it is assigned to _Main) with text assigned to it and default it's open state to being false (so not visible), so when the player clicks 'how to player' the text box will appear
public Canvas PanelInfo;

public bool infoOpen = false;

// Use this for initialization
void Start () {

infoOpen = false; //When the game loads, hide the text box that lists how to play the game and disable it
PanelInfo.enabled = false;

}

//Functions for each button on the menu

public void StartGame(){

Application.LoadLevel(1); //Loads the scene with an index number of 1, which in this case is the game's first level value as listed in the Unity build settings tab in order

}

public void TestLevel(){

Application.LoadLevel(4); //Same as start game, only loads the test level instead which exhibits all of the functionallity I've implimented into the game in a small area for testing purposes. Takes you to the first level of the game once you 'beat' it

}

public void InfoPanel()
{

infoOpen = !infoOpen; //Code used to switch the info panel (the how to play button's function) on and off everytime it's clicked. If it's enabled, open up the window
PanelInfo.enabled = infoOpen;




}


public void Quit(){

Application.Quit (); //Literally just closes the game and Unity application when the button is pressed

}
}'


The main menu as it appears when the game loads, with no help box.

The main menu as it appears when the 'how to play' button is toggled on. Also note the repositioned logo and background as they cycle through their animations.


As briefly mentioned earlier, throughout testing my code underwent a few changes here and there. For one my pause menu didn't even stop the game at first and didn't darken the background either, so both were later added for both functionality and quality of life purposes. Also the text on the pause menu buttons was pretty pixelated at first, and it turns out it's because the font size was small but being stretched out onto the button. To remedy this I made the font size huge (140), but then set the horizontal and vertical overflow to overflow (to align the text over the area of the box), and shrunk it down with the Unity scale tool to fit. This means that the text won't look blurry even on high-resolution PC monitors in fullscreen, due to the high DPI of the writing.

Researching beforehand also helped tremendously when programming this, my conditional statements post for instance helped when I was typing out my if and else statements since it listed out clearly the different types of them and their purpose (else isn't shown in my example, but is used for the double jump code where if the player is grounded, they can double jump and it resets the code, but if they are not (or else) and are in the air after double jumping, they cannot use it again until touching the ground). Since I researched that conditional statements can branch out code into different sections, I used it in my own C# scripting to space out the information into digestible chunks for both reading and optimisation purposes.