作者:孙广东
一、Enemy Aim Ai
目的: 这篇文章的主要目的是为了让您了解有关如何使用 Enemy Aim Ai 。你会得到结果:
-
应用适当的材料,根据要求向其网格渲染器
-
将 TargetMovementScript 应用于游戏对象
-
将Cube 作为对象来将移动上 player'scommands。
TargetMovementScript.cs
public class TargetMovementScript : MonoBehaviour { public float targetSpeed=9.0f;//Speed At Which the Object Should Move void Update () transform.Translate (Input.GetAxis ("Horizontal")*Time.deltaTime*targetSpeed,Input.GetAxis ("Vertical")*Time.deltaTime*targetSpeed,0); } }
6、一辆坦克应采取更多的时间锁定一名士兵用枪瞄准。所以在其中之一可以锁定目标的速度应该是不同的。
EnemyAimScript.cs
public class EnemyAimScript : MonoBehaviour { public Transform target; // Target Object public float enemyAimSpeed=5.0f; // Speed at Which Enenmy locks on the Target Quaternion newRotation; float orientTransform; float orientTarget; void Update () { orientTransform = transform.position.x; orientTarget = target.position.x; // To Check on which side is the target , i.e. Right or Left of this Object if (orientTransform > orientTarget) { // Will Give Rotation angle , so that Arrow Points towards that target newRotation = Quaternion.LookRotation (transform.position - target.position, -Vector3.up); } else { newRotation = Quaternion.LookRotation (transform.position - target.position,Vector3.up); } // Here we have to freeze rotation along X and Y Axis, for proper movement of the arrow newRotation.x = 0.0f; newRotation.y = 0.0f; // Finally rotate and aim towards the target direction using Code below transform.rotation = Quaternion.Lerp (transform.rotation,newRotation,Time.deltaTime * enemyAimSpeed); // Another Alternative // transform.rotation = Quaternion.RotateTowards(transform.rotation,newRotation, Time.deltaTime * enemyAimSpeed); } }
可以改变敌人目标并设置锁定目标的速度。
可以脚本通过允许X 或 Y 轴旋转,为了解这一概念的 。
可以给敌人添加Follow 脚本,以便敌人Follow 和 瞄准 玩家。
FSM 的基础知识:
在游戏中实施 AI Finite State Machine Framework是完美的, 产生伟大的结果,而无需复杂的代码。
Step - 2: Create and place Game Objects
创建空的游戏对象并将其作为游子点Wanderer Points。放置这些空的游戏对象下,为您选择平面周围。在这里蓝色的Cube是 AI Cube和红一个是玩家控制的Cube。将它们放在距离不够远。
Step - 3: Implement the BoxMovement Script
实现 BoxMovement 脚本来控制玩家的Cube的移动:如下:
public class BoxMovementScript : MonoBehaviour { public float speed = 0.1f; private Vector3 positionVector3; void Update () { InitializePosition (); if (Input.GetKey (KeyCode.LeftArrow)) { GoLeft (); } if (Input.GetKey (KeyCode.RightArrow)) { GoRight (); } if (Input.GetKey (KeyCode.UpArrow)) { GoTop (); } if (Input.GetKey (KeyCode.DownArrow)) { GoDown (); } RotateNow (); } private void InitializePosition () { positionVector3 = transform.position; } private void RotateNow () { Quaternion targetRotation = Quaternion.LookRotation (transform.position - positionVector3); transform.rotation = targetRotation; } private void GoLeft () { transform.position = transform.position + new Vector3 (-speed, 0, 0); } private void GoRight () { transform.position = transform.position + new Vector3 (speed, 0, 0); } private void GoTop () { transform.position = transform.position + new Vector3 (0, 0, speed); } private void GoDown () { transform.position = transform.position + new Vector3 (0, 0, -speed); } }
Step - 4: FSM Modelled Script
构建FSM模型脚本:
public class FSM : MonoBehaviour { //Player Transform protected Transform playerTransform; //Next destination position of the Box protected Vector3 destPos; //List of points for patrolling protected GameObject[] pointList; protected virtual void Initialize (){ } protected virtual void FSMUpdate (){ } protected virtual void FSMFixedUpdate (){ } void Start () { Initialize (); } void Update () { FSMUpdate (); } void FixedUpdate () { FSMFixedUpdate (); } }
Step - 5: AI Script for the Box
构建 AI 脚本作为Box扩展.
public class BoxFSM : FSM { public enum FSMState { None, Patrol, Chase, } //Current state that the Box is in public FSMState curState; //Speed of the Box private float curSpeed; //Box Rotation Speed private float curRotSpeed; //Initialize the Finite state machine for the AI Driven Box protected override void Initialize () { curState = FSMState.Patrol; curSpeed = 5.0f; curRotSpeed = 1.5f; //Get the list of points pointList = GameObject.FindGameObjectsWithTag ("WandarPoint"); //Set Random destination point for the patrol state first FindNextPoint (); //Get the target enemy(Player) GameObject objPlayer = GameObject.FindGameObjectWithTag ("Player"); playerTransform = objPlayer.transform; if (!playerTransform) print ("Player doesn't exist.. Please add one " + "with Tag named 'Player'"); } //Update each frame protected override void FSMUpdate () { switch (curState) { case FSMState.Patrol: UpdatePatrolState (); break; case FSMState.Chase: UpdateChaseState (); break; } } protected void UpdatePatrolState () { //Find another random patrol point on reaching the current Point //point is reached if (Vector3.Distance (transform.position, destPos) <= 2.5f) { print ("Reached to the destination point\n" + "calculating the next point"); FindNextPoint (); } //Check the distance with player Box //When the distance is near, transition to chase state else if (Vector3.Distance (transform.position, playerTransform.position) <= 15.0f) { print ("Switch to Chase State"); curState = FSMState.Chase; } //Rotate to the target point Quaternion targetRotation = Quaternion.LookRotation (destPos - transform.position); transform.rotation = Quaternion.Slerp (transform.rotation, targetRotation, Time.deltaTime * curRotSpeed); //Go Forward transform.Translate (Vector3.forward * Time.deltaTime * curSpeed); } protected void FindNextPoint () { print ("Finding next point"); int rndIndex = Random.Range (0, pointList.Length); float rndRadius = 5.0f; Vector3 rndPosition = Vector3.zero; destPos = pointList [rndIndex].transform.position + rndPosition; //Check Range to Move and decide the random point //as the same as before if (IsInCurrentRange (destPos)) { rndPosition = new Vector3 (Random.Range (-rndRadius, rndRadius), 0.0f, Random.Range (-rndRadius, rndRadius)); destPos = pointList [rndIndex].transform.position + rndPosition; } } protected bool IsInCurrentRange (Vector3 pos) { float xPos = Mathf.Abs (pos.x - transform.position.x); float zPos = Mathf.Abs (pos.z - transform.position.z); if (xPos <= 8 && zPos <= 8) return true; return false; } protected void UpdateChaseState () { //Set the target position as the player position destPos = playerTransform.position; //Check the distance with player Box When float dist = Vector3.Distance (transform.position, playerTransform.position); //Go back to patrol as player is now too far if (dist >= 15.0f) { curState = FSMState.Patrol; FindNextPoint (); } //Rotate to the target point Quaternion targetRotation = Quaternion.LookRotation (destPos - transform.position); transform.rotation = Quaternion.Slerp (transform.rotation, targetRotation, Time.deltaTime * curRotSpeed); //Go Forward transform.Translate (Vector3.forward * Time.deltaTime * curSpeed); } }
此脚本适用于Cube是要跟随玩家,不要忘记把player标记Tag为 Player 和 Tag 为 WandarPoint,现在如 FSMUpdate() 所示的脚本将调用方法,这在子类中重写和它将在每个 update () 上执行。
在这里switch case被实施 将用于执行的当前状态的操作。 因此扩展 AI 是很简单的仅仅通过添加新的state。Initialize() 方法也重写,并将在 start () 方法中调用执行。UpdatePatrolState() 将在每次更新上执行,当当前状态是patrol 周围巡逻,也将会发生在 UpdateChaseState(),当玩家在接近度 AI Box。如果当处于巡逻,玩家进来的 AI Box中,状态将更改为 巡逻,相同 类型的检查仍在 追逐模式检查如果球员已远离其视野范围, 然后切换回巡逻状态, 在每个更新,检查状态更改。
结论:
FSM 的很容易理解和实现,Fsm 可以用于执行复杂的 AI 。他们也可以表示使用图,允许开发人员很容易理解,因此开发人员可以调整、 改变和优化的最终结果。有限状态机使用的函数或方法来代表状态执行是简单、 功能强大、 易于扩展。 可以使用基于堆栈的状态机,确保易于管理和稳定的 执行流,而不会产生消极影响的代码应用甚至更复杂的 AI。 所以让你的敌人更聪明使用有限状态机,让您的游戏的成功。