游戏AI设计中,常用的方法有有限状态机
,行为树
等,最基本的也就是状态机了,下面用一个实例来记录下有限状态机的实现。
1,设计有限状态机
首先需要为游戏AI设计出合理的状态图,并且确定各个状态的转换条件。下面设计一个简单的有限状态机。
状态:
- 巡逻
- 攻击
- 躲避
状态转换条件
- 敌人距离AI的距离
-
血量
图片.png
2,代码实现
设计模式--状态模式
状态模式.pngcontext
类,状态机的一些初始化,以及切换状态
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>
/// 当前状态
/// </summary>
Status status;
/// <summary>
/// 构造,默认巡逻状态
/// </summary>
public Context(Ai _ai)
{
ai = _ai;
status = new FindStatus();
}
/// <summary>
/// 改变状态
/// </summary>
/// <param name="_status"></param>
public void ChangeStatus(Status _status)
{
Debug.Log("血量:" + data.Hp + "距离player:" + data.DistanceAiToPlayer);
status = _status;
}
/// <summary>
/// 执行动作
/// </summary>
public void DoAction(Data _data)
{
data = _data;
status.Action(this);
}
}
}
Status
状态接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Assets
{
interface Status
{
void Action(Context context);
}
}
FindSatus
具体状态,巡逻状态
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets
{
class FindStatus : Status
{
public FindStatus()
{
Debug.Log("进入巡逻模式");
}
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
具体状态,躲避状态
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets
{
class AvoidStatus : Status
{
public AvoidStatus()
{
Debug.Log("进入躲避模式");
}
public const float MinHp = 10;
public void Action(Context context)
{
context.ai.FarAwayPlayer();
if(context.data.DistanceAiToPlayer > FindStatus.MaxDistance)
{
context.ChangeStatus(new FindStatus());
}
}
}
}
AttackStatus
具体状态,攻击状态
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets
{
class AttackStatus : Status
{
public AttackStatus()
{
Debug.Log("进入攻击模式");
}
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
条件数据
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets
{
class Data
{
public float DistanceAiToPlayer;
public float Hp;
}
}
代码中为了便于测试,ai在攻击下会直接减Hp,每一帧减少0.01,躲避和巡逻状态会增加Hp,每一帧增加0.1。
运行结果
运行情况.png
视频转gif效果不是很好
小球是玩家控制的,大球是游戏AI
运行截图.gif
网友评论