AI决策算法之GOAP(三)

发表于2018-02-26
评论1 2.3k浏览
上篇给大家分别介绍了 IGoal,Agent,Action,Planer,FSM的实现,这篇我们就用上篇文章写的GOAP框架来完成一个实例:

实例内容:
(1)AI有10HP, 需要去站岗,站岗完成扣5HP
(2)当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;  
    }  
}  

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引