Advertisement
Guest User

Behavior Designer - ProbabilitySelector

a guest
Oct 11th, 2018
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.31 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEngine;
  4. using BehaviorDesigner.Runtime.Tasks;
  5.  
  6. [TaskDescription("Runs its children in a random order, weighted by probability. Returns success as soon as a child returns success.")]
  7. [TaskIcon("{SkinColor}RandomSelectorIcon.png")]
  8. public class ProbabilitySelector : Composite {
  9.     [BehaviorDesigner.Runtime.Tasks.Tooltip("The probability of each child task being selected. Values are relative to each other, e.g: 0.5/20 have twice the chance of 0.25/10 of occuring.")]
  10.     public float[] ChildTaskProbabilities;
  11.  
  12.     /// <summary>Tasks that have not been executed.</summary>
  13.     readonly List<TaskProbability> _availableTasks = new List<TaskProbability>();
  14.     /// <summary>Executed tasks to be reused later.</summary>
  15.     readonly List<TaskProbability> _executedTasks = new List<TaskProbability>();
  16.  
  17.     int _currentAvailableTasksIndex = 0;
  18.     int _currentChildIndex = 0;
  19.     TaskStatus _lastChildExecutionStatus = TaskStatus.Inactive;
  20.  
  21.     public override void OnAwake() {
  22.         if (ChildTaskProbabilities.Length != Children.Count) { Debug.LogErrorFormat("Incorrect amount of ChildTaskProbabilities in ProbabilitySelector. (ChildTaskProbabilities: {0}, Child Tasks: {1})", ChildTaskProbabilities.Length, Children.Count); }
  23.  
  24.         for (int i = 0; i < ChildTaskProbabilities.Length && i < Children.Count; i++) { _availableTasks.Add(new TaskProbability(i)); }
  25.     }
  26.  
  27.     public override void OnStart() {
  28.         // Transfer any previously completed tasks to _availableTasks
  29.         _availableTasks.AddRange(_executedTasks);
  30.         _executedTasks.Clear();
  31.  
  32.         UpdateTaskProbabilities();
  33.  
  34.         UpdateCurrentTaskIndex();
  35.     }
  36.  
  37.     void UpdateTaskProbabilities() {
  38.         float total = 0;
  39.         float currentValue = 0;
  40.  
  41.         foreach (TaskProbability task in _availableTasks) { total += ChildTaskProbabilities[task.Index]; }
  42.         foreach (TaskProbability task in _availableTasks) {
  43.             currentValue += ChildTaskProbabilities[task.Index] / total;
  44.             task.ProbabilityValue = currentValue;
  45.         }
  46.     }
  47.  
  48.     void UpdateCurrentTaskIndex() {
  49.         float value = Random.value;
  50.  
  51.         for (int i = 0; i < _availableTasks.Count; i++) {
  52.             TaskProbability task = _availableTasks[i];
  53.  
  54.             // If this isn't the last available task, test to see if the value is in its probability range
  55.             if (i < _availableTasks.Count - 1 && value > task.ProbabilityValue) { continue; }
  56.  
  57.             _currentAvailableTasksIndex = i;
  58.             _currentChildIndex = task.Index;
  59.  
  60.             break;
  61.         }
  62.     }
  63.  
  64.     public override int CurrentChildIndex() {
  65.         return _currentChildIndex;
  66.     }
  67.  
  68.     public override bool CanExecute() {
  69.         // Continue execution if there are still available tasks and no task has returned success
  70.         return _availableTasks.Count > 0 && _lastChildExecutionStatus != TaskStatus.Success;
  71.     }
  72.  
  73.     public override void OnChildExecuted(TaskStatus childStatus) {
  74.         if (_availableTasks.Count > 0) {
  75.             // Transfer executed task to _executedTasks
  76.             _executedTasks.Add(_availableTasks[_currentAvailableTasksIndex]);
  77.             _availableTasks.RemoveAt(_currentAvailableTasksIndex);
  78.  
  79.             // If there are still available tasks, select the next task
  80.             if (_availableTasks.Count > 0) {
  81.                 UpdateTaskProbabilities();
  82.  
  83.                 UpdateCurrentTaskIndex();
  84.             }
  85.         }
  86.  
  87.         _lastChildExecutionStatus = childStatus;
  88.     }
  89.  
  90.     public override void OnConditionalAbort(int childIndex) {
  91.         _lastChildExecutionStatus = TaskStatus.Inactive;
  92.     }
  93.  
  94.     public override void OnEnd() {
  95.         _lastChildExecutionStatus = TaskStatus.Inactive;
  96.     }
  97.  
  98.     class TaskProbability {
  99.         /// <summary>The index of this task in <see cref="ProbabilitySelector.ChildTaskProbabilities"/></summary>
  100.         public readonly int Index;
  101.         /// <summary>The maximum normalised value at which this task will be executed. (Provided the random value is also greater than the <see cref="ProbabilityValue"/>s of any preceding tasks in <see cref="_availableTasks"/>.)</summary>
  102.         public float ProbabilityValue;
  103.  
  104.         public TaskProbability(int index) {
  105.             Index = index;
  106.         }
  107.     }
  108. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement