好看的个人网站设计,深圳精准网络营销推广,大英县住房和城乡建设局网站,首页制作教程游戏中最常用的感知类型是视觉和听觉。对于视觉#xff0c;需要配对的触发器和感知器#xff0c;听觉也是。总的来说#xff0c;游戏中有多个触发器和感知器#xff0c;可以通过事件管理器同意对其进行管理
所有触发器的基类——Trigger类
在介绍感知之前#xff0c;需要…游戏中最常用的感知类型是视觉和听觉。对于视觉需要配对的触发器和感知器听觉也是。总的来说游戏中有多个触发器和感知器可以通过事件管理器同意对其进行管理
所有触发器的基类——Trigger类
在介绍感知之前需要实现触发器类Trigger。Trigger中包含所有触发器共有的相关信息和方法。例如位置、作用半径以及是否已完成使命而需要被移除等。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Trigger : MonoBehaviour
{protected TriggerSystemManager manager;//保存管理中心对象protected Vector3 position;//触发器的位置public int radius;//触发器的半径public bool toBeRemoved;//当前触发器是否需要被移除public virtual void Try(Sensor s) { }//这个方法检查作为参数的感知器s是否在触发器的作用范围内如果是那么采取相应行为。在派生类中实现public virtual void Updateme() { }//这个方法更新触发器的内部状态例如声音触发器的剩余有效时间等protected virtual bool isTouchingTrigger(Sensor sensor) //这个方法检查感知器s是否在触发器的作用范围内如果是返回true若不是返回false它被Try调用。在派生类中实现{return false;}void Awake(){manager FindObjectOfTypeTriggerSystemManager();}protected void Start(){toBeRemoved false;}void Update(){}
}所有感知器的基类——Sensor类
这个类中包含了对感知器的枚举定义和变量还保存了事件管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Sensor : MonoBehaviour
{protected TriggerSystemManager manager;//保存管理中心对象public enum SensorType{sight,sound,health}public SensorType sensorType;void Awake(){manager FindObjectOfTypeTriggerSystemManager();}void Start(){}void Update(){}public virtual void Notify(Trigger t){}
}事件管理器
这个类负责管理触发器的集合。它维护一个当前所有触发器的列表当每个触发器被创建时都会想这个管理器注册自身加入到这个列表中。事件管理器负责更新和处理所有的触发器并且当触发器已过期需要被移除时从列表中删除它们。
事件管理器还维护了一个感知器列表每个感知器被创建时向这个管理器注册加入到感知器列表中
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TriggerSystemManager : MonoBehaviour
{ListSensor currentSensors new ListSensor();//初始化当前感知器列表ListTrigger currentTriggers new ListTrigger();//初始化当前触发器列表ListSensor sensorsToRemove;//记录当前时刻需要被移除的感知器ListTrigger triggersToRemove;//记录当前时刻需要被移除的触发器void Start(){sensorsToRemove new ListSensor();triggersToRemove new ListTrigger();}private void UpdateTriggers(){foreach(Trigger t in currentTriggers){if (t.toBeRemoved){triggersToRemove.Add(t);//将t加入需要移除的触发器列表中}else{t.Updateme();}}foreach (Trigger t in triggersToRemove)currentTriggers.Remove(t);}private void TryTriggers(){foreach(Sensor s in currentSensors){if (s.gameObject ! null){foreach(Trigger t in currentTriggers){t.Try(s);}}else{sensorsToRemove.Add(s);}}foreach(Sensor s in sensorsToRemove)currentSensors.Remove(s);}void Update(){UpdateTriggers();TryTriggers();}public void RegisterTrigger(Trigger t)//用于注册触发器{print(registering trigger: t.name);currentTriggers.Add(t);}public void RegisterSensor(Sensor s)//用于注册感知器{print(registering sensor: s.name);currentSensors.Add(s);}
}视觉感知
一般可以用不同的圆锥来模拟不同类型的视觉。一个近距离大锥角的圆锥可以模拟出视觉中的余光而近距离的视觉通常用更长、更窄的圆锥体来表示。每一个锥体都有一个角度和视线能及的最大距离来定义。
视觉的一个特性是不能穿过障碍物因此只判断物体是否在视锥体范围之内是不够的还需要进行视线检测LOS才能确定最终结果。
要实现视觉感知要为感兴趣的、能被看到的那些游戏对象加上一个视觉触发器视觉触发器类是Trigger的派生类对于AI角色能看到并需要做出相应的每个游戏对象都需要添加它例如玩家、宝物、可以捡起的武器等。当AI角色看到这些对象时就会做出某种反应。相反如果某个游戏对象只是一般的涵盖五仅仅需要在行走时避开那么就不需要加触发器只需要在寻路时将其设置为障碍物即可。
需要注意的是AI角色的感知器中定义的是这个角色的视力能力而这个SightTrigger中定义的半径表示这个触发器的范围
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SightTrigger :Trigger
{public override void Try(Sensor sensor){if (isTouchingTrigger(sensor)){sensor.Notify(this);}}protected override bool isTouchingTrigger(Sensor sensor)//判断感知器是否能感知到这个触发器{GameObject g sensor.gameObject;if (sensor.sensorType Sensor.SensorType.sight)//如果这个感知器能够感知视觉信息{RaycastHit hit;Vector3 rayDirection transform.position - g.transform.position;rayDirection.y 0;if((Vector3.Angle(rayDirection,g.transform.forward))(sensor as SightSensor).fieldOfView)//判断感知体的前向方向与物体所在方向的夹角是否在视域范围内{if(Physics.Raycast(g.transform.positionnew Vector3(0,1,0),rayDirection ,out hit,(sensor as SightSensor).viewDistance))//在视线距离内是否存在其他障碍物{if (hit.collider.gameObject this.gameObject){return true;}}}}return false;}public override void Updateme() //更新触发器内部信息由于带有视觉触发器的AI角色可能是运动的因此要不停更新位置{position transform.position;}void Start(){base.Start();manager.RegisterTrigger(this);}void Update(){}
}我们还需要一个视觉感知器给能感知到视觉信息的AI角色带上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SightSensor : Sensor
{public float fieldOfView 45;//定义这个AI角色的视域范围public float viewDistance 100;//定义最远能看到的范围private AIController1 controller;void Start(){controller GetComponentAIController1();sensorType SensorType.sight;//设置感知器类型为视觉类型manager.RegisterSensor(this);}// Update is called once per framevoid Update(){}public override void Notify(Trigger t){print(I see a t.gameObject.name !);Debug.DrawLine(transform.positionn, t.transform.position, Color.red);controller.MoveToTarget(t.gameObject.transform.position);}void OnDrawGizmos(){Vector3 frontRayPoint transform.position (transform.forward * viewDistance);float fieldOfViewinRadians fieldOfView * 3.14f / 180.0f;Vector3 leftRayPoint transform.TransformPoint(new Vector3(viewDistance * Mathf.Sin(fieldOfViewinRadians), 0, viewDistance * Mathf.Cos(fieldOfViewinRadians)));Vector3 rightRayPoint transform.TransformPoint(new Vector3(-viewDistance * Mathf.Sin(fieldOfViewinRadians), 0, viewDistance * Mathf.Cos(fieldOfViewinRadians)));Debug.DrawLine(transform.position new Vector3(0, 1, 0), frontRayPoint new Vector3(0, 1, 0), Color.green);Debug.DrawLine(transform.position new Vector3(0, 1, 0), leftRayPoint new Vector3(0, 1, 0), Color.green);Debug.DrawLine(transform.position new Vector3(0, 1, 0), rightRayPoint new Vector3(0, 1, 0), Color.green);}
}听觉感知
听觉感知可以用一个球形区域来模拟。一种方法是声音被创建时为其加上一个强度属性随着距离增加强度减弱。而AI角色也有自己的听觉阈值如果声音强度小于这个值就听不到。
听觉的特殊之处是它会很快消失。除了声音外还有其他对象例如血包等物体也有这样的事件特性。所有这种具有特定生命周期的触发器都可以用下面的类派生出来
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TriggerLimitedLifetime :Trigger
{protected int lifetime;public override void Updateme() { if((--lifetime) 0){toBeRemoved true;}}void Start(){base.Start();}void Update(){}
}声音触发器是TriggerLimitedLifetime的派生类。武器开火时在开火的位置会创建一个SoundTrigger半径可以设置为正比于武器声音的大小。如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SoundTrigger : TriggerLimitedLifetime
{public override void Try(Sensor sensor) //判断感知器是否能听到声音,如果能通知感知器{if (isTouchingTrigger(sensor)){sensor.Notify(this);}}
protected override bool isTouchingTrigger(Sensor sensor) //判断感知器能否听到触发器的声音
{GameObject g sensor.gameObject;if (snesor.sensorType sensor.SensorType.sound){if ((Vector3.Distance(transform.position, g.transform.position)) radius){return true;}}return false;
}
void Start(){lifetime 3;base.Start();manager.RegisterTrigger(this);}void Update(){}void OnDrawGizmos(){Gizmos.color Color.blue;OnDrawGizmos().DrawWireSphere(transfor.position, radius);}
}为具有听觉的AI角色加上声音感知器这个感知器是Sensor的派生类用来感知由声音触发器触发的那些声音信息
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SoundSensor :Sensor
{public float hearingDistance 30.0f;private AIController1 contorller;void Start(){controller GetComponentAIController1();sensorType SensorType.sound;manager.RegisterSensor(this);}void Update(){}public override void Notify(Trigger t){print(I hear some sound at t.gameObject.transform.position Time.time);controller.MoveToTarget(t.gameObject.transform.position);}
}触觉感知
这一部分我们可以交给Unity的物理引擎来处理。通过为一个游戏物体加上碰撞体并勾选isTrigger就可以将其标记为触发器当触发器和另一个Collider碰撞时至少有一个附加了Rigidbody就会有OnTriggerEnter、OnTriggerStay和OnTriggerExit被调用。在这三个函数中编写相应的代码就可以实现触觉感知了。 记忆感知
为了让角色具有记忆实现了一个SenseMemory类这个类具有一个记忆列表列表中保存了每个最近感知到的对象、感知类型、最后感知到该对象的时间以及还能在记忆中保留的时间以及何时删除记忆对象。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class MemoryItem
{public GameObject g;public float lastMemoryTime;public float memoryTimeLeft;public float sensorType;public MemoryItem(GameObject objectToAdd, float time,float timeLeft,float type){g objectToAdd;lastMemoryTime time;memoryTimeLeft timeLeft;sensorType type;}
}public class SenseMemory : MonoBehaviour
{private bool alreadyInList false;//已经在表中?public float memoryTime 4.0f;//记忆存留时间public ListMemoryItem memoryList new ListMemoryItem();//记忆列表private ListMemoryItem removeList new ListMemoryItem();public bool FindInList()//在记忆列表中寻找玩家信息{foreach (MemoryItem mi in memoryList)if (mi.g.tag Player)return true;return false;}public void AddToList(GameObject g, float type)//向记忆列表中添加一个项{alreadyInList false;foreach (MemoryItem mi in memoryList){//如果添加项已在则更新其信息if (g mi.g){alreadyInList true;mi.lastMemoryTime memoryTime.time;mi.memoryTimeLeft memoryTime;if (type mi.sensorType)mi.sensorType type;break;}}if (!alreadyInList){MemoryItem newItem new MemoryItem(g, memoryTime.time, memoryTime, type);memoryList.Add(newItem);}}void Update(){removeList.Clear();foreach(MemoryItem mi in memoryList){mi.memoryTimeLeft - Time.deltaTime;if (mi.memoryTimeLeft 0){removeList.Add(mi);}else{if (mi.g ! null)Debug.DrawLine(transform.position, mi.g.transform.position, Color.blue);}}foreach(MemoryItem mi in removeList){memoryList.Remove(mi);}}
}其他类型的感知——血包、宝物等物品的感知
有一些游戏对象在被一个实体触发后会爆锤定时间的非活动状态之后又变成活动状态这种触发器都可以从下面的TriggerRespawning类派生出来
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TriggerRespawning : Trigger
{protected int numUpdateBetweenRespawns;protected int numUpdatesRemainingUnitilRespawn;protected bool isActive;protected void SetActive(){isActive true;}protected void SetInactive(){isActive false;}protected void Deactivate(){SetInactive();numUpdatesRemainingUnitilRespawnnumUpdateBetweenRespawns;}public override void Updateme(){if ((--numUpdatesRemainingUnitilRespawn 0) !isActive){SetActive();}}void Start(){isActivetrue;base.Start();}void Update(){}
}下面的血包供给器是TriggerRespawning类的派生类当能够感知它的角色靠近时就可以增加生命值
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TriggerHealthGiver : TriggerRespawning
{public int healthGiven 10;public override void Try(Sensor sensor){if (isActive isTouchingTrigger(sensor)){AIController1 cotroller sensor.GetComponentAIController();if (cotroller ! null){controller.health healthGiven;print(now my health is: healthScript.health);this.renderer.material.color Color.green;StartCoroutine(TurnColorBack);sensor.Notifu(this);}elseprint(cant get health script);}Deactivate();}IEnumerator TurnColorBack(){yield return new WaitForSeconds(3);this.renderer.material.color TurnColorBack().black;}protected override bool isTouchingTrigger(Sensor sensor){GameObject g sensor.gameObject;if(sensor.snesorTypeSensor.SensorType.health){if (Vector3.Distance(transform.position, g.transform.position) radius){return true;}}return false;}void Start(){numUpdateBetweenRespawns 6000;base.Start();manager.RegisterTrigger(this);}void Update(){}void OnDrawGizmos(){Gizmos.color TurnColorBack().yellow;OnDrawGizmos().DrawWireSphere(transform.position, radius);}
}下面的HealthSensor是Sensor的派生类添加了它的AI角色在靠近生命值触发器时能够增加自身的生命值
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class HealthSensor : Sensor
{void Start(){sensorType SensorType.health;manager.RegisterSensor(this);}public virtual void Notify(Trigger t){}
}