grid push

small-nav
chimchooree 4 years ago
parent c935346712
commit c13d2c03d9

@ -1,37 +1,63 @@
<!--210218,210107--> <!--210218,210107-->
<h1>designing a tutorial with bingo cards </h1> <h1>how to make a plugin for godot engine </h1>
april 15, 2021<br> april 15, 2021<br>
#gamedesign #tutorial<br> #godotengine <br>
<br> <br>
Give your players more freedom during the tutorial by having them play bingo. <br> If Godot Engine doesn't have the functionality you need, you can extend it with your own plugins. You can also use it to make specialized nodes to suit your project. <br>
<br> <br>
<h2>what's bingo? </h2><br> <h2>how to make a plugin </h2><br>
<br> <br>
Bingo is a game where the player is given a card with a grid filled with random squares. Someone will call out squares, and the player will cover the called squares with tokens. The goal is to fill a line of squares with tokens: a diagonal, a horizontal, or a vertical. Sometimes the game is played until a full card is covered. Since each card has different squares, it's a game of chance. <br> Navigate to your project folder. Within it, make a folder called <b>addons</b>. Within the addons folder, make a folder and name it after your plugin. Within the plugin folder, you will need a few files: plugin.cfg, custom_node.gd, a .gd file for each custom node your plugin will add, and a .png icon for your custom nodes. <br>
<br> <br>
Bingo's a popular gambling game in America, but it can be modified into an educational game, too. My music class played spurts of classical music in lieu of calling squares, so we had to identify the instrument in order to cover squares. <br> <h3>plugin.cfg </h3><br>
Within the plugin file, make a file called <b>plugin.cfg</b>. Open it in a simple text editor like Notepad and use this template to make your config: <br>
<br> <br>
[plugin]<br>
name="World"<br>
description="A world system."<br>
author="chimchooree"<br>
version="0.4"<br>
script="custom_node.gd"<br>
<br> <br>
<h2>using bingo to design a videogame </h2><br> Obviously, fill the space within the quotation marks with your own information. The script's value should be kept the same, though. Once you have these six lines in your file, save and close. Avoid writing these files in a full word processor like Microsoft Word because they tend to fill your documents with extra characters. Even if they aren't displayed in the word processor, they will make your file unreadable to Godot. <br>
<br> <br>
I like the bingo board as a game world because there are multiple paths to winning the game. The design of the board strikes a nice balance between game designer choice and player choice. The player is free to choose their own board based on their own criteria, but the designer ensured each board is reasonably equal. There's no board with 24 B4 squares on it, for instance. <br>
<br> <br>
This balance of freedom and control is great for something like a game tutorial. Usually, tutorials are set in extremely confined areas with strong limits on player exploration and choice. That's a good idea in theory because it will teach the player exactly what he needs to know at a pace that won't overwhelm him, but it's boring in practice. <br> <h3>custom_node.gd </h3><br>
Within the plugin file, make another file called <b>custom_node.gd</b>. The contents of this node should look like this: <br>
<br> <br>
You can think of a traditional tutorial as a row of squares on a bingo card. The squares are probably something like "move forward," "talk to an NPC," "double jump," "equip gun," and "hit the bulls-eye." If that was only one line on the board and all the other lines were filled with similar objectives, the player has a little more freedom to choose their own tutorial. The designer retains control over what the player learns because he can ensure each line is reasonably equal in its ability to prepare the player for the real game. The designer loses control of the order in which tasks are completed, but it's guaranteed that the player finished a complete set of tasks. <br> tool <br>
extends EditorPlugin<br>
<br> <br>
<h2>blessfrey bingo </h2><br> func _enter_tree():<br>
&nbsp;&nbsp;&nbsp;&nbsp;add_custom_type("Room", "Node2D", preload("room.gd"), preload("World.png"))<br>
<br> <br>
<center><img src="/static/img/ent/blessfreybingo.png" alt="(image: a bingo card filled with game objectives like Visit Nurse's Office, Talk to Chloe, Win a Sparring Match, and Buy Cheese Crackers.)"></center> <br> func _exit_tree():<br>
&nbsp;&nbsp;&nbsp;&nbsp;remove_custom_type("Room")<br>
<br> <br>
To play the main content in Blessfrey, the player needs to have basic knowledge of combat, dialog, different characters, and different areas on the map. There's also less vital information that the player should encounter quickly, like shopping, using phone apps, and randomized loot. So, almost every line has some basic combat, character interaction, and zone exploration. There's some more obscure tasks scattered around to hint at what kind of things are possible in the game. <br> To add a type, supply the <b>add_custom_type</b> method with 4 parameters: the name of your custom node, the node type (Node2D, AnimatedSprite, etc), your custom node's preloaded script, and a preloaded icon. Every type you add must also be removed. Use this process to add as many custom nodes as you need. <br>
<br> <br>
<h2>bingo and the players </h2><br>
<br> <br>
If you physically present the full card to the players, they will respond differently. Completionists might want to cover the entire board before leaving the tutorial area, so it would be fun to reward them. 1 bingo is a ticket out of Tutorial Land, but there can be further rewards for additional bingos and a big prize for the full board. Speedrunners (any%) are going to figure out which path is the fastest and only take that one. Most players are probably going to explore at their own pace and complete the objectives that seem easy or cool, though. <br> <h3>.gd files </h3><br>
For each custom node you declare in the custom_node.gd file, you'll need to supply a .gd script. These are going to look just like your other scripts in the editor. You can write them in full now or leave them relatively blank, but at least declare the type at the top. <br>
<br> <br>
<h2>in closing </h2><br> Since my example calls for a Node2D with a "room.gd", I can make a file within the plugins folder called <b>room.gd</b>. I'll keep the contents extremely simple for now: <br>
So long as the board and potential rewards are balanced, why not consider taking some inspiration from a bingo board when designing your tutorial? There doesn't have to be a literal board anywhere. The idea of alternate but equal paths to completing a tutorial already brings in more potential for player choice while retaining designer control. <br>
<br> <br>
Last updated April 15, 2021 <br> extends Node2D <br>
<br>
<br>
<h3>icon </h3><br>
Icon must be .png files with the dimensions of 16x16 pixels. They are just for you to see within the editor's node tree, so you can draw something fancy or just squish down the same Godot head everyone uses. You can also make a unique icon for each node or just use the same one across all nodes. Just make sure the file name matches what's used in custom_node.gd. <br>
<br>
If you want to use my squished icon, that's 100% fine with me. If you need to check the license for the original Godot head, though, it's on their <a href="https://github.com/godotengine/godot/blob/master/LOGO_LICENSE.md">git repo</a>. <img src="/static/img/ent/plugin_icon.png" alt="(image: Squished Godot head)"> <br>
<br>
When choosing whether to make something beautiful or lazy, let Colossians 3:23 echo in your head: "And whatever you do, do it heartily, as to the Lord and not to men." <br>
<br>
<br>
<h2>how to add a plugin </h2><br>
Now, inside Godot Engine's editor, go to the top-left menu and select Project>Project Settings and go to the Plugins tab. If your files came out okay, your new plugin should appear in the listing with all the data from your plugin.cfg file. Under the Status heading, make sure the plugin is set to "Enable" or "Active". To check whether your plugin's working, try to add a new node to a scene and search for your custom type. It should pop up with your custom icon in the search. If you add it, it will already have its custom script attached and ready to go. <br>
<br>
Happy coding! <br>
<br>
<br>
Last updated April 30, 2021 <br>
<br> <br>

@ -0,0 +1,46 @@
<!--210218,210107-->
<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>

@ -3,8 +3,6 @@
may 1, 2021<br> may 1, 2021<br>
<br> <br>
<br> <br>
<h2>week 1, april 1 - 3 </h2><br>
# <br>
<br> <br>
<h3>thursday, april 1 - April Fool's Day </h3> <h3>thursday, april 1 - April Fool's Day </h3>
<ul> <ul>
@ -20,7 +18,7 @@ may 1, 2021<br>
<li>I had several ways to initiate different phases of movement scattered throughout the program. I brought them together with an entry point. </li> <li>I had several ways to initiate different phases of movement scattered throughout the program. I brought them together with an entry point. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 7 </h3> <h3>wednesday, april 7 </h3>
<ul> <ul>
<li>Added handlers. The character shouldn't be its own handler because a handler can only handle one thing. I don't view this as an issue to correct, so instead the AI generates a handler to interpret the results of its attempts to move. Since NPCs use state machines as AI, they will do this during setup upon entering the Movement state and free them upon exiting. </li> <li>Added handlers. The character shouldn't be its own handler because a handler can only handle one thing. I don't view this as an issue to correct, so instead the AI generates a handler to interpret the results of its attempts to move. Since NPCs use state machines as AI, they will do this during setup upon entering the Movement state and free them upon exiting. </li>
<li>Added support for speed and velocity modifiers. </li> <li>Added support for speed and velocity modifiers. </li>
@ -31,58 +29,58 @@ may 1, 2021<br>
<li>Refactored pathfinding. </li> <li>Refactored pathfinding. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 9 </h3> <h3>friday, april 9 </h3>
<ul> <ul>
<li>Utter confusion over Slime Patrol begins. The slime won't move no matter what. I didn't spot the issue that prevented slime move-to-point until the very end of the month, which is frustrating but led to catching and fixing tons of potential issues in movement and related systems. It also got me to clean up the pathfinding debugger and make its output more detailed. </li> <li>Utter confusion over Slime Patrol begins. The slime won't move no matter what. I didn't spot the issue that prevented slime move-to-point until the very end of the month, which is frustrating but led to catching and fixing tons of potential issues in movement and related systems. It also got me to clean up the pathfinding debugger and make its output more detailed. </li>
<li>Of course I end up spending way more time than expected on the final update before my first release version...Can't wait to have something up! Even though it will be really bare bones. Once slime patrol works, movement is refactored, Bingo's tossed back in, and any noticeable issues are ironed out, I'll ship an HTML5 version to embed on my website. </li> <li>Of course I end up spending way more time than expected on the final update before my first release version...Can't wait to have something up! Even though it will be really bare bones. Once slime patrol works, movement is refactored, Bingo's tossed back in, and any noticeable issues are ironed out, I'll ship an HTML5 version to embed on my website. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 10 </h3> <h3>saturday, april 10 </h3>
<ul> <ul>
<li>Refactoring and debugging...Broke WASD movement and fixed it. </li> <li>Refactoring and debugging...Broke WASD movement and fixed it. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 11 </h3> <h3>sunday, april 11 </h3>
<ul> <ul>
<li>Refactoring and debugging...Broke mouse movement and fixed it. </li> <li>Refactoring and debugging...Broke mouse movement and fixed it. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 12 </h3> <h3>monday, april 12 </h3>
<ul> <ul>
<li>Refactoring and debugging...Slime moves in the wrong direction for an indisernible reason. Massively simplified how the slime identifies the order in which patrol points should be followed. </li> <li>Refactoring and debugging...Slime moves in the wrong direction for an indisernible reason. Massively simplified how the slime identifies the order in which patrol points should be followed. </li>
</ul> </ul>
<br> <br>
<h3>wednesday, april 13 </h3> <h3>tuesday, april 13 </h3>
<ul> <ul>
<li>I've been writing and drawing more lately. </li> <li>I've been writing and drawing more lately. </li>
<li>I feel more comfortable defining the mayor's character now, which is great because she's a major antagonist. She's supposed to be somewhat close in age and maturity to the teen protagonists, despite being in control of a city. I like the idea of a manchild leader with a powerful artifact. Since I'm not necessarily comfortable with writing conflicts between her and the main characters as life-or-death maximum evil encounters, I've been coming up with other stakes for the cast. It's more like petty maximum evil encounters. </li> <li>I feel more comfortable defining the mayor's character now, which is great because she's a major antagonist. She's supposed to be somewhat close in age and maturity to the teen protagonists, despite being in control of a city. I like the idea of a manchild leader with a powerful artifact. Since I'm not necessarily comfortable with writing conflicts between her and the main characters as life-or-death maximum evil encounters, I've been coming up with other stakes for the cast. It's more like petty maximum evil encounters. </li>
<li>She's always been "the mayor" lol. I finally have an idea what her name should be. Since the player's default name is Helia (a sunny name), the mayor will be given a moon name in contrast. Celeste and Selene feel overused in fantasy, and Liviana is too strongly associated with Magic: The Gathering for me. I was considering Chandra, Lunette, Charon, Dione, Liviana, and Mona...Do you think Chandra is too Hindi? For me, it has a strong local association with the Chandra space mission which is local to the setting + it's similar to the boomer name Shondra. </li> <li>She's always been "the mayor" lol. I finally have an idea what her name should be. Since the player's default name is Helia (a sunny name), the mayor will be given a moon name in contrast. Celeste and Selene feel overused in fantasy, and Liviana is too strongly associated with Magic: The Gathering for me. I was considering Chandra, Lunette, Charon, Dione, Liviana, and Mona...Do you think Chandra is too Hindi? For me, it has a strong local association with the Chandra space mission which is local to the setting + it's similar to the boomer name Shondra. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 14 </h3> <h3>wednesday, april 14 </h3>
<ul> <ul>
<li>I'm partially vaccinated against COVID now. It hurts... </li> <li>I'm partially vaccinated against COVID now. It hurts... </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 16 </h3> <h3>friday, april 16 </h3>
<ul> <ul>
<li>I was stuck in Sender Station in Anachronox for a while and finally got to Sunder. Finally! Progress in something! </li> <li>I was stuck in Sender Station in Anachronox for a while and finally got to Sunder. Finally! Progress in something! </li>
<li>The slime moves in a different direction depending on where it spawned. </li> <li>The slime moves in a different direction depending on where it spawned. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 17 </h3> <h3>saturday, april 17 </h3>
<ul> <ul>
<li>Refactoring and debugging... </li> <li>Refactoring and debugging... </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 18 </h3> <h3>sunday, april 18 </h3>
<ul> <ul>
<li>The first major problem is found, although correcting it doesn't change the slime's bizarre behavior yet. I was declaring that the slime reached a waypoint when it merely reached a dot. </li> <li>The first major problem is found, although correcting it doesn't change the slime's bizarre behavior yet. I was declaring that the slime reached a waypoint when it merely reached a dot. </li>
<li>In Blessfrey, pathfinding is made from a discrete line of "dots" and "waypoints." Waypoints are goal destinations, including waypoints along a patrol route and the global mouse position where the player point and clicked. Dots are the AI-determined positions inbetween the character and the next waypoint. <li> <li>In Blessfrey, pathfinding is made from a discrete line of "dots" and "waypoints." Waypoints are goal destinations, including waypoints along a patrol route and the global mouse position where the player point and clicked. Dots are the AI-determined positions inbetween the character and the next waypoint. <li>
<li>Refactoring and debugging...Make sure all entities are at position 0,0. </li> <li>Refactoring and debugging...Make sure all entities are at position 0,0. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 21 </h3> <h3>wednesday, april 21 </h3>
<ul> <ul>
<li>The player and NPCs need specialized movement handlers, so I create an Events plugin for Godot as a base movement handler. This allows me to fix player click-to-move, which was broken again. The individualized slime movement handler brings out the slime's first intended behavior! Even though he is moving in the wrong direction, he is selecting the nearest waypoint then cycling through them in order. </li> <li>The player and NPCs need specialized movement handlers, so I create an Events plugin for Godot as a base movement handler. This allows me to fix player click-to-move, which was broken again. The individualized slime movement handler brings out the slime's first intended behavior! Even though he is moving in the wrong direction, he is selecting the nearest waypoint then cycling through them in order. </li>
</ul> </ul>
@ -95,7 +93,7 @@ may 1, 2021<br>
<li>Debugging and refactoring...</li> <li>Debugging and refactoring...</li>
</ul> </ul>
<br> <br>
<h3>thursday, april 23 </h3> <h3>friday, april 23 </h3>
<ul> <ul>
<li>How did Just Dance released Big Bang songs without me hearing about it? Not only Big Bang, but also G-Dragon's solo career. Amazing!!! Fantastic Baby is Japanese only. I thought the Wii was region-free, but apparently not...Guess I'm stuck to playing 'pretend Just Dance' with Youtube recordings lol. But Bang Bang Bang got a real American release for 2019 that I will definitely investigate.</li> <li>How did Just Dance released Big Bang songs without me hearing about it? Not only Big Bang, but also G-Dragon's solo career. Amazing!!! Fantastic Baby is Japanese only. I thought the Wii was region-free, but apparently not...Guess I'm stuck to playing 'pretend Just Dance' with Youtube recordings lol. But Bang Bang Bang got a real American release for 2019 that I will definitely investigate.</li>
<li>There are two entry points for movement: move_to_position and move_to_object. I decide to make move_to_object the only entrypoint. This means a waypoint is generated at the position the player wants to move to. This allows for player movement to be more similar to character patrol movement, and it opens up the possibility of allowing the player to select multiple movement points or to draw his own patrol route. </li> <li>There are two entry points for movement: move_to_position and move_to_object. I decide to make move_to_object the only entrypoint. This means a waypoint is generated at the position the player wants to move to. This allows for player movement to be more similar to character patrol movement, and it opens up the possibility of allowing the player to select multiple movement points or to draw his own patrol route. </li>
@ -103,7 +101,7 @@ may 1, 2021<br>
</ul> </ul>
<br> <br>
<br> <br>
<h3>thursday, april 24 </h3> <h3>saturday, april 24 </h3>
<ul> <ul>
<li>Breakthroughs all around. I've been developing a quinoa recipe for years and finally used molasses. Molasses isn't really sweet but has more of that robust, almost spicy flavor that is the key to my vision. I tried with brown sugar before, but it mostly just makes quinoa taste sweet which I dislike. For two people I cook 2/3 c soaked quinoa (remove the frothy saponins), 4/3 c water, 1 tsp onion powder, 1 tsp garlic powder, 1/4 tsp salt, 1 tbsp squeezed lemon juice (no seeds), 1 tbsp olive oil, between 1/2 and 1 tbsp molasses, some lemon pulp, and four halved kalamata olives together in an uncovered saucepan. For molasses, 1/2 is too mellow and sweet, while 1 tbsp is strong and spicy but still good. Stir occasionally. After most of the water is boiled away, cover and steam the quinoa at reduced heat. Before serving, mix in mint and chives. It goes really well with tomatos, cucumbers, and spinach, but any vegetables will do. Finally, the taste I envisioned in my head! I'm still tweaking the proportions, but those are definitely the right ingredients. If only kitty didn't force me to give up my chive and mint garden. That would have been even better. </li> <li>Breakthroughs all around. I've been developing a quinoa recipe for years and finally used molasses. Molasses isn't really sweet but has more of that robust, almost spicy flavor that is the key to my vision. I tried with brown sugar before, but it mostly just makes quinoa taste sweet which I dislike. For two people I cook 2/3 c soaked quinoa (remove the frothy saponins), 4/3 c water, 1 tsp onion powder, 1 tsp garlic powder, 1/4 tsp salt, 1 tbsp squeezed lemon juice (no seeds), 1 tbsp olive oil, between 1/2 and 1 tbsp molasses, some lemon pulp, and four halved kalamata olives together in an uncovered saucepan. For molasses, 1/2 is too mellow and sweet, while 1 tbsp is strong and spicy but still good. Stir occasionally. After most of the water is boiled away, cover and steam the quinoa at reduced heat. Before serving, mix in mint and chives. It goes really well with tomatos, cucumbers, and spinach, but any vegetables will do. Finally, the taste I envisioned in my head! I'm still tweaking the proportions, but those are definitely the right ingredients. If only kitty didn't force me to give up my chive and mint garden. That would have been even better. </li>
<li>The flavor's supposed to be reminiscent of how I used to prepare Near East's Rosemary & Olive Oil Quinoa & Brown Rice blend. It got bland with the recipe change a while back, then a few years ago, stores stopped carrying it at all. It was the only box food I ever liked, though, and I've never stopped trying to recreate it. (Even though my version doesn't have rosemary, brown rice, or pretty much any of the same ingredients and tastes completely differently but whatever lol.) </li> <li>The flavor's supposed to be reminiscent of how I used to prepare Near East's Rosemary & Olive Oil Quinoa & Brown Rice blend. It got bland with the recipe change a while back, then a few years ago, stores stopped carrying it at all. It was the only box food I ever liked, though, and I've never stopped trying to recreate it. (Even though my version doesn't have rosemary, brown rice, or pretty much any of the same ingredients and tastes completely differently but whatever lol.) </li>
@ -111,7 +109,7 @@ may 1, 2021<br>
<li>I write some story for the Abyss and the Slime Kingdom, but it's not very interesting or funny. At least if I write a lot, I can be choosy and only take the few best events. </li> <li>I write some story for the Abyss and the Slime Kingdom, but it's not very interesting or funny. At least if I write a lot, I can be choosy and only take the few best events. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 25 </h3> <h3>sunday, april 25 </h3>
<ul> <ul>
<li>I fixed it. It's not the best fix, but I understand the problem. The slime finally patrols perfectly, no hiccups or unexpected behavior. If the player interrupts him, he can return to the patrol route and resume patrolling. </li> <li>I fixed it. It's not the best fix, but I understand the problem. The slime finally patrols perfectly, no hiccups or unexpected behavior. If the player interrupts him, he can return to the patrol route and resume patrolling. </li>
<li>The problem has to do with initialization. Apparently, the slime's initial global position is 0,0 before it is set to it's spawner's location. </li> <li>The problem has to do with initialization. Apparently, the slime's initial global position is 0,0 before it is set to it's spawner's location. </li>
@ -121,9 +119,15 @@ may 1, 2021<br>
<li>More refactoring and debugging so everything's clean and pretty. </li> <li>More refactoring and debugging so everything's clean and pretty. </li>
</ul> </ul>
<br> <br>
<h3>thursday, april 26 </h3> <h3>monday, april 26 </h3>
<ul> <ul>
<li>Now time to make sure all movement uses the new system. Move_to_skill_target, move_to_item, and move_to_target were all handled separately. </li> <li>Now time to make sure all movement uses the new system. Move_to_skill_target, move_to_item, and move_to_target were all handled separately. </li>
<li>The first thing I'd like to tackle is moving to a moving target. I draw diagrams and decide that having move_to_object only consider waypoints may be inferior to also taking targets. Setting the target as the next waypoint allows the player to tab through other targets without interrupting autopathing. Also, tracking movement is probably a job once again for the Knowledge Base and event handlers. </li> <li>The first thing I'd like to tackle is moving to a moving target. I draw diagrams and decide that having move_to_object only consider waypoints may be inferior to also taking targets. Setting the target as the next waypoint allows the player to tab through other targets without interrupting autopathing. Also, tracking movement is probably a job once again for the Knowledge Base and event handlers. </li>
</ul> </ul>
<br> <br>
<h3>friday, april 30 </h3>
<ul>
<li>Website maintenance day. I'm starting to wonder if anyone reads this? I don't share links, but it's probably somewhere in Google by now. Especially since I write about Godot Engine some, and that's definitely a topic not a ton of people write about. To see visitors, you need to use trackers, though, and the big ones are overly invasive and by companies I don't particularly like. Maybe I'll have to do some research and see what's available. </li>
<li>It's kind of annoying that the server is in almost a day ahead since it's in a different country. I should change the time zone to match mine sometime. I know it's online, so people in every time zone can read it if they want, but it sure makes predicting articles releases more confusing for me. <br>
</ul>
<br>

@ -0,0 +1,46 @@
<!--210218,210107-->
<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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Loading…
Cancel
Save