<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shun Moriya</title>
    <description>The latest articles on DEV Community by Shun Moriya (@shun126).</description>
    <link>https://dev.to/shun126</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4195470%2F79046689-4862-4d08-b828-b9d55fb75aef.png</url>
      <title>DEV Community: Shun Moriya</title>
      <link>https://dev.to/shun126</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shun126"/>
    <language>en</language>
    <item>
      <title>Script Design Notes — How Much of Game AI Should the Runtime Handle? (Part 2)</title>
      <dc:creator>Shun Moriya</dc:creator>
      <pubDate>Sun, 25 Oct 2026 14:46:13 +0000</pubDate>
      <link>https://dev.to/shun126/script-design-notes-how-much-of-game-ai-should-the-runtime-handle-part-2-3842</link>
      <guid>https://dev.to/shun126/script-design-notes-how-much-of-game-ai-should-the-runtime-handle-part-2-3842</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/shun126/why-i-chose-requests-instead-of-function-calls-for-game-actions-17aa"&gt;the first article&lt;/a&gt;, I wrote about why I introduced action requests in Mana, a scripting language I develop as a personal project.&lt;/p&gt;

&lt;p&gt;The idea was to let the runtime preserve an interrupted action and resume it later, instead of making each gameplay system manage that execution state itself.&lt;/p&gt;

&lt;p&gt;This time, I want to look more closely at what that means for game AI.&lt;/p&gt;

&lt;p&gt;By game AI, I mean the logic behind enemy and NPC behavior: patrolling, reacting to a hit, talking, and deciding what to do next.&lt;/p&gt;

&lt;p&gt;There are two questions I want to separate: how an action continues executing, and whether continuing that action still makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let Each Actor Own Its Progress
&lt;/h2&gt;

&lt;p&gt;A game often has several things happening at once.&lt;/p&gt;

&lt;p&gt;A guard patrols while another NPC talks. A door opens while enemies keep moving. An event controller waits for one character to finish an action while the rest of the scene continues.&lt;/p&gt;

&lt;p&gt;For these situations, I found it useful to think of each participant as owning its state and behavior, asking other participants to act when necessary.&lt;/p&gt;

&lt;p&gt;In Mana, a participant is an &lt;code&gt;Actor&lt;/code&gt;, and a named behavior belonging to it is an &lt;code&gt;Action&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A guard might have &lt;code&gt;patrol&lt;/code&gt;, &lt;code&gt;talk&lt;/code&gt;, and &lt;code&gt;damage&lt;/code&gt; Actions. An event controller can request a conversation without knowing which line of the patrol script the guard has reached.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Actor performing an action owns the progress of that action.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Actor Model helped shape this way of dividing responsibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Mana Borrows from the Actor Model
&lt;/h2&gt;

&lt;p&gt;The Actor Model describes independent entities that coordinate through messages.&lt;/p&gt;

&lt;p&gt;Mana borrows the idea of asking another participant to do something while leaving that participant responsible for its own execution.&lt;/p&gt;

&lt;p&gt;However, Mana is not a conventional implementation of the Actor Model.&lt;/p&gt;

&lt;p&gt;Its priority levels, action interruption, and resumption rules are mechanisms I added for gameplay scripting. Mana also supports global variables, so it does not enforce a design in which all state is isolated inside Actors.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Mana's approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Organizing behavior&lt;/td&gt;
&lt;td&gt;Actors own state and named Actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interacting with another Actor&lt;/td&gt;
&lt;td&gt;Request an Action with &lt;code&gt;request&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Choosing which Action runs&lt;/td&gt;
&lt;td&gt;Use priorities to interrupt or defer execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preserving interrupted work&lt;/td&gt;
&lt;td&gt;Keep execution state for each priority level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advancing Actors&lt;/td&gt;
&lt;td&gt;Let the VM run them in turn&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The distinction matters: the priority and resumption rules below describe Mana, rather than properties guaranteed by the Actor Model in general.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Hit Reaction in the Middle of a Patrol
&lt;/h2&gt;

&lt;p&gt;Consider an enemy with two Actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;patrol&lt;/code&gt;, its ordinary behavior, at priority &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;damage&lt;/code&gt;, its hit reaction, at priority &lt;code&gt;5&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Mana, a larger number means a higher priority.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;kPatrolPriority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;kDamagePriority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;actor&lt;/span&gt; &lt;span class="n"&gt;Enemy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kPatrolPriority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;patrol&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="nf"&gt;patrol&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enemy: Patrol A&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kDamagePriority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;damage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enemy: Patrol B&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="nf"&gt;damage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enemy: Ouch!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is Mana code; I am using C++ syntax highlighting because the syntax is similar.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;self&lt;/code&gt; refers to the current Actor. To keep the example focused on execution order, the enemy requests its own hit reaction during the patrol. In a game, a system detecting a hit could issue that request instead.&lt;/p&gt;

&lt;p&gt;The expected output is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Enemy: Patrol A
Enemy: Ouch!
Enemy: Patrol B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After &lt;code&gt;patrol&lt;/code&gt; prints its first message, the higher-priority &lt;code&gt;damage&lt;/code&gt; Action interrupts it. When &lt;code&gt;damage&lt;/code&gt; finishes, &lt;code&gt;patrol&lt;/code&gt; continues with the statement after the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Priority 1: patrol prints "Patrol A"
                |
                | Request damage at priority 5
                v
Priority 5: damage prints "Ouch!"
                |
                | damage finishes
                v
Priority 1: patrol resumes and prints "Patrol B"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example only prints messages. It does not move a character or play an animation.&lt;/p&gt;

&lt;p&gt;The important detail is that &lt;code&gt;damage&lt;/code&gt; contains no code to return to patrol.&lt;/p&gt;

&lt;p&gt;The hit reaction does not need to know whether it interrupted patrolling, talking, or something else. The VM preserves the interrupted execution state and resumes it afterward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where State Machines Still Fit
&lt;/h2&gt;

&lt;p&gt;State machines remain useful for organizing game AI.&lt;/p&gt;

&lt;p&gt;States such as patrolling, alert, and fighting make the character's current situation explicit. They provide a clear place to describe the conditions for switching behavior.&lt;/p&gt;

&lt;p&gt;Temporarily interrupting a behavior and later continuing it requires another kind of information: how far that behavior has progressed.&lt;/p&gt;

&lt;p&gt;Hierarchical state machines, state stacks, and coroutines can also represent this. Mana places the interruption and resumption mechanism in the VM, with execution state organized by priority.&lt;/p&gt;

&lt;p&gt;That still leaves an important gameplay question unanswered.&lt;/p&gt;

&lt;p&gt;Suppose the enemy spots the player while reacting to a hit. Once the reaction ends, should it continue patrolling? Perhaps it should start fighting instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Being able to resume a piece of code and deciding that its behavior is still appropriate are separate responsibilities.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The VM remembers where execution stopped. It does not, by doing so, determine what the character should do in a changed situation.&lt;/p&gt;

&lt;p&gt;For my purposes, a useful division seems to be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Represent situations such as alert or fighting through Actor variables or a state machine.&lt;/li&gt;
&lt;li&gt;Let priorities and the VM handle temporary interruption and resumption.&lt;/li&gt;
&lt;li&gt;Recheck the current situation when resumed behavior needs to respond to changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moving execution management into the runtime reduces some bookkeeping. The game still needs rules for choosing behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concurrent Behavior Without a Thread per Actor
&lt;/h2&gt;

&lt;p&gt;There is another aspect of this execution model worth clarifying.&lt;/p&gt;

&lt;p&gt;The Actor Model does not require a dedicated thread for every Actor. Mana does not create one either.&lt;/p&gt;

&lt;p&gt;The VM advances Actors in turn, allowing their behaviors to make progress over time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VM update
  -&amp;gt; Advance Actor A
  -&amp;gt; Advance Actor B
  -&amp;gt; Advance Actor C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mana's documentation describes this as cooperative pseudo-parallel execution.&lt;/p&gt;

&lt;p&gt;Scripts can also use &lt;code&gt;yield()&lt;/code&gt; to give control back to the VM, spreading an action across multiple advances of the runtime.&lt;/p&gt;

&lt;p&gt;I chose this approach because I wanted the execution model to fit into a game's update loop. The goal was to advance each participant's behavior alongside the game, rather than execute every Actor simultaneously on the CPU.&lt;/p&gt;

&lt;p&gt;Execution order still matters, though. When a request is issued, and how far its target has already progressed, can affect behavior.&lt;/p&gt;

&lt;p&gt;For an event that needs a specific sequence, yielding control is not enough to establish that another Actor's action has finished. That is where explicit waiting, such as the &lt;code&gt;await&lt;/code&gt; described in the first article, becomes useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple Actions Can Still Produce Complicated Interactions
&lt;/h2&gt;

&lt;p&gt;Letting the VM manage interruption can make individual Actions easier to read.&lt;/p&gt;

&lt;p&gt;But understanding the Actor as a whole can become harder as more requests interact.&lt;/p&gt;

&lt;p&gt;For example, an Actor might have this execution state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Priority 5: damage is running
Priority 3: talk is pending
Priority 1: patrol is suspended
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;damage&lt;/code&gt; finishes, &lt;code&gt;patrol&lt;/code&gt; does not immediately resume. The pending &lt;code&gt;talk&lt;/code&gt; Action has a higher priority and runs first.&lt;/p&gt;

&lt;p&gt;Each Action may be simple on its own, while the combination produces behavior that is difficult to infer from any one definition.&lt;/p&gt;

&lt;p&gt;The one-request-per-priority restriction discussed in the first article also matters here. If &lt;code&gt;damage&lt;/code&gt; already occupies a priority slot, another request at that priority cannot be queued behind it.&lt;/p&gt;

&lt;p&gt;Assigning a priority to hit reactions therefore does not fully specify how repeated hits should behave. The game still needs to decide what those events mean and how to handle them within the available execution model.&lt;/p&gt;

&lt;p&gt;This makes me think that better runtime visibility would be valuable. I would like to make it easier to inspect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which Action is currently executing.&lt;/li&gt;
&lt;li&gt;Which Actions are suspended.&lt;/li&gt;
&lt;li&gt;Which requests are pending.&lt;/li&gt;
&lt;li&gt;Which requests were rejected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A language feature can make behavior easier to write while also making its interactions harder to observe. The tools for understanding that behavior deserve attention alongside the execution model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Boundary I Am Trying to Draw
&lt;/h2&gt;

&lt;p&gt;Mana combines the idea of independent participants exchanging requests with gameplay-specific rules for priorities, interruption, and resumption.&lt;/p&gt;

&lt;p&gt;In the patrol example, the VM takes responsibility for preserving interrupted execution and determining when it can continue. The game retains responsibility for deciding whether that continuation is appropriate.&lt;/p&gt;

&lt;p&gt;I think that division can reduce the amount of execution bookkeeping in gameplay scripts. It also leaves real design work around changing situations, competing requests, and repeated events.&lt;/p&gt;

&lt;p&gt;That is the boundary I am still exploring: how much the runtime should remember and schedule, and how much the game should decide.&lt;/p&gt;

&lt;p&gt;To experiment with the execution rules, try the &lt;strong&gt;Request&lt;/strong&gt; example in the &lt;a href="https://shun126.github.io/Mana/playground/" rel="noopener noreferrer"&gt;Mana Playground&lt;/a&gt;. Lower the alarm priority below the conversation priority and watch how an interruption becomes deferred work.&lt;/p&gt;

&lt;p&gt;The implementation is available in the &lt;a href="https://github.com/shun126/Mana" rel="noopener noreferrer"&gt;Mana repository&lt;/a&gt;. Connecting this VM to a game's update loop is another part of the design I want to explore in this series.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>architecture</category>
      <category>programming</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Script Design Notes — Why I Chose Requests Instead of Function Calls for Game Actions</title>
      <dc:creator>Shun Moriya</dc:creator>
      <pubDate>Tue, 20 Oct 2026 16:42:40 +0000</pubDate>
      <link>https://dev.to/shun126/why-i-chose-requests-instead-of-function-calls-for-game-actions-17aa</link>
      <guid>https://dev.to/shun126/why-i-chose-requests-instead-of-function-calls-for-game-actions-17aa</guid>
      <description>&lt;p&gt;Imagine an NPC patrolling an area. The NPC notices an enemy and switches to combat. During combat, it takes damage and plays a hit reaction. Once the reaction is over, it resumes fighting. When combat ends, it returns to its patrol.&lt;/p&gt;

&lt;p&gt;This is ordinary behavior in a game. But implementing it can become surprisingly complicated.&lt;/p&gt;

&lt;p&gt;Where should each action be interrupted? Who remembers what the character was doing? How should an interrupted action resume?&lt;/p&gt;

&lt;p&gt;I wanted to find a simpler way to describe these behaviors.&lt;/p&gt;

&lt;p&gt;That idea eventually led me to develop &lt;strong&gt;Mana&lt;/strong&gt;, a scripting language for game characters and gameplay logic.&lt;/p&gt;

&lt;p&gt;I've been working on it as a personal project since 2016, and finally reached version 1.0 in 2026.&lt;/p&gt;

&lt;p&gt;Now that I've reached that milestone, I'd like to write about some of the decisions I made while developing the language, the problems those decisions created, and the questions I still haven't resolved.&lt;/p&gt;

&lt;p&gt;This is not intended to be a language tutorial or a feature announcement. It's a series of development notes about the difficulties of designing a scripting language specifically for games.&lt;/p&gt;

&lt;p&gt;For this first article, I'll focus on one of Mana's central ideas: &lt;strong&gt;requesting an action instead of directly calling it.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  First, Try Running It
&lt;/h1&gt;

&lt;p&gt;Before getting into the design, it may be easier to see how the language behaves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://shun126.github.io/Mana/playground/" rel="noopener noreferrer"&gt;&lt;strong&gt;Mana Playground — Try it in your browser&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Playground runs the compiler and virtual machine through WebAssembly, so nothing needs to be installed.&lt;/p&gt;

&lt;p&gt;There are three examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hello:&lt;/strong&gt; A minimal script that prints a message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actor:&lt;/strong&gt; A lamp that remembers its brightness and changes its state when asked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request:&lt;/strong&gt; A conversation interrupted by an alarm, followed by a return to the conversation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Request example is particularly relevant to this article.&lt;/p&gt;

&lt;p&gt;Try changing the alarm priority from &lt;code&gt;100&lt;/code&gt; to &lt;code&gt;5&lt;/code&gt; and observing how the execution order changes.&lt;/p&gt;

&lt;p&gt;You can also replace &lt;code&gt;request&lt;/code&gt; with &lt;code&gt;await&lt;/code&gt; to see what happens when one actor waits for another.&lt;/p&gt;

&lt;p&gt;You don't need to understand the syntax yet. The interesting part is how changing a small piece of code changes the order in which actions execute.&lt;/p&gt;

&lt;h1&gt;
  
  
  Who Should Own an Action?
&lt;/h1&gt;

&lt;p&gt;In Mana, game characters and other participants are represented as &lt;code&gt;Actor&lt;/code&gt; objects.&lt;/p&gt;

&lt;p&gt;Each Actor owns its behavior, represented by &lt;code&gt;Action&lt;/code&gt; definitions.&lt;/p&gt;

&lt;p&gt;The basic idea is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Character = Actor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavior = Action&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interaction = Request&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, to ask a guard to move:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request(3, Guard-&amp;gt;move());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means: ask the &lt;code&gt;Guard&lt;/code&gt; actor to execute its &lt;code&gt;move&lt;/code&gt; action with priority &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The syntax may look similar to a function call, but the execution model is different.&lt;/p&gt;

&lt;p&gt;The idea was inspired by the Actor Model, although Mana is not intended to be a conventional implementation of it.&lt;/p&gt;

&lt;p&gt;I wanted to adapt some of its concepts to the specific problems of game behavior: actions that take time, can be interrupted, and may eventually resume.&lt;/p&gt;

&lt;p&gt;That raised a question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should one character execute another character's behavior, or should it simply ask that character to perform the behavior?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I chose the latter.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Not Just Call a Function?
&lt;/h1&gt;

&lt;p&gt;In a conventional synchronous function call, the caller waits until the function returns.&lt;/p&gt;

&lt;p&gt;For short operations, this is usually exactly what we want.&lt;/p&gt;

&lt;p&gt;Game actions, however, often take place over multiple frames.&lt;/p&gt;

&lt;p&gt;A character may walk toward a destination. A door may take several seconds to open. A conversation may pause while waiting for player input.&lt;/p&gt;

&lt;p&gt;Of course, none of this requires a new programming language.&lt;/p&gt;

&lt;p&gt;State machines, coroutines, asynchronous functions, and task schedulers can all handle such behavior.&lt;/p&gt;

&lt;p&gt;The difficulty I wanted to address was not asynchronous execution itself.&lt;/p&gt;

&lt;p&gt;It was &lt;strong&gt;the responsibility for interrupting, preserving, and resuming an action.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider the patrol example again.&lt;/p&gt;

&lt;p&gt;If the character switches from patrol to combat, something must remember the patrol state. If a damage reaction interrupts combat, the combat state must also be preserved.&lt;/p&gt;

&lt;p&gt;When the damage reaction finishes, combat should resume. When combat finishes, patrol should resume.&lt;/p&gt;

&lt;p&gt;As more behaviors interact, the code managing these transitions can become more complicated than the behaviors themselves.&lt;/p&gt;

&lt;p&gt;I began wondering whether the scripting runtime could manage these execution states instead of requiring every game system to do so independently.&lt;/p&gt;

&lt;p&gt;That was one of the motivations behind Mana's Action model.&lt;/p&gt;

&lt;h1&gt;
  
  
  A Request Is Not a Direct Execution
&lt;/h1&gt;

&lt;p&gt;In Mana, &lt;code&gt;request&lt;/code&gt; sends an action request to another Actor.&lt;/p&gt;

&lt;p&gt;It does not immediately execute the requested Action as an ordinary function call.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request(10, NPC-&amp;gt;talk());
print("continue\n");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The requesting Actor continues without waiting for the NPC's conversation to finish.&lt;/p&gt;

&lt;p&gt;The NPC manages the execution of its own actions.&lt;/p&gt;

&lt;p&gt;This separation was important to me.&lt;/p&gt;

&lt;p&gt;The requester should be able to express what it wants another Actor to do without managing exactly how that Actor executes the behavior.&lt;/p&gt;

&lt;p&gt;For example, an event controller should not need to know every detail of the NPC's current movement, conversation, or combat state.&lt;/p&gt;

&lt;p&gt;It can simply request an action.&lt;/p&gt;

&lt;p&gt;The runtime then determines when that action can execute, based on the target Actor's current state and priorities.&lt;/p&gt;

&lt;p&gt;This does not eliminate coordination problems, but it changes where those problems are handled.&lt;/p&gt;

&lt;h1&gt;
  
  
  Interrupting and Resuming Actions
&lt;/h1&gt;

&lt;p&gt;Mana associates a priority with each action request.&lt;/p&gt;

&lt;p&gt;A higher-priority request can interrupt a lower-priority Action.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Priority 1: patrol
        |
        | Priority 5 request arrives
        v
Priority 5: damage
        |
        | damage finishes
        v
Priority 1: patrol resumes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interrupted Action retains its execution state, allowing it to continue after the higher-priority Action finishes.&lt;/p&gt;

&lt;p&gt;The script does not need to explicitly jump back to the patrol behavior.&lt;/p&gt;

&lt;p&gt;The Request example in the Playground demonstrates this with a conversation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const int kTalk = 10;
const int kAlarm = 100;

actor Guard
{
    action talk()
    {
        print("Guard: Halt! Who goes there?\n");

        request(kAlarm, self-&amp;gt;alarm());

        print("Guard: False alarm. You may pass.\n");
    }

    action alarm()
    {
        print("Guard: (The bell rings!)\n");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The guard requests its own alarm action while executing &lt;code&gt;talk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because the alarm has a higher priority, it interrupts the conversation. Once the alarm finishes, the conversation resumes.&lt;/p&gt;

&lt;p&gt;If the alarm priority is changed to a value lower than the conversation priority, the execution order changes.&lt;/p&gt;

&lt;p&gt;The action code itself does not need to manage the interruption.&lt;/p&gt;

&lt;p&gt;That was the behavior I wanted from the runtime.&lt;/p&gt;

&lt;p&gt;However, once I implemented this model, new design problems started to appear.&lt;/p&gt;

&lt;h1&gt;
  
  
  Was Using Priorities as Execution Slots a Good Decision?
&lt;/h1&gt;

&lt;p&gt;One important limitation of Mana's current implementation is that &lt;strong&gt;each Actor can hold only one request at a given priority level.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, if an Actor already has an Action registered at priority &lt;code&gt;3&lt;/code&gt;, another request at priority &lt;code&gt;3&lt;/code&gt; will not be accepted.&lt;/p&gt;

&lt;p&gt;This is different from a conventional task queue.&lt;/p&gt;

&lt;p&gt;The reason is that Mana manages Action execution states by priority. Each priority effectively acts as an execution slot.&lt;/p&gt;

&lt;p&gt;This makes interruption and resumption relatively straightforward to manage.&lt;/p&gt;

&lt;p&gt;But it creates a restriction.&lt;/p&gt;

&lt;p&gt;Imagine several game events trying to start conversations with the same NPC.&lt;/p&gt;

&lt;p&gt;Should those requests be queued and processed in order?&lt;/p&gt;

&lt;p&gt;Should later requests be rejected?&lt;/p&gt;

&lt;p&gt;Should a newer request replace an older one?&lt;/p&gt;

&lt;p&gt;All of these behaviors could be useful, depending on the game.&lt;/p&gt;

&lt;p&gt;Allowing multiple requests at the same priority might seem like an obvious improvement. But then I would also need to decide how requests are ordered, cancelled, replaced, or discarded when they become irrelevant.&lt;/p&gt;

&lt;p&gt;What started as a simple priority system could gradually become a much more complicated scheduling system.&lt;/p&gt;

&lt;p&gt;I still haven't decided whether the current restriction is the right trade-off.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sometimes the Requester Needs to Wait
&lt;/h1&gt;

&lt;p&gt;Non-blocking requests are useful when Actors should operate independently.&lt;/p&gt;

&lt;p&gt;But game events often require a specific sequence.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Talk to the guard.&lt;/li&gt;
&lt;li&gt;Open the gate.&lt;/li&gt;
&lt;li&gt;Let the traveler enter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For this reason, Mana also provides &lt;code&gt;await&lt;/code&gt;, which sends a request and waits for the requested Action to complete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await(10, Guard-&amp;gt;talk());
await(10, Gate-&amp;gt;open());
request(10, Traveler-&amp;gt;enter());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The event waits for the guard's conversation before opening the gate.&lt;/p&gt;

&lt;p&gt;Once the gate has opened, it requests the traveler's entry without waiting for that action to finish.&lt;/p&gt;

&lt;p&gt;An important detail is that &lt;strong&gt;waiting suspends only the requesting Actor's execution, not the entire game.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Other Actors continue running.&lt;/p&gt;

&lt;p&gt;This allows sequential event scripts and independent character behaviors to coexist within the same execution model.&lt;/p&gt;

&lt;p&gt;It also introduces another distinction that becomes important later: requesting an action, waiting for it to begin, and waiting for it to complete are not necessarily the same operation.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Happens When a Request Is Rejected?
&lt;/h1&gt;

&lt;p&gt;This is one of the design problems I am still thinking about.&lt;/p&gt;

&lt;p&gt;In the current implementation, a request may be rejected for several reasons.&lt;/p&gt;

&lt;p&gt;The target Actor might be stopped. It might be configured to reject requests. The requested Action might not exist, or its priority slot might already be occupied.&lt;/p&gt;

&lt;p&gt;However, Mana's &lt;code&gt;request&lt;/code&gt; statement does not directly return a result indicating whether the request was accepted.&lt;/p&gt;

&lt;p&gt;That can be inconvenient.&lt;/p&gt;

&lt;p&gt;Suppose a character asks an NPC to begin a conversation, but the request is rejected. The requesting script may need to choose another action.&lt;/p&gt;

&lt;p&gt;How should it learn about the failure?&lt;/p&gt;

&lt;p&gt;One possibility is to return a result from &lt;code&gt;request&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But what exactly should that result represent?&lt;/p&gt;

&lt;p&gt;There are several distinct events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The request was accepted.&lt;/li&gt;
&lt;li&gt;The requested Action started executing.&lt;/li&gt;
&lt;li&gt;The Action completed successfully.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not equivalent.&lt;/p&gt;

&lt;p&gt;An accepted request may execute later. An Action may begin and then be interrupted. It may never reach normal completion.&lt;/p&gt;

&lt;p&gt;This becomes even more complicated if Actions are allowed to accept arguments or return values.&lt;/p&gt;

&lt;p&gt;With a regular function call, arguments and return values have relatively straightforward semantics.&lt;/p&gt;

&lt;p&gt;With a deferred, interruptible Action, questions arise about the lifetime of arguments, when a result becomes available, and what happens if execution never completes.&lt;/p&gt;

&lt;p&gt;Adding a return value to &lt;code&gt;request&lt;/code&gt; does not solve all of those problems.&lt;/p&gt;

&lt;p&gt;It may simply expose more of them.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Much Should the Language Handle?
&lt;/h1&gt;

&lt;p&gt;Looking back, I did not introduce &lt;code&gt;request&lt;/code&gt; because I believed function calls were unsuitable for games.&lt;/p&gt;

&lt;p&gt;I introduced it because I wanted the execution model to understand a particular kind of behavior:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An action can take time, be interrupted, preserve its state, and resume later.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By managing these behaviors in the runtime, I hoped to make gameplay scripts easier to write and reason about.&lt;/p&gt;

&lt;p&gt;In that sense, the design has achieved part of what I wanted.&lt;/p&gt;

&lt;p&gt;But every responsibility moved into the language becomes another responsibility of the language designer.&lt;/p&gt;

&lt;p&gt;Supporting priorities raises questions about queues and scheduling.&lt;/p&gt;

&lt;p&gt;Supporting non-blocking requests raises questions about completion and failure.&lt;/p&gt;

&lt;p&gt;Supporting Actions with arguments or return values raises questions about data lifetime and synchronization.&lt;/p&gt;

&lt;p&gt;The more the language handles automatically, the more complicated its semantics can become.&lt;/p&gt;

&lt;p&gt;This has been one of the recurring difficulties throughout Mana's development:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Making the user's code simpler often means making the language itself more complicated.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I don't think there is a universal answer to where that balance should be.&lt;/p&gt;

&lt;p&gt;It depends on what problems the language is intended to solve, and which problems should remain the responsibility of the application.&lt;/p&gt;

&lt;p&gt;For Mana, that boundary is still evolving.&lt;/p&gt;

&lt;p&gt;I have reached version 1.0, but that doesn't mean every design question has been settled.&lt;/p&gt;

&lt;p&gt;There are still decisions to make about the relationship between Actions and ordinary functions, how much of game AI behavior the runtime should manage, and how responsibilities should be divided between C++ and scripts.&lt;/p&gt;

&lt;p&gt;Those unresolved questions are part of what I want to document in this series.&lt;/p&gt;

&lt;p&gt;I would also be interested in how other language and game-engine developers approach this problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should a scripting language manage the lifecycle of gameplay actions, or is that responsibility better left to the game engine and its task system?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's a question I am still trying to answer.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>gamedev</category>
      <category>programminglanguages</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
