Routine Check


Programming


Hello Universe!

Was working on the scheduling system... again

I feel like I'll be working on the scheduling system constantly throughout the entire duration of the project.
The way it usually works is:

  1. I try to program an idea.
  2. Go away and think about it (best ideas/solutions happen in the shower or before I sleep), sometimes over a couple of days/weeks/months.
  3. Come back and program those ideas in.
  4. Have no bugs if I'm super super lucky.
  5. Repeat for Days/Weeks/Months.

And do this until I'm extremely satisfied with a bug free, perfect child, because I'm a perfectionist to a degree and possibly OCD for ideas.
But, I digress. So far here is where I am at with my "scheduling" system. Keep in mind, the names of things may seem strange. I, too, find the things I have named strange and may change in the future. Starting from the outer layer.

Schedules

Upon loading a scene, a schedule file is loaded in. Every existing NPC/entity that has some sort of schedule will exist here. Each schedule is on a day by day basis. New day, new schedule.

In each schedule of each NPC exists a set of quests. Described by the name of the quest, and the file in which to find said quest. I don't think it necessary anymore to have quests described in another file, as the chance of the same quest being used by multiple NPCs is rare. But It's there, I will leave it. It may provide useful later on. If I need a hard-drive/CPU boost on load times, perhaps I'll get rid of it.

<Root>
  <routine name="auto/1" file="shrine.routines" />
  <schedule>
    <entity name="bench" parent="MG">
      <quests>
        <quest name="bench_sit" file="shrine.quests"/>
      </quests>
      <components>
        <TransformComponent x="586" y="64" z="15"/>
        <SpriteComponent>
          <material name="sprite.material">
            <samplers>
              <texture0 name="bench.it" />
            </samplers>
          </material>
        </SpriteComponent>
      </components>
    </entity>
    <entity name="clouds" parent="BG">
      <quests>
        <quest name="clouds" file="shrine.quests" />
      </quests>
      <components>
        <TransformComponent y="300" z="6"/>
      </components>
    </entity>
  </schedule>
</Root>

Quests

These are the high level containers for each routine. Think of quests as a big task and the routines as little tasks to get the big task done. Example: The quest of go shopping and the routines may be: walk to shops, get groceries, walk back home. Three routines to complete a wider objective.

Each quest is described by a name(as referenced in the schedule file), a start-time, an expiration time, and a priority number. The time's are written in 24 hour clock time for ease of designing. Hopefully these attributes are easy enough to interpret, except, the priority number: is used to determine which quests are more important to run than others. Useful for when quests start changing by the game.

Inside each quest are what I call "event routine types". Explained further down in the Routines section. Enclosed are the actual routines. Which, have a name of the routine, the file in which they exist, and a starting offset(from the quest starting time), and a resume type. Now, the latter is used for when another "activated event" finishes and the auto routines resume. For Example: If an NPC is operating a shop and the player talks to them. After the talking has finished does the NPC resume his last task? Does they skip it and move on to mopping? Do they restart what they were doing?

What happens if the NPC was mopping when the "activated event" was initiated, and they move over to the counter. When the "activated event" finishes, If the NPC resumes "mopping", the NPC will start "mopping" behind the counter. But, because the "play animation node" has passed, the NPC will just stand there doing nothing. But if we set the resume type to "restart", the routine will restart and rerun the set position node, the set animation node, etc.

<Root>
  <quest name="bench_sit" start-time="0000">
    <activate-routines>
      <routine name="activate/bench_sit" file="shrine.routines" offset="0" resume-type="resume"/>
    </activate-routines>
  </quest>
  <quest name="clouds" start-time="0300" expiration="1830">
    <auto-routines>
      <routine name="auto/clouds" file="shrine.routines" offset="0"/>
    </auto-routines>
  </quest>
</Root>

Routines

These are the tiny little tasks that make up the big quest.
Auto routines are the stock standard ones that occur as time goes on, automatically. Any other event happen upon some kind of interaction. Example: Active routines may be run upon hitting the action key in proximity of the entity.

The routine file is divided up by events. I.E. Auto, Activate, etc. Inside you will find the routines, explained with only a name and enclosed inside are the nodes that operate in sequence one after another.
OR
The nodes are enclosed inside phases which I figured may be helpful in handling loops, and resuming back into the "auto event". They may have an expiration time to help with this.

<Root>
  <auto>
    <routine name="clouds">
      <phase>
        <SpawnChildren stencil="cloud_stencil.xml" num-children="10"/>
      </phase>
      <phase expiration="840">
        <bundle>
          <ChildrenTreadmill width="2800" y-offset="120" direction="-1" min-speed="0.04" max-speed="0.1" min-spawn-rate="5" max-spawn-rate="20" spawn-count="0"/>
          <FadeAlpha entity="clouds_0" duration="60" reverse="false" />
        </bundle>
      </phase>
      <phase>
        <FadeAlpha entity="clouds_0" duration="60" reverse="true" />
        <Destroy />
      </phase>
    </routine>
  </auto>
  <activate>
    <routine name="bench_sit">
      <SitStand entity="protagonist" sit-animation="protagonist_idle" />
    </routine>
  </activate>
</Root>

Bundles

The latest thing I was working on was parallel nodes. Let's say I have a fade node that over time fades in the alpha of a sprite. Now let's that this entity also moves across the screen. The current system would run as: Fade in, then move across the screen, or vice versa. That will not do. So I programmed in these bundle things (Name not final, maybe). Now, All the nodes inside a bundle all update together and wait for the other nodes to finish, before moving onto the next bundle.

Here is a demonstration of clouds moving across the screen and fading in, at the same TIME!

I've basically programmed an onion. Layers upon layers upon layers...

I hope that a post like this helps developers out there. I know how hard and fustrating it is to find learning material on npcs and routine systems. <3

Leave a comment

Log in with itch.io to leave a comment.