Unity 内的敌人AI

孙广东  2015.8.15

一、Enemy Aim Ai 
          目的: 这篇文章的主要目的是为了让您了解有关如何使用 Enemy Aim Ai 。你会得到结果:

Enemy aim AI是非常有用的,当你想要敌人一直监视player。适当争取对象在真实世界的场景,需要时间,所以敌人会采取一些之前它锁在目标系统上的时间量。

这种效应可以创建的 Lerping 旋转角度对玩家的敌人。这种情况是在动作游戏,敌人跟随,目的是何地然后射球员的情况下非常有用。对敌人遵循概念是在早些时候发布的博客中已经讨论过。在推行针对在游戏的同时,理解四元数的概念是非常必要的。

四元数存储对象的旋转,还可以计算价值取向。一个可以直接玩欧拉角,但可能会出现 万向锁 的情况。

根据当地的坐标系统,如果你旋转模型X 轴,然后其 Y 和 Z 轴经验万向节锁被"锁定"在一起。

现在回到我们的主题,给出了下面是一个简单的例子来解释 Enemy aim AI

按照下面给出的步骤。

1、创建Cube将作用在player control

  • 应用适当的材料,根据要求向其网格渲染器
  • 将 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);
}
}



2、创建一个Enemy对象,由箭头和Cube组成,

1、应用适当的材料对Cube 。

2、使箭头Sprite作为一个不同的对象

3、其方向由 Cube指出 . 所以在这里,箭头将充当了敌人的枪。

4、此箭头将指向目标对象和它看起来就好像它试图锁定目标

5、我们也可以操纵速度,敌人将能够锁定目标属性 ;作为不同的敌人应该是不同的困难,以及不同的功能。
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);
}
}

7、Hierarchy 和 Scene View 可能会像作为给定下面

备注:-

可以改变敌人目标并设置锁定目标的速度。

可以脚本通过允许X 或 Y 轴旋转,为了解这一概念的 。

可以给敌人添加Follow 脚本,以便敌人Follow 和 瞄准 玩家。

而不是使用 Quaternion.Lerp 你也可以使用 Quaternion.RotateTowards 达到相同的效果。

二、通过有限状态机实现AI

Contents Objective Step -

1: Set up the scene Step -

2: Create and place Game Objects Step -

3: Implement the BoxMovement Script Step -

4: FSM Modelled Script Step -

5: AI Script for the Box -

目的: 这篇文章的主要目的是要给你一个关于如何使用有限状态机模型在 实现 AI 。

FSM 的基础知识:
           在游戏中实施 AI  Finite State Machine Framework是完美的, 产生伟大的结果,而无需复杂的代码。   它是一个模型,由一个或多个状态。可以在一段时间只有一个单一的状态处于活动状态, 所以这台机器必须从一个状态到另一种的转换 为执行不同的操作。

有限状态机框架通常用于管理、 组织和 代表不同的状态、执行流,在游戏中实现人工智能是非常有用的。"brain"是敌人,例如,可以使用有限状态机来实现:   每个状态表示一个动作,例如 巡逻、 Chase、 逃避或拍摄或任何其他种类的行动。

AI FSMs 的工作与Unity的的Animation FSMs,在那里一个动画状态将更改为另一个符合的要求。可以通过使用第三方插件像行为实施 AI FSM 或它可以直接由脚本以及执行。

若要获取有限状态机框架的基本理念,我们将执行一个教程最简单的方法,使用 switch 语句。然后我们将学习如何使用一个框架,使 AI 实现易于管理和扩展。

请按照下面的步骤来执行简单的有限状态机。

在这里我们将会有两个Box,在那里将由玩家控制一个Box和 对方将由 AI 控制Box。此 AI 控制的Box会在chasing追逐状态或patrolling巡逻状态,即Box中将开始追逐Player Box,一旦Player Box进来的接近 AI 控制Box。它将切换回 巡逻状态,如果玩家足够远逃避  未未的定义的愿景。

Step - 1: Set up the scene

以一个平面和两个Box在场景中,如下图所示的设置。

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。 所以让你的敌人更聪明使用有限状态机,让您的游戏的成功。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-09 18:19:07

Unity 内的敌人AI的相关文章

[Unity插件]Behavior Designer:制作敌人AI

一个简单的敌人AI: 当处于监视范围内,跑向玩家:当处于攻击范围内,攻击玩家:否则呆在原地.用行为树表示就是: 其中当前行为树的变量与全局变量为: 效果图: 制作简单的AI确实不需要写代码,不过配置起来确实有点麻烦了.可以根据需求,编写自定义的节点来组成复杂的AI. 当游戏需要大量的AI时,Behavior Designer确实是一个不错的选择,因为自定义的节点可以不断被重用了.

Unity3D 敌人AI 和 动画( Animator )系统的实例讲解

在这个实例中,我们要做一些敌人AI的简单实现,其中自动跟随和动画是重点,我们要达到的目标如下: 1.敌人能够自动跟随主角 2.敌人模型一共有四个动作:Idle(空闲) Run(奔跑) Attack(攻击) Death(死亡). 3.要求敌人在合适的时机能够做出合适动作 (一)自动跟随的实现 1)首先,新建一个场景  如图,场景里至少有两个角色:  有一个敌人(刀骷髅兵) 还有一个主角(没错,就是那个胶囊体) 2)先选择场景模型,然后在 Inspector 窗口选项 Static旁边的小三角显示出

Unity内置的shader include files

Unity内置的shader include files:这些文件都以.cninc结尾, HLSLSupport.cginc:自动包含,一些跨平台编译相关的宏和定义. UnityCG.cginc:常用的全局变量和函数. AutoLight.cginc:光影相关帮助函数,surface shader内部使用此文件. Lighting.cginc:surface shader自动包含,定义了标准的光照模式. TerrainEngin.cginc:地形和植被shader相关的帮助函数.UnityGC.

【Unity Shaders】使用CgInclude让你的Shader模块化——Unity内置的CgInclude文件

本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源(当然你也可以从官网下载). ========================================== 分割线 ========================================== 写在前面 啦啦啦,又开了新的一章...为什么会讲CgInclude呢?什么又是Cg呢?呜,按我的理解

Unity内置的三套消息发送机制的应用实例

转自http://blog.sina.com.cn/s/blog_1491e52310102wuf6.html 代码简介 : [1] 实例中包含2个类文件, SendMessage.cs 和 ReceiveMessage.cs , 分别为消息发送端和消息接收端. [2] Unity内置的消息发送系统有一个很特别的地方 - 即使接收端的方法类型为 private 或者 protected, 也能够收到信息. [3] Unity内置了3套消息机制,它们分别为 1. SendMessage() 向自己

扩展 Unity 内置类型 (组件)

Unity 内置组件基本没有可以继承的.某些比较常用但现有 API 没有定义的功能,我们可以通过C# 的扩展类方法来实现.下面是一些比较实用的扩展方法. 扩展 Transform 每一个 GameObject 都含有一个 Transform 组件(在 UGUI 里新引入的 RectTransform 继承 Transform),GameObject 的层级也是由 Transform 负责的.以下扩展方法使用了 C# 的委托,关于委托可以参考这里:C# 中的 delegate 和 event. /

Unity3D ARPG游戏开发《最初的幻想》之强化敌人AI,折腾的GUI

 昨天搞了死亡的完善与提示栏的工作.今天的话,首先再升级一下敌人的Ai吧.毕竟在玩家在敌人身后使劲攻击的话,这敌人也都不会有反应的,太不合理了. 打开Enemy脚本,在最前面"变量"标签中,先定义一个计数器,因为必须考虑到被同类"误伤"的情况: private int m_attackMeCount=0;//被一个同类对象攻击的次数 然后再在最下面的WaitForAttack函数中将自己的对象传入自己的攻击对象,以作判断: m_damageTarget.m_ch

unity行为树制作AI简单例子(2)

继续昨天的工程,给Monster添加一个空物体命名为AI,在AI添加脚本BehaviorTree,然后就可以打开行为树编辑器进行编辑了 先写好自定义的节点脚本,下面是一个寻找漫游点的行为节点脚本 using UnityEngine; using BehaviorDesigner.Runtime.Tasks; using BehaviorDesigner.Runtime; [TaskCategory("MyActions")] [TaskDescription("计算出更新的路

【Unity】8.1 Unity内置的UI控件

分类:Unity.C#.VS2015 创建日期:2016-04-27 一.简介 Unity 5.x内置了-套完整的GUI系统,提供了从布局.控件到皮肤的-整套GUI解决方案,因此可直接利用它做出各种风格和样式的GUI界面,并且扩展性很强(程序员可以基于已有的控件创建出适合自己需求的控件). 有两种使用GUI的办法,一种是直接将UI添加到层次视图或者场景视图中,然后通过GUI脚本去控制它:另一种是直接通过GUI脚本去创建. 二.直接添加UI控件到场景中 下图是Unity 5.3.4内置的UI控件,