I worked as the AI programmer for Boomerblade!
To bring the monsters of the game to life, I used behavior trees, state machines, and navigation behaviors. Each enemy has unique abilities that are encoded into an easily expandable system of AI scripts.
Because all enemies had a similar set of behaviors, they have a central state machine with special implementations of each state. Each enemy can attack, chase, and be damaged, but they all carry out these behaviors in their own way.
In order to create a clean and easily modified intelligence, the enemy types have small behavior trees to control their behavior. The tree is the enemy's thought process which tells it whether its should try to swing at the player, run away, or continue chasing.
The most impressive enemy in the game is the final boss. It is a giant Golem with several abilities. The abilities have charge up times, cool-downs, and special conditions. The boss was a difficult enemy to balance because of the complexity of its behaviors.
By creating a behavior tree for the final boss, one can easily visualize, rearrange, and potentially add to these behaviors. The "laser", "fireball", and "charge" moves are encoded in the boss script, and the high-level control of these moves is encoded in the behavior tree.
Below is log of my progress while working on Boomerblade (newest to oldest).
6/7/19
I made some small fixes to the enemies including the showing/hiding of the rotating enemy arm during different states. I also fixed the sounds playing at the wrong times. Lastly I played through every level and updated the objectives to be perfect.
6/5/19
The boss now has an awaken state that plays the intro animation at the start of the boss level. I also changed bugbears to not be stunned when charging their ability. This makes them more challenging. I also double checked the functionality of each level system.
5/22/19
Boss animations and behavior are fully functional. I added the third ability, "Snipe", to the state machine. Snipe fires a large fireball towards the player. I added many animations to the other enemies as well. i also added the fireball animations and coded them to have a rotation towards the player upon firing. Finally, I added the bugbear's arm and swing animation.
5/15/19
Added more animations to the game including the Skeleton Mage and Floating Skull. Added some behavior changes to the boss.
5/1/19
Boss animations added. Working out the kinks.
4/24/19
I added a prototype for the final boss AI. It is integrated into the existing system using the state machine and behavior tree. It has two special behaviors: the stomp and the spin. The stomp move jumps into the air after a short channeling period and tries to land on the player. It is a global ability. the spin spawns a laser coming out of the boss to each side. The player must barrel roll over the laser to avoid damage. I also changed the bugbear AI so that it cannot be stunned while charging. Lastly, I organized the enemy AI base class and added some documentation.
4/10/19
Added some new visual effects for the Skeleton Mage and Bugbear enemies. They each have line renders with special colors to indicate their special abilities. I changed the level spawners to be easier and added a new objective type that forces the player to fully clear the level. Added a level clock so that the player can see their time and possibly to create a future objective based on time.
4/3/19
Added behavior trees to enemies. It works. The behavior tree replaces the code in the "tracking" state of each enemy. It is now much easier to read and adjust the enemy behaviors. The behavior trees are designed as "state selectors" which means the root node is a selector that will end up in a particular enemy state.
3/13/19
Today I added some final touches to the game for our 10 week submission. I cleaned up the Goblin attack animation by fixing some layering and playing it at the correct times. I also fixed the lighting by creating a lighting prefab and having uniform light settings in each level. The 10 week final diagrams for the systems I designed are attached below.
3/13/19
Today I added some minor touches to the game levels. Firstly, all of the levels now have doors to reach the next scene. Secondly, all of the scenes have functioning objectives, but the objective types and parameters can be easily tweaked. Thirdly, the colliders and walls and some levels now work properly and have more simple geometry to that the player can use them easily. With these changes, the game is playable from the first to last level continuously.
Next, I added a Unity hardware cursor with the cursor texture to the game and removed the gray box we were using before. It looks a lot better. I also added materials to all of the line render components of the enemies and player. We will probably make cooler materials for these, but at least they aren't hot pink.
3/6/19
This week I adjusted the Enemy spawner behavior to have a range. I think this is the best way to pace the level, such that enemies only spawn when the player is close by. I have played the game a lot and tried to balance Level 3 to have the right amount of enemies spawning at fair rates. I changed the bugbear to have a charge distance limit, so he has to be within a certain range to use his ability. Lastly, I added a new objective for clearing all spawners. This requires the player to completely exhaust all of the spawners in the level. I think this is a clean design for a level objective and it flows nicely.
2/27/19
This week I fixed the objective system to be more expandable. Now we can add new event types and more easily implement different level objectives. I also added this system to the normal levels and tried to balance the spawning amount in each level with the objectives.
I also added some UI elements to the bugbear and tweaked his behavior slightly. he now has a small cast time to his special ability. I added this cast time as an Enemy State so that future enemies can utilize the cast time behavior. The bugbear also changes color while using the charge ability. While he is charging, it draws a line render towards the player to show where the bugbear is going to charge at.
2/20/19
Today I added an objective system to the game. This doesn't actually change anything yet, because there was already text tracking some events like enemies killed and damage dealt. However, the text and data is now updated in a much smarter way, with individual objectives. The game has a list of active objectives that are each associated with a text slot on the user interface. The idea is that each level has a set of objectives to be completed. The derived objectives each have a specific goal they are testing for completion. The objectives are notified by a statistics manager when an event occurs that they care about (using the observer/listener pattern). UML attached.
2/15/19
For the past week I have been working to tweak and perfect the basic parameters and behaviors of enemies and the boomerang. Working within the new "Horde Mode" scene, I've been able to test the game-play in a more realistic environment than the prototype level. To make the game more fast paced, I basically turned up all of the values. The enemies move and attack faster and the boomerang moves faster and in a tighter arc.
I added another basic ranged enemy to the game based on the designer's outline. I also added to the spawner behavior to have parameters for amount of spawns and efficient checks for disabling and spawning. I added some enemies to the new level 1 scene.
2/8/19
I created a new scene in the project as a "Horde Mode" to test combat on endless waves on enemies. The scene has a simplified and smaller level so that the player can see the entire room and use the walls easily in combat. I spent a lot of time tweaking the boomerang parameters to get a more fun behavior. I think we should increase the speed of the boomerang and decrease the total air time. Lastly, I added a visual effect when the enemies are damaged to signal to the player that they hit the enemy.
2/4/19
Today we met to discuss the results of play-testing and finalize our prototype level. I worked on adjusting enemy behaviors slightly to fit the scope of the level. I added a visualization object attached to the melee enemies to help the player see where the enemies are attacking because there are no animations or sprites yet. We discussed the enemy attack behavior and are working on how to implement it.
2/1/19
Implemented enemy system with the project. The game now has three enemy types derived from an EnemyAI base type (the goblin, floating skull, and bugbear designs). The enemies all utilize common elements such as states and interactions with the player/weapon. The scripts are attached to prototype prefabs in the scene with simple capsules. We need to work on how to attach the 2D sprites to the objects correctly.
I am satisfied with the enemy system so far because it is easily expandable, and it addresses the relatively homogeneous enemy behaviors while allowing some customization for each enemy type. A thing to consider would be separating the ranged and melee enemies into two categories to centralize the logic of melee attacks in an EnemyMeleeAI class and the ranged attacks in an EnemyRangedAI class. However, I am uncertain if future enemy designs would be limited by this change.
1/28/19
Worked on a high level design for the enemy structure of the game. I decided that state machines are sufficient for implementing the behaviors of most of our enemies. I want each enemy to derive from a base enemy class to encapsulate the NavMeshAgent and Health properties. I want the boomerang to be able to collide with any enemy and be able to tell that enemy how much damage to take, to call its "knock-back" function (each enemy does something special when hit).
The diagram for the enemy types and state machines is attached. I am not entirely happy with it. There are other possible designs for the state machines. I think another good idea is to have the states all derive from one Enemy State class. This way enemies could share some states like stunned or idle. The states could call back to the Enemy AI which has override functions for each state.
Edit: I had a second go at the enemy structure design and I've refined it. I decided to alter the states so that they call back to the Enemy AI. This adds complexity to the enemy implementations and makes the states just a simple call back. However, this allows each enemy to share the pool of states. This is better because the enemy design reuses mechanics like "stunned", "tracking" (chasing), and "idle" for almost every enemy. The unique states can be implemented with the "Special" state. I like this better because the state-change logic is not so complicated that it needs to be separated from the state execution. This second draft is attached.
1/23/19
This week I implemented another enemy prototype AI system, the mage. This is a more complicated system involving several states and abilities. I focused on making the abilities easy to tweak and add onto to balance the game. The diagram for this system is attached. Additionally, I worked on a mechanism for displaying and moving our 2D sprites in the 3D environment using a simple script.
To do: Add a base enemy class with an API that can accessed by the boomerang to damage enemies, trigger effects, and add multipliers. Also implement the "GoblinAI" and "FloatingSkullAI" as more refined versions of my prototypes in line with the design docs. Once the enemy system is more refined with these enemies, add any other AI characters.
1/16/19
This week we worked on brainstorming idea's for the game, culminating in draft for our game design document and elevator pitch. We discussed level design, game play mechanics such as boomerang behavior, and enemy design.
Individually, I worked on prototyping the basic enemy systems and diagramming how they might be implemented. I created a simple enemy that 'seeks' a player and a more complicated enemy with a ranged attack.
Commentaires