游戲AI設(shè)計(jì)中,常用的方法有有限狀態(tài)機(jī)
甜奄,行為樹
等柠横,最基本的也就是狀態(tài)機(jī)了,下面用一個(gè)實(shí)例來記錄下有限狀態(tài)機(jī)的實(shí)現(xiàn)课兄。
1牍氛,設(shè)計(jì)有限狀態(tài)機(jī)
首先需要為游戲AI設(shè)計(jì)出合理的狀態(tài)圖,并且確定各個(gè)狀態(tài)的轉(zhuǎn)換條件烟阐。下面設(shè)計(jì)一個(gè)簡單的有限狀態(tài)機(jī)搬俊。
狀態(tài):
- 巡邏
- 攻擊
- 躲避
狀態(tài)轉(zhuǎn)換條件
- 敵人距離AI的距離
-
血量
2,代碼實(shí)現(xiàn)
設(shè)計(jì)模式--狀態(tài)模式
context
類蜒茄,狀態(tài)機(jī)的一些初始化唉擂,以及切換狀態(tài)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets
{
class Context
{
public Data data;
public Ai ai;
/// <summary>
/// 當(dāng)前狀態(tài)
/// </summary>
Status status;
/// <summary>
/// 構(gòu)造,默認(rèn)巡邏狀態(tài)
/// </summary>
public Context(Ai _ai)
{
ai = _ai;
status = new FindStatus();
}
/// <summary>
/// 改變狀態(tài)
/// </summary>
/// <param name="_status"></param>
public void ChangeStatus(Status _status)
{
Debug.Log("血量:" + data.Hp + "距離player:" + data.DistanceAiToPlayer);
status = _status;
}
/// <summary>
/// 執(zhí)行動(dòng)作
/// </summary>
public void DoAction(Data _data)
{
data = _data;
status.Action(this);
}
}
}
Status
狀態(tài)接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Assets
{
interface Status
{
void Action(Context context);
}
}
FindSatus
具體狀態(tài)檀葛,巡邏狀態(tài)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets
{
class FindStatus : Status
{
public FindStatus()
{
Debug.Log("進(jìn)入巡邏模式");
}
public const float MaxDistance = 5;
public const float MaxRange = 5;
public void Action(Context context)
{
context.ai.RecoveryHp();
if(context.data.DistanceAiToPlayer < MaxDistance)
{
context.ChangeStatus(new AttackStatus());
}
else
{
context.ai.StopMove();
}
}
}
}
AvoidStatus
具體狀態(tài)玩祟,躲避狀態(tài)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets
{
class AvoidStatus : Status
{
public AvoidStatus()
{
Debug.Log("進(jìn)入躲避模式");
}
public const float MinHp = 10;
public void Action(Context context)
{
context.ai.FarAwayPlayer();
if(context.data.DistanceAiToPlayer > FindStatus.MaxDistance)
{
context.ChangeStatus(new FindStatus());
}
}
}
}
AttackStatus
具體狀態(tài),攻擊狀態(tài)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets
{
class AttackStatus : Status
{
public AttackStatus()
{
Debug.Log("進(jìn)入攻擊模式");
}
public void Action(Context context)
{
context.ai.MoveToPlayer();
context.ai.BeAttack();
if(context.data.Hp < AvoidStatus.MinHp)
{
context.ChangeStatus(new AvoidStatus());
}else if(context.data.Hp > AvoidStatus.MinHp && context.data.DistanceAiToPlayer > FindStatus.MaxDistance)
{
context.ChangeStatus(new FindStatus());
}
}
}
}
player
控制腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class player : MonoBehaviour {
Rigidbody rigidbody;
// Use this for initialization
void Start () {
rigidbody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
rigidbody.AddForce(new Vector3(x, 0, z).normalized * 2);
}
}
游戲AI
控制腳本
using Assets;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ai : MonoBehaviour {
public GameObject player;
float Hp = 20;
Rigidbody rigidbody;
Context context;
// Use this for initialization
void Start () {
context = new Context(this);
rigidbody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
context.DoAction(GetData());
}
/// <summary>
/// 獲取各種條件
/// </summary>
/// <returns></returns>
Data GetData()
{
Data data = new Data();
data.DistanceAiToPlayer = Vector3.Distance(transform.position, player.transform.position);
data.Hp = Hp;
return data;
}
public void MoveToPlayer()
{
rigidbody.AddForce((player.transform.position - transform.position).normalized);
}
public void StopMove()
{
rigidbody.AddForce(-rigidbody.velocity);
}
public void BeAttack()
{
Hp -= 0.01f;
}
public void FarAwayPlayer()
{
rigidbody.AddForce(-(player.transform.position - transform.position).normalized*2);
}
public void RecoveryHp()
{
if(Hp < 20)
{
Hp += 0.1f;
}
}
}
Data
條件數(shù)據(jù)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets
{
class Data
{
public float DistanceAiToPlayer;
public float Hp;
}
}
代碼中為了便于測(cè)試屿聋,ai在攻擊下會(huì)直接減Hp卵凑,每一幀減少0.01庆聘,躲避和巡邏狀態(tài)會(huì)增加Hp,每一幀增加0.1勺卢。
運(yùn)行結(jié)果
視頻轉(zhuǎn)gif效果不是很好
小球是玩家控制的,大球是游戲AI