You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

47 lines
6.2 KiB
Plaintext

<!--210501,210402-->
<h1>an enemy patrol in godot </h1>
april 29, 2021<br>
#ai #knowledgebase <br>
<br>
My patrol routes look like a series of waypoints (Position2Ds) which are the children of a patrol (Node2D). The patrol node is in a group named after the patrol route. Whenever the enemy decides to patrol, adds all the waypoints into an array. The nearest waypoint is set as the enemy's next point. The enemy then pathfinds by building a constellation of dots leading to that next point and moves fowards. To determine whether it is successfully moving towards or has reached the next point, the Knowledge Base is called in to help. <br>
<br>
The Knowledge Base is a system of event handlers and a message bus used originally to accomodate achievements. Since it is a clean, self-contained system that is aware of and can respond toevery event that happens in the game, it has grown to be the driving force behind dynamic events and game progression. <br>
<br>
<h2>fast explanation of the knowledge base </h2><br>
<br>
Essentially, individual, granular events are assigned a knowledge key. The Knowledge Base stores all knowledge in the game. Upon the encounter of a key in the wild, the key is used to "learn" a piece of knowledge by the Knowledge Base. Event Handlers are subscribed to the MessageBus, and once certain pieces knowledge are learned, they can generate an outcome. <br>
<br>
So let's say every tea has a unique knowledge key. Upon drinking mint tea, the "item_used" event is passed to the MessageBus, the Knowledge Base learns the "mint_tea" knowledge, and the tea achievement event handler takes note. The Knowledge Base groups all the tea knowledge arrays into the tea category. Once the tea category is complete, the tea drinker achievement is awarded to the player. <br>
<br>
I discuss its design and use more in other articles. <br>
<br>
<h2>why involve the achievement system? </h2><br>
<br>
The character or its AI could track its own proximity and vectors, but tying character movement into this achievement system allows more creativity in how the game world can respond to patrols. When event handlers can listen for certain characters to reach certain points, events like having guards switch shifts or get suspicious of missing buddies can happen naturally instead of being hard-coded. I could even do silly things like have an "Arbiter of Left" who censures any character who moves left within his zone. At the very least, I could do what many games do and include a step counter somewhere in a statistics menu. <br>
<br>
<h2>getting back into the patrol flow </h2><br>
<br>
So, to determine the enemy's progress towards reaching the next point, the enemy's going to generate an event handler for the "moved" event upon entering the patrol state. This event handler is going to be subscribed to "moved." Every time the enemy moves, it's going to publish "moved" and itself to the MessageBus, so the event handler can be notified. The event handler is going to take the enemy and evaluate whether it's reached the next point or an intermediary dot yet. The handler can also evaluate whether it's on course. Once the event handler knows how the enemy's doing, it will shoot off the appropriate signal. <br>
<br>
The enemy's AI will receive the signal and respond. If it's arrived at the next point, it will get the index of the current next point (the child order of the patrol node) and set the waypoint at the following index as the new next point. Then it can repeat the process of moving to this next point. If the AI finds out the enemy isn't on course, if can check to see if it's stuck on the terrain, affected by a paralysis status effect, or being pushed around by other characters, then respond appropriately. <br>
<br>
<h2>pathfinding and moving </h2><br>
Pathfinding is mostly handled by the Godot Engine, but there's an important distinction to maintain between the waypoints that form a patrol route and intermediary pathfinding points between a character and a waypoint. Lack of clarity in my design led to a few weeks of confusion. <br>
<br>
The "path_to_object" method handles finding a path between the character and goal point. It sets the given object as the next point and sets the character's "dots" as the discrete line between itself and the next point. These dots are determined by the zone's Navigation2D's built-in get_simple_path method. The dots are stored in the state machine. Upon getting new dots, it sets its current dot by popping the front dot off the array. The patrol state, every time Execute is called, sets the enemy's velocity as the current dot - the character's global position. It also published "moved" to the MessageBus for the event handler to handler. To actually move, the enemy's KinematicBody2D calls move_and_collide from its _process method with the parameter get_velocity() * get_speed() * delta. <br>
<br>
<h2>cleaning up </h2><br>
<br>
Since the enemy might switch out of the patrol state at any moment, the setup and teardown are important. I also was sure to use signals when communicating to the patrol state instead of direct calls. <br>
<br>
Every state in Blessfrey is structured into an Enter, Execute, and Exit method. Enter is called once upon state transition, Execute is called every time the AI's timer ticks, and Exit is called once upon transitioning out of the state. The Enter and Exit are where setup and teardown are called respectively. <br>
<br>
The setup instances the moved handler, subscribes it to "moved" through the message bus, and connects all the necessary signals between the event handler + patrol state and the patrol state + state machine. The teardown disconnects all these signals and unsubscribes + queue_frees the event handler. That way, all loose ends are tied up. <br>
<br>
<h2>finally - the enemy patrol! </h2><br>
Finally got the enemy patrol into the game. It required a redesign of the character movement system, the development of new features for the Knowledge Base, and tons of debugging, but I'm pretty happy with my little enemies. Next, I'll refactor movement, since there's still some fragments of the old movement system cluttering my AI scripts, but after that, I'll try publishing a release version for HTML5 to put up on my website. Looking forward to it! <br>
<br>
<br>
Last updated April 30, 2021 <br>
<br>