前情提要
今天在用BehaviorDesigner插件时遇到了一个问题
我想要通过一个自定义的概率来执行子节点,但是由于本人对这个插件不是很了解,所以只知道插件自带有一个RandomSelector节点,这个节点是以相同的概率选择一个子节点执行,所以为了实现需求,我参照这个节点的脚本写了一个可以自定义每个子节点选择概率的脚本。
代码
using UnityEngine;
using System.Collections.Generic;
using System;
namespace BehaviorDesigner.Runtime.Tasks
{
[TaskDescription("改写自RandomSelector脚本,将根据概率随机选择执行一次子节点")]
[TaskIcon("{SkinColor}RandomSelectorIcon.png")]
public class RandomSelectorByNums : Composite
{
[Tooltip("Seed the random number generator to make things easier to debug")]
public int seed = 0;
[Tooltip("Do we want to use the seed?")]
public bool useSeed = false;
[Tooltip("子节点概率队列,对应从左至右每个节点被选中的概率")]
public List<int> Probabilities = new List<int>();
// 每个子任务的索引列表。此列表由 Fischer-Yates shuffle 算法使用。
private List<int> childIndexList = new List<int>();
//最后一个子项的任务状态。
private TaskStatus executionStatus = TaskStatus.Inactive;
private int total;//总概率
private int target;//本次执行所击中的子节点
public override void OnAwake()
{
// If specified, use the seed provided.
if (useSeed) {
UnityEngine.Random.InitState(seed);
}
// Add the index of each child to a list to make the Fischer-Yates shuffle possible.
childIndexList.Clear();
for (int i = 0; i < children.Count; ++i) {
childIndexList.Add(i);
}
if(Probabilities.Count<childIndexList.Count)
{
throw new Exception("概率列表数量少于子节点数量");
}
//将概率列表长度与子节点数量所匹配
for (int i = Probabilities.Count - 1; i >= childIndexList.Count; i--)
{
Probabilities.RemoveAt(i);
}
//总概率
foreach (var item in Probabilities)
{
total += item;
}
}
public override void OnStart()
{
target=GetTargetByRandom();
//Debug.LogError("--------------------"+target);
}
private int GetTargetByRandom()
{
int thisHit = UnityEngine.Random.Range(0, total);
int rangemin = 0;
int rangemax = 0;
for (int i = 0; i < childIndexList.Count; i++)
{
rangemin = rangemax;
rangemax += Probabilities[i];
if (thisHit >= rangemin && thisHit < rangemax)
{
return i;
}
}
return -1;//标记出错
}
public override int CurrentChildIndex()
{
// Peek will return the index at the top of the stack.
//return childrenExecutionOrder.Peek();
//return childIndexList[target];
return target;
}
public override bool CanExecute()
{
// 是否能够继续执行&&该次目标是否执行完毕
return !(executionStatus == TaskStatus.Success);
}
public override void OnChildExecuted(TaskStatus childStatus)
{
// 目标子节点执行后的状态
executionStatus = childStatus;
}
public override void OnConditionalAbort(int childIndex)
{
// 从终止状态开始
executionStatus = TaskStatus.Inactive;
target = GetTargetByRandom();
}
public override void OnEnd()
{
// All of the children have run. Reset the variables back to their starting values.
executionStatus = TaskStatus.Inactive;
//childrenExecutionOrder.Clear();
}
public override void OnReset()
{
// Reset the public properties back to their original values
seed = 0;
useSeed = false;
}
}
}
使用
面板中选择使用
属性栏中有一个列表,这个列表存放着从左到右每个子节点的选择概率。
如1号子节点的选择概率对应Probabilities[0],也就是5/(列表每个数之和=5+5+5+5+80)
本人是Unity新手,只能想到这种方法,如果有更好的办法欢迎大家告诉我!