Fine-tuning Enemy AI


This week, since I created all the enemies we are going to have for now, I focused on fine-tuning the enemy AI and debugging anything that didn't seem quite right. I ended up having to fix more than I thought because when I updated the enemy base class for the ore type enemies, I forgot the plant type enemies also used the same base so it ended up duplicating any variables or functions that were in there before I updated the base class. Once I fixed that, I also found out that the potato enemy was no longer attacking at all but all the other plants were. After some debugging, I found the issue and resolved it and all the plants attacked as they should. After I fixed everything that got broken over time, I turned my focus onto making improvements to the AI of the plant enemies to make them a bit more active and difficult since they are stationary targets. I originally tried to fix this by having the tree enemy rotate towards the player (since we don't have models/animations for forward and backward attacks) so that the player can't just cheese it by standing where the tree can't hit them. This was also so the apples that the tree throws would go towards the player as well. The issue with this though was that I was updating the rotation of the actor using math and LERPing it but it never really looked right and was a bit too slow and mechanical. When I transferred the same functionality over to the tomato plant, I again wasn't happy with it so I looked for a better way to do it.

This is the math I was having to do every tick to rotate the enemy towards the player. It mostly worked but I felt like it could have been better.

After a bit of research, it turned out the answer was quite simple. My thinking was that since its an action related to their AI, I should move it to the behavior tree instead of the event graph for the actor. As it turns out, Unreal already has a built in task to rotate towards a specified blackboard key, in this case the player. So my original thought was to just replace the wait node in my simple parallels for the attack sequence with that rotate task and it seemed to work, but wasn't quite right. The issue now was that since it was a simple parallel, the enemy would now only attack if it rotated first. So if you got within range and it turned to face you then attacked, if you sat still then they would not attack anymore because its waiting for a rotation. After this I looked up the documentation for decorators and found one called a cone condition which seemed like it was used for determining the angle between a source (the enemy) and a target (the player). This also sort of worked to rotate the enemy but it caused some issues like it would only rotate if the player was out of melee range but in melee range it would break and not even attack. After some more head scratching I realized I was over complicating things and instead of a simple parallel I could use a simple sequence to rotate the enemy and then attempt to run the attack task if the player is in melee range. This turned out to be exactly what I was going for and after a bit more tweaking finally got to a place I was happy with it and I no longer had to run math calculation every tick to rotate the enemy.

This is an updated look at one of the behavior trees using the built in rotate task that works much better.
Author: Chase Thacker 2/29/2024

Leave a comment

Log in with itch.io to leave a comment.