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 tagNames = new List(); 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 enemyLDisList = new List();// All Enemy Lside Distances public static List enemyRDisList = new List();// 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, List, float[]) enemySensorRay(GameObject myself, Camera agentCam, float attentionRange) { List thisLDistanceList = new List(); List thisRDistanceList = new List(); 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().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]); } */ } }