源码地址:http://pan.baidu.com/s/1dFwzmfB
这篇我们使用上篇文章写的GOAP框架来完成一个实例:
实例内容:
AI有10HP, 需要去站岗,站岗完成扣5HP
当HP<=5必须去补充HP,找到HP球补充HP,每个HP球补充5HP
根据GOAP框架逻辑推断出需要:AI数据提供者,站岗Action,补充HPAction,HP点脚本,站岗点脚本, AI属性脚本
主要脚本:
AI数据提供者
public class Worker : MonoBehaviour,IGoap{
private PropertyComponent property; //属性脚本
public float moveSpeed = 3; //移动速度
void Start()
{
property = GetComponent<PropertyComponent>();
}
public System.Collections.Generic.HashSet<System.Collections.Generic.KeyValuePair<string, object>> GetState()
{
HashSet<KeyValuePair<string, object>> state = new HashSet<KeyValuePair<string, object>>();
//当前状态HP是否足够
state.Add(new KeyValuePair<string, object>("EnoughHP", property.HP > 5));
return state;
}
public System.Collections.Generic.HashSet<System.Collections.Generic.KeyValuePair<string, object>> CreateGoalState()
{
HashSet<KeyValuePair<string, object>> goal = new HashSet<KeyValuePair<string, object>>();
//站岗完成目标
goal.Add(new KeyValuePair<string, object>("SentryComplete", true));
return goal;
}
public void PlanFailed(System.Collections.Generic.HashSet<System.Collections.Generic.KeyValuePair<string, object>> failedGoal)
{
}
public void PlanFound(System.Collections.Generic.HashSet<System.Collections.Generic.KeyValuePair<string, object>> goal, System.Collections.Generic.Queue<Action> actions)
{
}
public void ActionsFinished()
{
Debug.LogError("FinishedSentry");
}
public void PlanAborted(Action aborterAction)
{
}
public bool MoveAgent(Action tagetAction)
{
//移动
float step = moveSpeed * Time.deltaTime;
gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, tagetAction.target.transform.position, step);
if (gameObject.transform.position.Equals(tagetAction.target.transform.position))
{
tagetAction.IsInRange = true;
return true;
}
else
return false;
}
}
站岗Action
public class SentryAction : Action {
private SentryComponent targetSentry; //站岗目标脚本
private float SentryTimer = 0; //站岗计时
public float SentryTime = 3;
bool isDone = false; //是否完成
public SentryAction()
{
AddPrecondition("EnoughHP", true); //前置条件:必须HP足够
AddEffect("SentryComplete", true); //完成效果:站岗完成
}
public override void Reset()
{
targetSentry = null;
SentryTimer = 0;
isDone = false;
}
public override bool IsDone()
{
return isDone;
}
public override bool CheckProcedualPrecondition(GameObject agent)
{
//得到最近的站岗目标
SentryComponent[] sentryComponents = GameObject.FindObjectsOfType<SentryComponent>();
SentryComponent temp = null;
foreach(var v in sentryComponents)
{
if (temp == null)
{
temp = v;
continue;
}
if (Vector3.Distance(agent.transform.position, v.transform.position) < Vector3.Distance(agent.transform.position, temp.transform.position))
temp = v;
}
targetSentry = temp;
target = temp.gameObject;
return temp != null;
}
public override bool Perform(GameObject agent)
{
//站岗执行
SentryTimer += Time.deltaTime;
if(SentryTimer > SentryTime)
{
//站岗完成消耗HP
agent.GetComponent<PropertyComponent>().HP -= 5;
isDone = true;
}
return true;
}
public override bool RequiresInRange()
{
return true;
}
}
补充HPAction
public class GetHPAction : Action {
private HPPointComponent targetHPPoint; //HP点目标脚本
bool isDone = false;
void Start()
{
AddEffect("EnoughHP", true); //完成效果:HP补充到足够
}
public override void Reset()
{
targetHPPoint = null;
isDone = false;
}
public override bool IsDone()
{
return isDone;
}
public override bool CheckProcedualPrecondition(GameObject agent)
{
HPPointComponent[] tempComponents = GameObject.FindObjectsOfType<HPPointComponent>();
HPPointComponent temp = null;
foreach (var v in tempComponents)
{
if (temp == null)
{
temp = v;
continue;
}
if (Vector3.Distance(agent.transform.position, v.transform.position) < Vector3.Distance(agent.transform.position, temp.transform.position))
temp = v;
}
targetHPPoint = temp;
target = temp.gameObject;
return temp != null;
}
public override bool Perform(GameObject agent)
{
DestroyImmediate(targetHPPoint.gameObject);
isDone = true;
agent.GetComponent<PropertyComponent>().HP += 5;
return true;
}
public override bool RequiresInRange()
{
return true;
}
}