在Unity3D中的感知系统使用的便是一个中介者模式,感知包括视觉感应器、听觉感应器、视觉触发器、听觉触发器等,感应器触发器之间的交互交由中介者来完成,最大程度上实现感应器、触发器直接的解耦。
听觉感应器:
[RequireComponent(typeof(NavMeshAgent))]
public class HearingSensor:AbstractSensor
{
public float hearingDistance;
public bool IsCheckCover;
private NavMeshPath path;
private NavMeshAgent navMeshAgent;
private Vector3? targetPosition;
public new void Start()
{
base.Start();
navMeshAgent = GetComponent<NavMeshAgent>();
}
public override bool CheckTrigger(AbstractTrigger trigger)
{
if (trigger.triggerType == TriggerType.Hearing)
{
var tempTrigger = trigger as HearingTrigger;
float toDistance = tempTrigger.spreadDistance + hearingDistance;
if (!tempTrigger.IsSounding) return false;
bool result = tempTrigger.IsSounding && toDistance >
Vector3.Distance(this.transform.position,trigger.gameObject.transform.position);
if(IsCheckCover && targetPosition != trigger.gameObject.transform.position)
{
targetPosition = trigger.gameObject.transform.position;
result = toDistance > PathLength(targetPosition.Value);
}
return result;
}
return false;
}
private float PathLength(Vector3 targetPosition) {
NavMeshPath path = new NavMeshPath();
navMeshAgent.CalculatePath(targetPosition, path);
if (path.corners.Length < 2)
return 0;
Vector3 previousCorner = path.corners[0];
float lengthSoFar = 0.0F;
int i = 1;
while (i < path.corners.Length) {
Vector3 currentCorner = path.corners[i];
lengthSoFar += Vector3.Distance(previousCorner, currentCorner);
previousCorner = currentCorner;
i++;
}
return lengthSoFar;
}
private void OnDisable()
{
targetPosition = null;
}
}
}
听觉触发器:
public class HearingTrigger:AbstractTrigger
{
public float spreadDistance;
private Coroutine coroutine;
public bool IsSounding;
public float continueTime;
public new void Start()
{
base.Start();
triggerType = TriggerType.Hearing;
}
private void OnEnable()
{
StartCoroutine(Timer());
}
private IEnumerator Timer()
{
IsSounding = true;
yield return new WaitForSeconds(continueTime);
IsSounding = false;
}
private void OnDisable()
{
IsSounding = false;
}
}
}
中介者:触发器与感应器管理类
public class SensorTriggerManager:MonoSingleton<SensorTriggerManager>
{
private List<AbstractSensor> listSensor = new List<AbstractSensor>();
private List<AbstractTrigger> listTrigger = new List<AbstractTrigger>();
private float CheckInterval = 1.0f;
public void AddSensor(AbstractSensor sensor)
{
if (!listSensor.Contains(sensor))
listSensor.Add(sensor);
}
public void RemoveSensor(AbstractSensor sensor)
{
if (listSensor.Contains(sensor))
listSensor.Remove(sensor);
}
public void AddTrigger(AbstractTrigger trigger)
{
if (!listTrigger.Contains(trigger))
listTrigger.Add(trigger);
}
public void RemoveTrigger(AbstractTrigger trigger)
{
if (listTrigger.Contains(trigger))
listTrigger.Remove(trigger);
}
private void OnEnable()
{
InvokeRepeating("CheckSensor", 0, CheckInterval);
}
private void OnDisable()
{
CancelInvoke("CheckSeneor");
}
private void CheckSensor()
{
List<AbstractTrigger> tempList = new List<AbstractTrigger>();
for (int i = 0; i < listSensor.Count; i++)
{
tempList.Clear();
if (!listSensor[i].enabled)
continue;
for (int j = 0; j < listTrigger.Count; j++)
{
if (listTrigger[j].enabled &&
listSensor[i].gameObject != listTrigger[j].gameObject &&
listSensor[i].CheckTrigger(listTrigger[j]))
tempList.Add(listTrigger[j]);
}
if (0 < tempList.Count)
listSensor[i].OnSenorInfoNotity(tempList);
else
listSensor[i].OnNoSenorInfoNotity();
}
}
}
当需要扩展感知系统时,比如视觉感知,只需要添加视觉感应器和视觉触发器就可以了。
总结:
中介者模式解决了多对多的情况的耦合问题,而与之相似的观察者则是解决一对多的解耦问题。