Log 30: Getting Artificially Intelligent...With No AI Generated Content in Sight!
- Kassandra McCormack
- May 28
- 6 min read

...We should really come up with a different name for it now that ChatGPT and its ilk are real things, but I've never been good at naming things so I doubt I'll come up with the new term.
Anyway, enough of my tangent and on to something unrelated to my game's AI system. The first thing I did was fix a quick bug with attacking where I was setting attacks to weapon attacks only when the summoning animation is fully completed. Which meant that if the player wanted a weapon attack they would have to wait a bit before they could do it, so I changed the attack setting to be at the beginning of the animation. Another "bug" was when the character gets guard broken, I had forgotten to actually stop the guarding, so that was a quick fix with a single function call.
On to the AI! The first thing I did was to close the project, and open up a Warriors game (Specifically Dynasty Warriors: Origins). This time instead of playing I sat and studied how they have the enemies function.
When enemies are not aware of the player they typically just stand around. Some missions will have them moving about the map to target areas, these are typically story missions though.
While numerous enemies can be aware of the player, only a handful have healthbars above their heads and those are the only ones that can attack.
While waiting to attack, enemies move around in seemingly random ways around the player, including away from and towards the player.
Those that attack stay closer and don't wander away immediately
Enemies attack one at a time, but can attack one after the other
Melee enemies attack one at a time, ranged enemies all attack at once in single volley
Captain enemies (that is those with names or titles) can attack continuously (some kind of cooldown or grace period in between attacks) even when other basic enemies are also attacking.
On occasion, captain enemies can guard. I haven't found the trigger for this, it could just be on a timer or when it is off cooldown and the player attacks.
The next thing I did was look up AI tutorials online. I had attempted using behavior trees before in Unity so I was familiar with the concept, but I wanted to learn how they were implemented in Unreal. I wound up relying heavily on tutorial series made by Ryan Laley and another by Ali Elzoheiry.

While following Ali's tutorial series I realized I would need to refactor how the attack controller worked and interacted with animations. Because the behavior tree tasks would need to know when the attack animation was finished the attack functions had to be moved over to macros so that I could use the Play Montage node with all the output pins. This enabled me to move the attack stage notifies into Montage Notifies called directly on the Attack Controller. The only notify I had to leave was the Detect Hits notify as that one passes in custom hit detection info for the animation.

One thing I noticed when enemies became capable of moving on their own: When they push into the player character or the player character pushes into them, it breaks the physics and at least one character goes flying. At this point I did some research into how other Warriors games treat moving through the hoards of enemies. Specifically I opened up three games: Dynasty Warriors: Origins, Fire Emblem Warriors: Three Houses, and Hyrule Warriors: Age of Calamity. In the two Switch games the player could easily push enemies out of the way, while in Origins the player can not do that, the characters act more like how default Unreal characters push on each other (that is neither of them move). I ultimately decided to just go the Origins route and not have enemy characters get pushed out of the way because I've spent weeks on this problem, cumulatively, and I need to stop on it before it consumes more time. Moving about the battlefield in Origins feels fine so I'll have to assume that my game will feel fine with it too (since I'm not at the point of being able to fully test moving through hoards of enemies). One thing I did notice with Origins enemies is that once the player character touches them, they tend to move on their own to a set distance from the player, which kind of gets them out of the way. I would eventually realize this is a byproduct of what will eventually become the strafing node on my behavior tree.
Once I got the enemy characters attacking I found several pieces of my game either didn't work or just felt really bad to be on the receiving end. The first piece I noticed was that when the enemy hit the player, the player's health bar would not go down. At first I thought it was a bug with the health bar but, no...the stats were just so heavily skewed that the damage was too small to be noticeable. I had to play around with the character stats a bit to make the game a bit more balanced and challenging. I still have to do more number balancing later but for now it is working fine.
The next thing I had to change is: Originally, I had built a system where when a character starts hitting another the hit character gets dragged into a central location in front of the attacking character. This didn't feel or look super great, but helped with some attack animation edge cases (e.g. where the attack animation has significant root motion). However, once the enemy did it to the player...Wow did it feel and look really bad. So I had to scrap that whole system. I left it in, just in case I want to do some sort of gravity effect later, but just disconnected it for now.
A weird bug that popped up was: After getting hit the player would be able to super jump. It turned out that for some reason (that I'm sure made sense to me a while ago) on receiving a hit I set the gravity scale to 0.5. I just got rid of that and the bug was fixed. Yay, easy fix!
I had a couple of hiccups with setting up the enemy block and token return systems. They weren't anything major, I just hooked up my function calls in the wrong spots so they didn't immediately work as intended.
Speaking of Doom's token system: as Ali was explaining it in his video I was struck by the realization that that was probably how Origins did it too. With the token system it would enable the enemies to only attack one at a time, and depending on cooldowns they could attack back to back or spaced out. Testing it out in engine showed that I was right, so the vindication was nice.
One that that I needed to do separate from the tutorials was make the AI character stop moving when they get hit. I already had a variable that gets updated when a character gets hit: the [Time Last Hit] variable that I use to keep track of the character being stuck in a combo. At first I tried making a custom decorator that tracked the value, but for some reason it refused to abort anything when the value was changed. I wound up working around it by making a blackboard variable for it that updates every tick and when that variable is over 0, then it aborts whatever movement task is being done.
One final bug that I noticed was that the enemy character was never locking off of the player character, even when out of sight. This was especially weird because I had thought of that before and put in a "clear target" node, but it wasn't triggering. It turns out I had put it on the false pin of the wrong branch node, so it was never getting there. A little bit of nodes moving around and now the enemy loses sight of the player!
It was at this point that I realized I was more or less done with the basic enemy AI. Just following along with the tutorials and I managed to hit all my observations from Dynasty Warriors: Origins. That's an odd feeling, but I suppose basic enemies are really simplistic in Warriors games. I'll need to do a bit of work for boss enemies and getting enemies to move around the map during story missions, but for the most part it would all be re-using the same nodes that the basic enemy behavior tree uses.
Comments