大家好,我是Zander,我们接着来开发Rts3D即时战略游戏开发。这节课我们开讲AI的相关部分。在游戏中,游戏AI有行为树,决策树、状态机等可选。我们将使用基本的等待队列,AI的每次决策都会返回一个权重,然后根据这个值来执行相应功能,这里只需要考虑两件事,是否值得做,怎么做。
首先,在Scripts文件夹下创建一个新的文件夹AI,并创建两个脚本,AiBehaviour AiController,分别编辑
using UnityEngine;
using System.Collections;
public abstract class AiBehavior : MonoBehaviour {
public float WeightMultiplier = 1; //可以让设计者设定数值对AI的影响
public float TimePassed = 0;
public abstract float GetWeight(); //表示Ai重要度的值,假如有两个AI,建造AI想创建一个指挥部,攻击AI想寻路到敌方,也会坚持有无敌人要攻击,然后根据权重值,来判断优先执行那个AI
public abstract void Execute(); //执行决策的方法
}
using UnityEngine;
using System.Collections.Generic;
public class AiController : MonoBehaviour {
public float Confusion = 0.3f; // 添加在AI权重上的随机值
public float Frequency = 1; //我们检测的频率
private float waited = 0; //两次决策间隔时间的花费
private List<AiBehavior> Ais = new List<AiBehavior>();
// Use this for initialization
void Start () {
foreach (var ai in GetComponents<AiBehavior>())
Ais.Add (ai);
}
// Update is called once per frame
void Update () {
waited += Time.deltaTime;
if (waited < Frequency) //间隔时间判断
return;
float bestAiValue = float.MinValue;
AiBehavior bestAi = null;
foreach (var ai in Ais) //判断哪个是需要最先执行的AI
{
ai.TimePassed += waited;
var aiValue = ai.GetWeight() * ai.WeightMultiplier + Random.Range(0, Confusion);
if (aiValue > bestAiValue)
{
bestAiValue = aiValue;
bestAi = ai;
}
}
bestAi.Execute ();
waited = 0;
}
}
好了,现在就实现了AI的控制,现在有两种方法来控制AI,一种是通过决策执行的频率,另一种是通过混淆值。
现在我们就来创建空闲AI,这个默认AI行为什么都不做,它不依赖权重和行为的暂停,也让我们有机会执行操作,在AI文件夹中创建一个DoNothingAI,如下
using UnityEngine;
using System.Collections;
public class DoNothingAi : AiBehavior {
public float ReturnWeight = 0.5f; //方便设计者设置的明确的权重
public override float GetWeight ()
{
return ReturnWeight;
}
public override void Execute ()
{
Debug.Log ("Doing Nothing");
}
}
AI需要知道所属玩家名字,以及获得相关玩家的信息,所以回到AiController脚本中,添加一下信息:
public string PlayerName; //所属玩家的名字
private PlayerSetupDefinition player; //所属玩家的详细信息
public PlayerSetupDefinition Player { get { return player; } }
并在Start函数里面赋值
void Start () {
foreach (var ai in GetComponents<AiBehavior>()) {
Ais.Add (ai);
}
foreach (var p in RtsManager.Current.Players) {
if (p.Name == PlayerName) player = p;
}
gameObject.AddComponent<AiSupport> ().Player = player;
}
返回到Unity中,在Manager下创建一个新的空物体命名Player2Ai ,并为其添加脚本,如图
现在就做好了一个空闲的AI,接下来我们将处理建造AI,我们要创建一个AISupport来检测每个AiController的单位数量,编辑如下:
using UnityEngine;
using System.Collections.Generic;
public class AiSupport : MonoBehaviour {
public List<GameObject> Drones = new List<GameObject>(); //无人机
public List<GameObject> CommandBases = new List<GameObject>();//建筑
public PlayerSetupDefinition Player = null;
public static AiSupport GetSupport (GameObject go)
{
return go.GetComponent<AiSupport>();
}
public void Refresh()
{
Drones.Clear ();
CommandBases.Clear ();
foreach (var u in Player.ActiveUnits) {
if (u.name.Contains("Drone Unit")) Drones.Add (u);
if (u.name.Contains("Command Base")) CommandBases.Add(u);
}
}
}
每个AIController都需要获得AISupport脚本,然后返回到AIController中,在Start里面添加一下:
void Start () {
foreach (var ai in GetComponents<AiBehavior>()) {
Ais.Add (ai);
}
foreach (var p in RtsManager.Current.Players) {
if (p.Name == PlayerName) player = p;
}
gameObject.AddComponent<AiSupport> ().Player = player;
}
然后在Update里面调用Refesh函数进行刷新,如下
void Update () {
waited += Time.deltaTime;
if (waited < Frequency)
return;
float bestAiValue = float.MinValue;
AiBehavior bestAi = null;
AiSupport.GetSupport (gameObject).Refresh ();
foreach (var ai in Ais) {
ai.TimePassed += waited;
var aiValue = ai.GetWeight() * ai.WeightMultiplier + Random.Range(0, Confusion);
if (aiValue > bestAiValue)
{
bestAiValue = aiValue;
bestAi = ai;
}
}
bestAi.Execute ();
waited = 0;
}
好了,运行如下图,
好了,这一章就写到这,欢迎大家加入QQ群:280993838 或者关注我的公众号: