using System; using System.Collections.Generic; using UnityEngine; /*该scrip用于创建复数条ray于视角内,并探测被ray射到的物体*/ public class RaySensors : MonoBehaviour { [SerializeField] private Camera agentCam; [SerializeField] private Camera TPSCam; [SerializeField] private Material lineMeterial; [SerializeField] private GameObject rayInfoPrefab; [SerializeField] private GameObject agentCanvas; [SerializeField, Range(0, 500)] public float viewDistance = 100; // how long the ray can detect //[SerializeField, Range(0, 1)] public float totalRange = 1f; // Total view range Max = 1 [SerializeField, Range(0, 1)] public float focusRange = 0.15f; // center focus range public int halfOuterRayNum = 7; // >=2 public int focusRayNum = 5; // >= 1 and must be odd num! [Header("InGameLineSetting")] public bool showInGameRay = true; public bool showDebugRay = true; public bool showInGameRayInfo = true; public float lineWidth = 0.05f; [Header("RayCastResult")] public float[] rayTagResult; public float[] rayTagResultOneHot; public float[] rayDisResult; [System.NonSerialized] public int totalRayNum; private string myTag = ""; private GameObject[] linesOBJ; private GameObject[] rayInfoOBJ; private LineRenderer[] lineRenderers; private RayInfoUI[] rayInfoUIs; public List inViewEnemies = new List(); private List tags = new List { "Wall", "Enemy" }; private Onehot oneHotTags = new Onehot(); private void Start() { myTag = gameObject.tag; totalRayNum = halfOuterRayNum * 2 + focusRayNum; rayTagResult = new float[totalRayNum]; rayDisResult = new float[totalRayNum]; rayTagResultOneHot = new float[totalRayNum*ObjectTags.Tags.Count]; linesOBJ = new GameObject[totalRayNum]; lineRenderers = new LineRenderer[totalRayNum]; rayInfoOBJ = new GameObject[totalRayNum]; rayInfoUIs = new RayInfoUI[totalRayNum]; oneHotTags.Initialize(tags); for (int i = 0; i < totalRayNum; i++) { linesOBJ[i] = new GameObject(); linesOBJ[i].name = "rayCastLine-" + Convert.ToString(i); linesOBJ[i].transform.parent = agentCam.transform; linesOBJ[i].AddComponent(); lineRenderers[i] = linesOBJ[i].GetComponent(); lineRenderers[i].material = lineMeterial; rayInfoOBJ[i] = (GameObject)Instantiate(rayInfoPrefab); rayInfoOBJ[i].transform.SetParent(agentCanvas.transform, false); rayInfoOBJ[i].name = "rayInfo-" + Convert.ToString(i); rayInfoUIs[i] = rayInfoOBJ[i].GetComponent(); } } private void SingleRaycastUpdate(Ray ray,int rayIndex) { // get Raycast hit infomation and return Tag and distance RaycastHit nowHit; Color rayColor = Color.gray; float lineLength = viewDistance; string rayInfoText = ""; Vector3 rayInfoPosition; if (Physics.Raycast(ray, out nowHit, viewDistance)) // 若在viewDistance范围内有碰撞 { // Tag string thisTag = nowHit.collider.tag; // result update rayTagResult[rayIndex] = ObjectTags.TagToInt(thisTag); rayDisResult[rayIndex] = nowHit.distance; int oneHotIndex = rayIndex * ObjectTags.Tags.Count + ObjectTags.TagToInt(thisTag); rayTagResultOneHot[oneHotIndex] = 1f; if (rayTagResult[rayIndex] == ObjectTags.TagToInt("Enemy")) { inViewEnemies.Add(nowHit.transform.gameObject); } // ingame info update lineLength = nowHit.distance; rayInfoText = thisTag + "\n" + Convert.ToString(nowHit.distance); rayColor = ObjectTags.TagToCololr(thisTag); } else // 若在viewDistance范围无碰撞 { // Result update // rayTagResultOneHot keep zero rayTagResult[rayIndex] = -1; rayDisResult[rayIndex] = -1; // Info rayInfoText = "Empty"; } // draw Info In Game rayInfoPosition = ray.origin + (ray.direction * lineLength); if (showInGameRay) { DrawLine(ray, lineLength, lineRenderers[rayIndex], rayColor); } else { TurnOffLine(lineRenderers[rayIndex], rayColor); } // drawRay in game if (showInGameRayInfo) rayInfoUIs[rayIndex].UpdateInfo(rayInfoText, rayInfoPosition, rayColor, TPSCam); // Show log if (showDebugRay) Debug.DrawRay(ray.origin, ray.direction * viewDistance, rayColor); // drawRay in debug // Debug.Log(ray.origin + ray.direction); // Debug.Log(thisRayTagResult); // Debug.Log(tagToInt(nowHit.collider.thisTag)); } private void DrawLine(Ray ray, float lineLength, LineRenderer lineRenderer, Color lineColor) { lineRenderer.startColor = lineColor; lineRenderer.endColor = lineColor; lineRenderer.startWidth = lineWidth; lineRenderer.endWidth = lineWidth; lineRenderer.SetPosition(0, ray.origin); lineRenderer.SetPosition(1, ray.origin + (ray.direction * lineLength)); } private void TurnOffLine(LineRenderer lineRenderer, Color lineColor) { lineRenderer.startColor = lineColor; lineRenderer.endColor = lineColor; lineRenderer.startWidth = 0f; lineRenderer.endWidth = 0f; lineRenderer.SetPosition(0, new Vector3(0, 0, 0)); lineRenderer.SetPosition(1, new Vector3(0, 0, 0)); } public void UpdateRayInfo() { float focusLEdge = agentCam.pixelWidth * (1 - focusRange) / 2; float focusREdge = agentCam.pixelWidth * (1 + focusRange) / 2; float camPixelHeight = agentCam.pixelHeight; inViewEnemies.Clear(); ClearResult(); for (int i = 0; i < halfOuterRayNum; i++) // create left outside rays; 0 ~ focusLeftEdge { Vector3 point = new Vector3(i * focusLEdge / (halfOuterRayNum - 1), camPixelHeight / 2, 0); Ray nowRay = agentCam.ScreenPointToRay(point); SingleRaycastUpdate(nowRay,i); } for (int i = 0; i < halfOuterRayNum; i++) // create right outside rays; focusRightEdge ~ MaxPixelHeight { Vector3 point = new Vector3(focusREdge + (i * focusLEdge / (halfOuterRayNum - 1)), camPixelHeight / 2, 0); Ray nowRay = agentCam.ScreenPointToRay(point); SingleRaycastUpdate(nowRay, halfOuterRayNum + i); } for (int i = 0; i < focusRayNum; i++) // create center focus rays; focusLeftEdge ~ focusLeftEdge { Vector3 point = new Vector3(focusLEdge + ((i + 1) * (focusREdge - focusLEdge) / (focusRayNum + 1)), camPixelHeight / 2, 0); Ray nowRay = agentCam.ScreenPointToRay(point); SingleRaycastUpdate(nowRay, halfOuterRayNum * 2 + i); } } private void ClearResult() { rayTagResult = new float[totalRayNum]; rayDisResult = new float[totalRayNum]; rayTagResultOneHot = new float[totalRayNum * ObjectTags.Tags.Count]; } }