1
\$\begingroup\$

I am designing a game in Unity which has NPCs (Non-player controllers). I have worked out the path-finding but I need some help with how to implement tasks. I need the task system to be flexible and allow me to easily add new tasks. I also want to be able to have a task trigger another task.

Example for turning light on:

  • When mouse clicked on light switch
  • Wait for available/idle NPC
  • NPC walks to light switch (Using a walkToPostion(pos) task)
  • Light turns on
  • NPC is set to available/idle and can perform another task

Another example could be emptying the trash can:

  • When trash can is full
  • Wait for an available NPC
  • NPC walks to trash can (Using a walkToPostion(pos) task)
  • Trash can is set to empty
  • NPC takes garbage bag outside (Using a walkToPostion(pos) task)
  • NPC walks back into house/given position. (Using a walkToPostion(pos) task)
  • NPC waits to be given next task.

I haven't done a lot with AI before so some hits on how I could go about implements this would be very helpful.

EDIT: One thing I specifically need help with is performing a task inside a task. How do I pause the TurnOnLight task while the player is doing to WalkToPos task?

\$\endgroup\$
  • \$\begingroup\$ As your question is currently written it is impossible to tell what kind of help you actually need. Can you please describe your concrete problems with implementing your plan? \$\endgroup\$ – Philipp Mar 11 '15 at 9:11
  • \$\begingroup\$ @Philipp I am not really sure how I can better describe my problem. I just don't really know where to get started. \$\endgroup\$ – Aces_Charles Mar 11 '15 at 9:26
  • \$\begingroup\$ Questions about "how to get started" are off-topic. \$\endgroup\$ – zenith Mar 11 '15 at 9:55
  • 1
    \$\begingroup\$ @Aces_Charles Not knowing how to get started is usually a symptom of a) not yet knowing enough about the technology to be ready for even attempting a task of this complexity level or b) not having thought enough about how to break the problem down into manageable sub-problems which you could either solve yourself or could ask concrete problems about. \$\endgroup\$ – Philipp Mar 11 '15 at 10:23
  • \$\begingroup\$ This may be of use to you... It's call goal oriented action planning... It may be a little complex but check it out gamedevelopment.tutsplus.com/tutorials/… \$\endgroup\$ – Savlon Mar 11 '15 at 11:14
3
\$\begingroup\$

A design pattern I've enjoyed using has two types of things: task management and task execution. Task management asks the question "What should I be doing right now?" And task execution asks, "How do I complete the current task?"

Task Managers

The job of the task manager is to constantly look at the AI's internal state (read-only) to determine whether new tasks should be assigned. Tasks have priorities, and are placed on a Priority Queue when assigned. Tasks are also unique, so that an agent can't be assigned exactly the same task twice.

For instance, the Task Manager could constantly be checking to see if the agent has sensed any new enemies that must be attacked. If enemies are sensed, it adds high-priority DestroyThreat tasks to the task queue.

When the agent is done with the current task, it pops another one off the task queue. Task managers can also pre-empt the current task by putting it back on the queue if an extremely high priority task overrides the current task.

Task Executors

Your agent will have several actions which are merely functions, bits of behavior tree, or states in a state machine. Every action can either fail, or succeed. These are implemented inside the AI agent itself. They should be atomic (like "play animation" or "attack entity").

The task executor will simply tell the AI agent what actions to take given a current task. It does not need to directly know about the agent's state, but only the return values of the actions the agent takes. The executor can either fail the task, or succeed, based on whether the current action fails or succeeds. If the task fails, it is either put back on the task queue or is destroyed, depending on the desired behavior.

\$\endgroup\$
3
\$\begingroup\$

The best way I can think of to do this is to have an empty object with a TaskController script. Assuming the NPCs have their own scripts, and you can call a function in their script to have them handle a task, your logic would flow like:

  1. Player clicks on light switch
  2. Light switch script calls CreateTask(TaskName, Index) on your TaskController empty's script, where TaskName = "TurnOnLight" and Index = 1 (light switch # 1 in your scene, if it has multiple switches)
  3. TaskController creates a new task (likely a class object with parameters like TaskIndex, TaskName, TargetIndex, Assignee, and Completed)
  4. TaskController finds the nearest Idle NPC and sends the task to them via function, then adds them to the Assignee field and sets Completed to false. (This also allows idle NPCs to periodically check the TaskController for unassigned, incomplete tasks)
  5. NPC can now execute its WalkTo function and head for the light switch. TaskController will know not to assign the task to someone else because its Assignee slot is not blank.
  6. When the NPC reaches its destination, it can re-check with the TaskController to make sure its task is still not Completed, then perform the task (flip on light if off else flip off).
  7. Once the NPC performs the task, it can tell the TaskController to mark the task as Completed and set itself to idle and wander off for a beer.

Let me know if you need more detail.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.