本文共 4951 字,大约阅读时间需要 16 分钟。
前面讲的算法和确定性算法都很好,不过有时候你需要创建一个按照顺序执行操作的游戏对象。例如,工作日来到单位你都会执行一系列特定的步骤:
1、打卡 2、开启电脑 3、点开平常逛的网站看看最新消息 ........
关键在于很多步骤是你不会多想的,每次都是习惯性的自然重复。当然,如果有什么事情不对了,你可能会改变顺序,比如今天接到一个要外出的任务,你可能就直接打完卡就走了。模式是只能行为的重要部分,甚至人类也会用到模式。
扯了那么多没用的,进入的正题吧,这次我要讲的是基本模式。它是游戏模式里面最简单的,为游戏对象创建模式可以很简单,这取决于游戏对象本身。大部分的类似于《星球大战》的射击游戏,所有攻击者必须遵循一个左右移动的模式并在某点用一个特定的进攻模式来攻击你。这种模式,或者脚本控制的AI,可以有很多实现的技术,不过我想最简单的技术是基于一套经由解释执行的动作指令,每一个运动模式都存储为一系列方向或指令。如下表:为一个我设计的模式语言指令集
而模式发生的运动(假设的)如图所示:
另外每一个方向性的指令后面可能还根由一个操作数或者数据来限定它,比如执行的时间。我预设了一个text文件里面存储了这样的一系列指令
这个text的指令文件没一行代表一个指令序列,第一个数字时这一行指令序列的索引紧跟其后的是分号用来作为读取的时候的分割符号。比如第一行,1代表的是序列索引号,后面的1和10是一起的表示执行第一个指令并执行10秒钟,最后都是以6结束代表这行指令执行完毕。
读取并使用这个text的代码如下:
using UnityEngine;using System.Collections;using System.Collections.Generic;using System.IO;using System.Text;public class TextToolControl{ private static TextToolControl _istance; public static TextToolControl GetInstance() { if (_istance == null) { _istance = new TextToolControl(); } return _istance; } private DictionarypatternDict; // Use this for initialization public void Init() { TextAsset ta = Resources.Load("BasicPattern") as TextAsset; StringReader sr = new StringReader(Encoding.UTF8.GetString(ta.bytes)); char[] sp1 = { ';' }; char[] sp2 = { ',' }; patternDict = new Dictionary (); while (true) { string line = sr.ReadLine(); if (line == null) { return; } if (line == "" || line == " ") { continue; } string[] data = line.Split(sp1, System.StringSplitOptions.RemoveEmptyEntries); if (data == null) { Debug.LogError("数据为空" + line); continue; } patternDict[int.Parse(data[0])] = data[1].Split(sp2, System.StringSplitOptions.RemoveEmptyEntries); } } public List GetContent(int key) { if (patternDict == null) { Init(); } if (!patternDict.ContainsKey(key)) { Debug.LogError("不存在" + key); return null; } List temp = new List (); for (int i = 0; i < patternDict[key].Length; i++) { temp.Add(int.Parse(patternDict[key][i])); } return temp; }}
要处理模式指令,你只需要使用一个Switch语句解释每一个指令并告诉游戏角色他需要做什么,如下:
void BasicPattern_AI() { if (m_currentPattern == null) { m_patternIndex = Random.Range(1, 5); // m_patternIndex = 3; m_currentPattern = TextToolControl.GetInstance().GetContent(m_patternIndex); m_currentOperand = 0; m_timeCounter = 0; } //每个具体操作的操作时间到了就执行下一个操作 m_timeCounter -= Time.deltaTime; if(m_timeCounter<=0) { // moveDirection = MoveDirection.Random; moveDirection = (MoveDirection)m_currentPattern[m_currentOperand]; m_timeCounter = m_currentPattern[m_currentOperand + 1]; switch (moveDirection) { case MoveDirection.East: { ChangeDirection(-1, 0); } break; case MoveDirection.North: { ChangeDirection(0, -1); } break; case MoveDirection.South: { ChangeDirection(0, 1); } break; case MoveDirection.West: { ChangeDirection(1, 0); } break; case MoveDirection.Stop: { ChangeDirection(0, 0); } break; case MoveDirection.End: { ChangeDirection(0, 0); m_patternIndex = Random.Range(1, 5); m_currentPattern = TextToolControl.GetInstance().GetContent(m_patternIndex); m_currentOperand = 0; m_timeCounter = 0; } break; case MoveDirection.Random: { //随机的改变方向 float x=Random.Range(-10.0f, 10.0f) / 10.0f;//一定是要是浮点型不是整数型不然得不到-1到1之间的小数,如果是整数等到的永远是0 float z=Random.Range(-10.0f, 10.0f) / 10.0f; // Debug.Log("x:" + x + "z:" + z); ChangeDirection(x,z); } break; } if (m_currentOperand < m_currentPattern.Count-1) { m_currentOperand += 1; } } }
另外,所有的的模式都要有一个要点:合理运动。因为有可能选择一个模式,而按照这个模式运动的话它会撞上其他东西。如果模式AI不考虑这一点的话,模式只会被游戏对象盲从。因此你的模式AI必须要有一个反馈循环来通知AI它执行了某些非法、不可行的或者不合理的操作,而且必须采取相应的应对措施使得它恢复正常。这一次就不配动态图了,因为动态图片都好大。
转载地址:https://blog.csdn.net/zhangxiao13627093203/article/details/47708893 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!