PRE-BETA II
My work this sprint was spread between a large variety of tasks and began with integrating the ShooterAttack script that another member of my pod created into ShooterDriver.cs. The intended behavior of the enemy while in its ATTACKING state is to shoot a number of times, select a node within a certain range to move to, and repeat. Integrating this into my driver was relatively straight-forward, but unfortunately, required additional global booleans to be created to determine when to attack. I initially disabled the ShooterAttack script between uses and used Unity’s enabled command as my conditional statement. However, this was ultimately changed due to safety concerns (it was deemed unsafe to disable a script to interrupt its functionality). A projectile prefab also had to be created. I am still unsure why, but the prefab that was intended to be used for the projectile was missing its data (perhaps due to a missing .meta file?), so a temporary one was made in its place.
What seemed to be a straightforward process quickly turned into hours of debugging. The enemy had a tendency to “shimmy” between attacks or slide and shoot while moving to a node, where attacking should not have occurred. I also encountered a frequent bug where, when moving across a NavMeshLink and transitioning to the ATTACKING state, the enemy would teleport to its destination and begin twitching back and forth furiously. I tried to solve these issues myself, but ultimately leaned on my team for support.
The other enemy programmers and I met multiple times throughout the week, both to work out the shooter bugs as well as those that appeared on the charger enemy when using them outside of test scenes. For the shooter, the “shimmying” turned out to be a simple fix. In order to shoot, the enemy has to maintain line-of-sight with the player. The raycast that was being used to determine line-of-sight turned out to be colliding with both the enemy's projectiles and the enemy itself. The layer mask was adjusted accordingly. The other shooter bugs and some glaring charger bugs (i.e. getting stuck in corners, even if manually dragged away from them) were discovered to be caused by having both a NavMeshAgent and a Rigidbody on both enemies. While this is necessary to determine collisions (an agent does not have this capability), the Rigidbody must be set to IsKinematic to prevent these collisions from introducing velocity to it, which in turn competes with the movement of the NavMeshAgent. While it can be frustrating to invest so much time and energy into something so trivial, I am always happy to learn from these experiences – this will be one of the first conditions I enforce when using NavMeshAgents going forward.
We also patched many other bugs for the charger, including it becoming stuck on walls after charging, not transitioning states properly after attacking (by switching two lines of code), and it not moving on inclines. My most recent iteration of GroundDirectionChooser.cs included both a NavMeshSample and Physics.Raycast check to determine if a location was valid to move to. The raycast was originally used to avoid moving in a given direction if a wall was present. However, the raycast collided with the ground directly in front of the enemy when on an incline, and was therefore removed. In hindsight, the wall detection case seems unnecessary, as if one is in the way, the agent can simply move around it.
Once all of these changes and those for the shooter were made, I realized that I had been on the shooter branch of git the entire time. This should have been another simple fix – stash the charger changes, switch to the correct branch, and apply them. Instead, thinking that stashed changed cannot be applied to other branches, I manually copy/pasted the charger fixes into new files, switched branches, and re-inserted them into the appropriate scripts. Upon returning to the shooter branch, something was very wrong. Git’s status showed a large list of deleted files that I did not recall touching. I stashed the shooter changes and reset my project to the most recent development build. Going back to the shooter branch, I attempted to apply the stash, yet git detected no stashed files within the branch. I thought I had lost my work. It took a bit of panicking and research before I found my stashed files accessible in the development branch and realized that the copy/paste method had also been completely unnecessary (not to mention unsafe). Yet another painfully long and stressful scenario, but one I learned a lot from.
The following week, I put some additional work into adding events for the animators to use in the shooter driver, editing the animation event locations in the charger scripts, and attaching the correct shooter projectile prefab via a Unity package that one of our artists sent to me (after some editing to match the functionality of the temporary prefab from before). We also discovered that changing our enemies’ Rigidbodies to kinematic negatively effected some systems. For instance, collision with the player, which was fixed through enabling kinematic-kinematic pairs in the project settings, and any knockbacks that may need to be applied to enemies. The knockback script was adjusted to enable and disable the NavMeshAgent and IsKinematic/useGravity on the Rigidbody when necessary. This will need to be playtested a bit – there is potential for scripts such as PatrolBehavior.cs to attempt to access a disabled agent, resulting in errors. These scripts may need to be adjusted in the case of not having an active agent at times.
Lastly, I created a driver for our final enemy, the flier. This script functions nearly identically to the shooter driver regarding the state transition checks in Update. Where it differs is in the enemy’s functionality. The shooter driver became rather convoluted and bloated, handling nearly all of the behavior within one script. I wanted to separate concerns on the flier driver, allowing other scripts to receive the current state from FlyerDriver.cs and use it to perform their respective behaviors if necessary. The new driver therefore functions only as the base state machine for the enemy. It currently invokes a state change event when a transition is triggered, with a string representing that state given as a parameter. I would prefer this parameter to be an enumerated type. However, I did not see an easy way to invoke a Unity event with an enumerated type, particularly given the time I had to work on the script. I may look into this a bit more next week and consider other options as well, such as making the current state public or placing it outside of the FlyerDriver class.
Time breakdown:
Weekly studio meetings – 2 hours
Additional enemy pod meetings – 1 hour
Integrating/testing shooter behavior – 6 hours
Cooperative enemy debugging – 6 hours
Troubleshooting git – 2 hours
Shooter animations and projectile – 1.5 hours
Charger animations, collisions, and knockback – 3 hours
FlyerDriver.cs – 1.5 hours
Total time spent: 23 hours