322 lines
15 KiB
C#
322 lines
15 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
/*该scrip用于创建复数条ray于视角内,并探测被ray射到的物体*/
|
||
|
||
|
||
public class RaySensors : MonoBehaviour
|
||
{
|
||
|
||
public Camera agentCam;
|
||
public GameObject myself;
|
||
public int rayNum = 6;
|
||
public string EnemyTagName;
|
||
public string WallTagName;
|
||
public float viewDistance = 100; // how long the ray can detect
|
||
public float Damage = 50; // damage to enemy
|
||
public float attentionRange = 1f; //注意力范围,1为最大
|
||
public float MaxDistance = 9999999999f;
|
||
public float EnemyWidthRedundancy = 0.01f; //为了确保Ray可以击中Enemy,用于缩小EnemyWidth的长度
|
||
//public List<string> tagNames = new List<string>();
|
||
public static int allEnemyNum = 0;//All Enemy Num
|
||
public static float[] focusEnemyInfo = new float[3];
|
||
public static float[] rayTagResult; // Array to save Tag Result
|
||
public static float[] rayDisResult; // Array to save Distance Result
|
||
public static List<float> enemyLDisList = new List<float>();// All Enemy Lside Distances
|
||
public static List<float> enemyRDisList = new List<float>();// All Enemy Rside Distances
|
||
|
||
|
||
|
||
public bool showEnemySensor = true;
|
||
public bool showEyeSensor = true;
|
||
|
||
|
||
static int tagToInt(string tag)
|
||
{
|
||
switch (tag)
|
||
{
|
||
case "Wall":
|
||
return 1;
|
||
case "Enemy":
|
||
return 2;
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// 敌人Ray探测处理
|
||
// 返回
|
||
(int, List<float>, List<float>, float[]) enemySensorRay(GameObject myself, Camera agentCam, float attentionRange)
|
||
{
|
||
List<float> thisLDistanceList = new List<float>();
|
||
List<float> thisRDistanceList = new List<float>();
|
||
|
||
GameObject[] EnemyGameObjs;
|
||
EnemyGameObjs = GameObject.FindGameObjectsWithTag("Enemy");
|
||
int EnemyIndex = 0;
|
||
float MinEnemyDis = MaxDistance+1.0f;
|
||
int MinEnemyIndex = 0;
|
||
float[] MinEnemyInfo = new float[3];
|
||
|
||
//遍历所有Enemy
|
||
foreach (GameObject EnemyObj in EnemyGameObjs)
|
||
{
|
||
Vector3 thisEnemyPosition = EnemyObj.transform.position;
|
||
Vector3 thisEnemyScale = EnemyObj.transform.localScale;
|
||
Vector3 MyselfPosition = myself.transform.position;
|
||
float thisEnemyWidth = (float)(thisEnemyScale.x / 2) - EnemyWidthRedundancy;
|
||
float thisEnemyDistance = Vector3.Distance(MyselfPosition, thisEnemyPosition);
|
||
|
||
//探测到Agent为自己时的处理
|
||
if (thisEnemyPosition == MyselfPosition)
|
||
{
|
||
//Debug.Log("OH It's me");
|
||
thisLDistanceList.Add(MaxDistance);
|
||
thisRDistanceList.Add(MaxDistance);
|
||
}
|
||
//非己Agent处理
|
||
else
|
||
{
|
||
EnemyIndex += 1;
|
||
Vector3 Vertical = new Vector3(0, 100, 0);//垂直向上的向量
|
||
Vector3 EnemytoMe = MyselfPosition - thisEnemyPosition;//Enemy和自机连线,指向自机的向量
|
||
Vector3 LHorizontal = Vector3.Cross(Vertical, EnemytoMe);// 垂直于EnemytoMe与Vertical向量所组成的面的,且指向<-左侧的小向量<- Enemy
|
||
Vector3 RHorizontal = Vector3.Cross(EnemytoMe, Vertical);// 垂直于EnemytoMe与Vertical向量所组成的面的,且指向->右侧的小向量Enemy ->
|
||
//此时RHorizontal,LHorizontal的长度巨几把长,需要下面操作标准化为1/2Enemy宽度
|
||
float standaedization = (float)thisEnemyWidth / Vector3.Distance(thisEnemyPosition, RHorizontal);//计算需要缩小的比例
|
||
RHorizontal *= standaedization;//应用缩小比例,标准化完成
|
||
LHorizontal *= standaedization;//应用缩小比例,标准化完成
|
||
Vector3 LMetoEnemy = LHorizontal - EnemytoMe;//自机与左侧边界连线Me<- Enemy
|
||
Vector3 RMetoEnemy = RHorizontal - EnemytoMe;//自机与右侧边界连线Enemy ->Me
|
||
Vector3 L0toEnemy = LHorizontal + thisEnemyPosition;// Enemy左侧绝对坐标
|
||
Vector3 R0toEnemy = RHorizontal + thisEnemyPosition;// Enemy右侧绝对坐标
|
||
float LMetoEnemyDist = Vector3.Distance(MyselfPosition, L0toEnemy);
|
||
float RMetoEnemyDist = Vector3.Distance(MyselfPosition, R0toEnemy);
|
||
Vector3 LEnemyInView = agentCam.WorldToViewportPoint(L0toEnemy);//Enemy左侧于视角中位置
|
||
Vector3 REnemyInView = agentCam.WorldToViewportPoint(R0toEnemy);//Enemy右侧于视角中位置
|
||
//Debug连线,颜色遵循飞机航行灯基本使用规则,左红右绿尾翼白。
|
||
//Debug.DrawRay(thisEnemyPosition, EnemytoMe, Color.white);//Enemy和自机连线,指向自机的向量
|
||
//Debug.DrawRay(thisEnemyPosition, Vertical, Color.white);//垂直向上的向量
|
||
//Debug.DrawRay(thisEnemyPosition, LHorizontal, Color.red);// 垂直于Vc与Vertical向量所组成的面的,且指向<-左侧的小向量<- Enemy
|
||
//Debug.DrawRay(thisEnemyPosition, RHorizontal, Color.green);// 垂直于Vc与Vertical向量所组成的面的,且指向->右侧的小向量Enemy ->
|
||
//Debug.DrawRay(MyselfPosition, LMetoEnemy, Color.red);//自机与左侧边界连线<- Enemy
|
||
//Debug.DrawRay(MyselfPosition, RMetoEnemy, Color.green);//自机与右侧边界连线Enemy ->
|
||
//Debug.Log("EnemyObj" + EnemyIndex + "Position:" + thisEnemyPosition);
|
||
|
||
|
||
//左侧于可见范围内--<--<--<--<--<--<--<--<--<--<--<--<--<--<
|
||
if (LEnemyInView.x >= (thisEnemyWidth - attentionRange / 2) && LEnemyInView.x <= (thisEnemyWidth + attentionRange / 2) && LEnemyInView.z > 0)
|
||
{
|
||
//射出Raycast
|
||
Ray LRay = new Ray(MyselfPosition, LMetoEnemy);
|
||
RaycastHit LHit;
|
||
if (showEnemySensor)
|
||
{
|
||
Debug.DrawRay(LRay.origin, LRay.direction * LMetoEnemyDist, Color.white);//自机与左侧边界连线<- Enemy
|
||
}
|
||
//Ray Hit Something
|
||
if (Physics.Raycast(MyselfPosition, LMetoEnemy, out LHit, LMetoEnemyDist))
|
||
{
|
||
//Ray Hit Enemy
|
||
//并且当射线射到的Enemy的距离与当前判断Enemy的距离差小于该Enemy半径时
|
||
//既该射线所射到的Enemy为当前Enemy而不是别的时
|
||
if (LHit.collider.tag == EnemyTagName && System.Math.Abs(LHit.distance - thisEnemyDistance) <= thisEnemyWidth)
|
||
{
|
||
if (showEnemySensor)
|
||
{
|
||
Debug.DrawRay(LRay.origin, LRay.direction * LHit.distance, Color.red);//自机与所击中物体的连线
|
||
}
|
||
thisLDistanceList.Add(LHit.distance);
|
||
//Debug.Log("Hit Tag = " + LHit.collider.tag);
|
||
//Debug.Log(LDistance[EnemyIndex-1]);
|
||
//Debug.Log("ADD_LIST_ENEMYL");
|
||
}
|
||
//当射线所hit的不是enemy或hit的enemy不是当前所判断的enemy
|
||
else
|
||
{
|
||
if (showEnemySensor)
|
||
{
|
||
Debug.DrawRay(LRay.origin, LRay.direction * LHit.distance, Color.cyan);//自机与所击中物体的连线
|
||
}
|
||
thisLDistanceList.Add(MaxDistance);
|
||
//Debug.LogWarning("Hit Tag = " + LHit.collider.tag);
|
||
//Debug.LogWarning(LDistance[EnemyIndex-1]);
|
||
//Debug.Log("ADD_LIST_ENEMYL");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
thisLDistanceList.Add(MaxDistance);
|
||
Debug.LogError("LRAY HIT NOTHING, Check Code!");
|
||
}
|
||
}
|
||
//左侧不在可见范围内时--<--<--<--<--<--<--<--<--<--<--<--<--<--<
|
||
else
|
||
{
|
||
thisLDistanceList.Add(MaxDistance);
|
||
//Debug.LogError("NoVisual");
|
||
//Debug.LogError(LDistance[EnemyIndex-1]);
|
||
//Debug.Log("ADD_LIST_ENEMYL_ELSE");
|
||
}
|
||
|
||
//右侧于可见范围内-->-->-->-->-->-->-->-->-->-->-->-->-->-->
|
||
if (REnemyInView.x >= (thisEnemyWidth - attentionRange / 2) && REnemyInView.x <= (thisEnemyWidth + attentionRange / 2) && REnemyInView.z > 0)
|
||
{
|
||
//射出Raycast
|
||
Ray RRay = new Ray(MyselfPosition, RMetoEnemy);
|
||
RaycastHit RHit;
|
||
if (showEnemySensor)
|
||
{
|
||
Debug.DrawRay(RRay.origin, RRay.direction * RMetoEnemyDist, Color.white);//自机与左侧边界连线<- Enemy
|
||
}
|
||
//Ray Hit Something
|
||
if (Physics.Raycast(MyselfPosition, RMetoEnemy, out RHit, RMetoEnemyDist))
|
||
{
|
||
//Ray Hit Enemy
|
||
//并且当射线射到的Enemy的距离与当前判断Enemy的距离差小于该Enemy半径时
|
||
//既该射线所射到的Enemy为当前Enemy而不是别的时
|
||
if (RHit.collider.tag == EnemyTagName && System.Math.Abs(RHit.distance - thisEnemyDistance) <= thisEnemyWidth)
|
||
{
|
||
if (showEnemySensor)
|
||
{
|
||
Debug.DrawRay(RRay.origin, RRay.direction * RHit.distance, Color.red);//自机与所击中物体的连线
|
||
}
|
||
thisRDistanceList.Add(RHit.distance);
|
||
//Debug.Log("Hit Tag = " + LHit.collider.tag);
|
||
//Debug.Log(LDistance[EnemyIndex-1]);
|
||
//Debug.Log("ADD_LIST_ENEMYR");
|
||
}
|
||
//当射线所hit的不是enemy或hit的enemy不是当前所判断的enemy
|
||
else
|
||
{
|
||
if (showEnemySensor)
|
||
{
|
||
Debug.DrawRay(RRay.origin, RRay.direction * RHit.distance, Color.cyan);//自机与所击中物体的连线
|
||
}
|
||
thisRDistanceList.Add(MaxDistance);
|
||
//Debug.LogWarning("Hit Tag = " + LHit.collider.tag);
|
||
//Debug.LogWarning(LDistance[EnemyIndex-1]);
|
||
//Debug.Log("ADD_LIST_ENEMYR");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
thisLDistanceList.Add(MaxDistance);
|
||
Debug.LogError("RRAY HIT NOTHING, Check Code!");
|
||
}
|
||
}
|
||
//右侧不在可见范围内时-->-->-->-->-->-->-->-->-->-->-->-->-->-->
|
||
else
|
||
{
|
||
thisRDistanceList.Add(MaxDistance);
|
||
//Debug.LogError("NoVisual");
|
||
//Debug.LogError(LDistance[EnemyIndex-1]);
|
||
//Debug.Log("ADD_LIST_ENEMYR_ELSE");
|
||
}
|
||
}
|
||
//Debug.LogWarning("EnemyIndex" + EnemyIndex);
|
||
//Debug.LogWarning(thisLDistanceList.Count);
|
||
//Debug.LogWarning(MinEnemyIndex);
|
||
//Debug.Log("thisLDistanceList" + thisLDistanceList.Count);
|
||
//Debug.Log("thisRDistanceList" + thisRDistanceList.Count);
|
||
|
||
//检查最近Enemy
|
||
if (System.Math.Min(thisLDistanceList[EnemyIndex], thisRDistanceList[EnemyIndex]) < MinEnemyDis)
|
||
{
|
||
//Debug.Log("EnemyIndex" + EnemyIndex);
|
||
MinEnemyDis = System.Math.Min(thisLDistanceList[EnemyIndex], thisRDistanceList[EnemyIndex]);
|
||
MinEnemyIndex = EnemyIndex;
|
||
}
|
||
}
|
||
// 获取最近敌人的准确位置信息
|
||
MinEnemyInfo[0] = (float)MinEnemyIndex;
|
||
if(MinEnemyInfo[0] <= 0)
|
||
{
|
||
MinEnemyInfo[1] = MaxDistance;
|
||
MinEnemyInfo[2] = MaxDistance;
|
||
}
|
||
else
|
||
{
|
||
MinEnemyInfo[1] = EnemyGameObjs[MinEnemyIndex].transform.position.x;
|
||
MinEnemyInfo[2] = EnemyGameObjs[MinEnemyIndex].transform.position.z;
|
||
}
|
||
return (EnemyIndex, thisLDistanceList, thisRDistanceList,MinEnemyInfo);
|
||
}
|
||
|
||
|
||
// 全局Ray探测处理
|
||
(float[], float[]) eyeSensorRay(int rayNum, Camera agentCam, float viewDistance)
|
||
{
|
||
//初始化result Array
|
||
float[] thisRayTagResult = new float[rayNum];
|
||
float[] thisRayDisResult = new float[rayNum];
|
||
|
||
//于视角范围内一帧射出rayNum条射线
|
||
for (int a = 0; a <= rayNum - 1; a = a + 1)
|
||
{
|
||
//射线射出
|
||
Vector3 point = new Vector3(a * agentCam.pixelWidth / (rayNum - 1), agentCam.pixelHeight / 2, 0);//发射位置
|
||
Ray ray = agentCam.ScreenPointToRay(point);
|
||
RaycastHit hit;
|
||
if (showEyeSensor)
|
||
{
|
||
Debug.DrawRay(ray.origin, ray.direction * viewDistance, Color.black);
|
||
}
|
||
//若在viewDistance范围内有碰撞
|
||
if (Physics.Raycast(ray, out hit, viewDistance))
|
||
{
|
||
thisRayTagResult[a] = tagToInt(hit.collider.tag);
|
||
thisRayDisResult[a] = hit.distance;
|
||
if (showEyeSensor)
|
||
{
|
||
Debug.DrawRay(ray.origin, ray.direction * hit.distance, Color.yellow);
|
||
}
|
||
//输出log
|
||
//Debug.Log(rayTagResult[a]);
|
||
//Debug.Log(tagToInt(hit.collider.tag));
|
||
|
||
}
|
||
//若在viewDistance范围无碰撞
|
||
else
|
||
{
|
||
thisRayTagResult[a] = -1f;
|
||
thisRayDisResult[a] = -1f;
|
||
//输出log
|
||
//Debug.Log(0);
|
||
//Debug.Log(0);
|
||
}
|
||
}
|
||
return (thisRayTagResult, thisRayDisResult);
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
rayTagResult = new float[rayNum];
|
||
rayDisResult = new float[rayNum];
|
||
}
|
||
|
||
|
||
|
||
void Update()
|
||
{
|
||
(rayTagResult, rayDisResult) = eyeSensorRay(rayNum, agentCam, viewDistance);
|
||
(allEnemyNum, enemyLDisList, enemyRDisList, focusEnemyInfo) = enemySensorRay(myself, agentCam, attentionRange);
|
||
transform.gameObject.GetComponent<UIController>().updateRemainEnemy(allEnemyNum);
|
||
/*
|
||
Debug.LogWarning("rayNum :" + rayNum);
|
||
for (int i =0;i < rayNum; i++)
|
||
{
|
||
Debug.Log("rayTagResult" + rayTagResult[i] + "rayDisResult"+ rayDisResult[i]);
|
||
}
|
||
Debug.LogWarning("EnemyNum Include Me:" + allEnemyNum);
|
||
for(int i = 0; i < allEnemyNum; i++)
|
||
{
|
||
Debug.Log("enemyLDisList" + enemyLDisList[i] + "enemyRDisList" + enemyRDisList[i]);
|
||
}
|
||
*/
|
||
}
|
||
}
|