Saturday, 8 December 2018

Game - Enemy boss

To complete my Unreal game, the player will need to defeat a boss, in order to complete the level.

The enemy boss performs a series of mechanics, using the Sequence function.

  1. Rotates to face the player
  2. Shoots projectiles at the player
  3. Randomly chooses a new location from three points and moves towards that location

How the code works:
Step one of the Sequence set's the rotation of the boss to face the player. Then, it fires a projectile in that direction.

To rotate towards the player, the boss uses PawnSensing event to recognize if the player is within a close proximity. If this is true, then the boss sets the look rotation (using FindLookAtRotation, starting at the boss's location with GetActorLocation, and targeting the new rotation to be towards the player's location with GetActorLocation).

To fire the projectile, the Blueprint checks a boolean to see if a projectile can be spawned. If not, a projectile will be spawned (SpawnActor), and an impulse (AddImpulse) towards the forward vector (GetForwardVector) multiplied by a large speed will fire it. It will then set the boolean to false and add a delay.

The boolean acts as a cool down mechanic to avoid an overload of projectiles to be fired. If there was an overload of projectiles, it would cause the game to lag, therefore making it difficult to play.

To move to a new location, the boss will lerp between the boss's current position (GetActorLocation) and a random point. This random point is determined in a custom function named GetRandomLoc, which randomly chooses a random integer from the patrolPoints array, and stores it in a variable (currentPatrolPoint).

The patrolPoints array is used to store static gameObjects, which act as positions for the boss to move towards. Within the Blueprint code on the start of the game (Event BeginPlay), the code retrieves the world locations of the three positions (GetWorldLocation), makes an array from it (MakeArray), and sets it to the patrolPoints array, and chooses a random location.

To take damage from the player, the Blueprint code uses the Event AnyDamage to recognize if it has taken a hit, and subtracts 3 health points from the health variable. If the health variable goes below 1, it will be destroyed.

To show the end screen, the Blueprint code uses the Event Destroyed to check if the boss has been defeated, and then setsup a heads-up display (HUD) widget to display the end screen, and adds it to the view port. We also disable the input and display the mouse cursor to allow the user to click on the buttons. (Create EndGame WidgetAdd To Viewport > Disable Input > Set ShowMouseCursor to true)


Different Game Objects to show positions for the Patrol Points array:



Blueprint Code (use right-click and drag):




Final Boss:


What I have learnt:

From this mechanic, I have learned how to use some different coding features in the Unreal engine, such as arrays, randomness and adding my own functions.

With arrays in UE4, the software allow you to store different types of variables within them. For my instance, I stored game objects which acted as positions for the boss's movement mechanic. The functionality of arrays in UE4 work as I expected and remain similar to arrays in other programming languages - such as being able to get the array's length.

With randomness in UE4, the software allowed me to randomly determine an item in an array with RandomInteger (seen in the GetRandomLoc function). This felt easy to set up as it was just a single function to add in. Compared to retrieving a random integer in other programming languages (such as C# in Unity), this felt easier as I did not need to pre-define any random classes beforehand. In C#, you would need instantiate the Random class, before going Random.Next(minimum, maximum). 

I added a custom function in this boss mechanic named GetRandomLoc. This included the randomness factor. This was useful to repeat the same step as one function, as it made the code look tidier, and it is an example of good programming practice. 


Conclusion
In this mechanic, I was happy to be able to incorporate the idea of arrays and custom functions into the code, as it helped me understand the software, and continue to use regular programming features in a new software.

If I approached this boss mechanic in the future, I could make a change to the PatrolPoints array, where this array could be predefined in the engine, instead of defining it in the code. This could tidy up the code. However, I would have to change the array type to store vectors, instead of game objects.