blob: 86bb841e635ad5c93cd3dc6a86b64cd4597e77bc (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("The task guard task is similar to a semaphore in multithreaded programming. The task guard task is there to ensure a limited resource is not being overused. " +
"\n\nFor example, you may place a task guard above a task that plays an animation. Elsewhere within your behavior tree you may also have another task that plays a different " +
"animation but uses the same bones for that animation. Because of this you don't want that animation to play twice at the same time. Placing a task guard will let you " +
"specify how many times a particular task can be accessed at the same time.\n\nIn the previous animation task example you would specify an access count of 1. With this setup " +
"the animation task can be only controlled by one task at a time. If the first task is playing the animation and a second task wants to control the animation as well, it will " +
"either have to wait or skip over the task completely.")]
[HelpURL("http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=40")]
[TaskIcon("{SkinColor}TaskGuardIcon.png")]
public class TaskGuard : Decorator
{
[Tooltip("The number of times the child tasks can be accessed by parallel tasks at once")]
public SharedInt maxTaskAccessCount;
[Tooltip("The linked tasks that also guard a task. If the task guard is not linked against any other tasks it doesn't have much purpose. Marked as LinkedTask to " +
"ensure all tasks linked are linked to the same set of tasks")]
[LinkedTask]
public TaskGuard[] linkedTaskGuards = null;
[Tooltip("If true the task will wait until the child task is available. If false then any unavailable child tasks will be skipped over")]
public SharedBool waitUntilTaskAvailable;
// The number of tasks that are currently using a particular task.
private int executingTasks = 0;
// True if the current task is executing.
private bool executing = false;
public override bool CanExecute()
{
// The child task can execute if the number of executing tasks is less than the maximum number of tasks allowed.
return executingTasks < maxTaskAccessCount.Value && !executing;
}
public override void OnChildStarted()
{
// The child task has started to run. Increase the executing tasks counter and notify all of the other linked tasks.
executingTasks++;
executing = true;
for (int i = 0; i < linkedTaskGuards.Length; ++i) {
linkedTaskGuards[i].taskExecuting(true);
}
}
public override TaskStatus OverrideStatus(TaskStatus status)
{
// return a running status if the children are currently waiting for a task to become available
return (!executing && waitUntilTaskAvailable.Value) ? TaskStatus.Running : status;
}
public void taskExecuting(bool increase)
{
// A linked task is currently executing a task that is being guarded. If the task just started executing then increase will be true and if it is ending then
// true will be false.
executingTasks += (increase ? 1 : -1);
}
public override void OnEnd()
{
// The child task has been executed or skipped over. Only decrement the executing tasks count if the child task was being executed. Following that
// notify all of the linked tasks that we are done executing.
if (executing) {
executingTasks--;
for (int i = 0; i < linkedTaskGuards.Length; ++i) {
linkedTaskGuards[i].taskExecuting(false);
}
executing = false;
}
}
public override void OnReset()
{
// Reset the public properties back to their original values
maxTaskAccessCount = null;
linkedTaskGuards = null;
waitUntilTaskAvailable = true;
}
}
}
|