first commit
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
public class EnemyVisionVisualizer : MonoBehaviour
|
||||
{
|
||||
public EnemyVision vision;
|
||||
public EnemyStateMachine stateMachine;
|
||||
public Material visionMaterialTemplate;
|
||||
public int segmentCount = 28;
|
||||
public float groundOffset = 0.05f;
|
||||
|
||||
private Transform meshRoot;
|
||||
private MeshFilter meshFilter;
|
||||
private MeshRenderer meshRenderer;
|
||||
private Mesh visionMesh;
|
||||
private Material runtimeMaterial;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
vision = vision != null ? vision : GetComponent<EnemyVision>();
|
||||
stateMachine = stateMachine != null ? stateMachine : GetComponent<EnemyStateMachine>();
|
||||
EnsureMeshObjects();
|
||||
RebuildMesh();
|
||||
UpdateVisualState();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
EnsureMeshObjects();
|
||||
UpdateVisualState();
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
segmentCount = Mathf.Max(6, segmentCount);
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
EnsureMeshObjects();
|
||||
RebuildMesh();
|
||||
UpdateVisualState();
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureMeshObjects()
|
||||
{
|
||||
int visualizationLayer = LayerMask.NameToLayer("Vision");
|
||||
if (visualizationLayer < 0)
|
||||
{
|
||||
visualizationLayer = LayerMask.NameToLayer("Ignore Raycast");
|
||||
}
|
||||
|
||||
if (meshRoot == null)
|
||||
{
|
||||
Transform existing = transform.Find("VisionCone");
|
||||
if (existing != null)
|
||||
{
|
||||
meshRoot = existing;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject root = new GameObject("VisionCone");
|
||||
root.transform.SetParent(transform, false);
|
||||
root.transform.localPosition = new Vector3(0f, groundOffset, 0f);
|
||||
root.transform.localRotation = Quaternion.identity;
|
||||
root.layer = visualizationLayer;
|
||||
meshRoot = root.transform;
|
||||
}
|
||||
}
|
||||
|
||||
meshRoot.localPosition = new Vector3(0f, groundOffset, 0f);
|
||||
meshRoot.gameObject.layer = visualizationLayer;
|
||||
|
||||
if (meshFilter == null)
|
||||
{
|
||||
meshFilter = meshRoot.GetComponent<MeshFilter>();
|
||||
if (meshFilter == null)
|
||||
{
|
||||
meshFilter = meshRoot.gameObject.AddComponent<MeshFilter>();
|
||||
}
|
||||
}
|
||||
|
||||
if (meshRenderer == null)
|
||||
{
|
||||
meshRenderer = meshRoot.GetComponent<MeshRenderer>();
|
||||
if (meshRenderer == null)
|
||||
{
|
||||
meshRenderer = meshRoot.gameObject.AddComponent<MeshRenderer>();
|
||||
meshRenderer.shadowCastingMode = ShadowCastingMode.Off;
|
||||
meshRenderer.receiveShadows = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (visionMesh == null)
|
||||
{
|
||||
visionMesh = new Mesh { name = "EnemyVisionCone" };
|
||||
meshFilter.sharedMesh = visionMesh;
|
||||
}
|
||||
|
||||
if (runtimeMaterial == null)
|
||||
{
|
||||
runtimeMaterial = visionMaterialTemplate != null ? new Material(visionMaterialTemplate) : BuildTransparentMaterial();
|
||||
runtimeMaterial.name = "EnemyVisionRuntimeMaterial";
|
||||
meshRenderer.sharedMaterial = runtimeMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildMesh()
|
||||
{
|
||||
if (vision == null || visionMesh == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float radius = vision.viewRadius;
|
||||
float halfAngle = vision.viewAngle * 0.5f;
|
||||
|
||||
Vector3[] vertices = new Vector3[segmentCount + 2];
|
||||
int[] triangles = new int[segmentCount * 3];
|
||||
Vector2[] uv = new Vector2[vertices.Length];
|
||||
|
||||
vertices[0] = Vector3.zero;
|
||||
uv[0] = new Vector2(0.5f, 0f);
|
||||
|
||||
for (int i = 0; i <= segmentCount; i++)
|
||||
{
|
||||
float progress = i / (float)segmentCount;
|
||||
float angle = -halfAngle + progress * vision.viewAngle;
|
||||
float radians = Mathf.Deg2Rad * angle;
|
||||
Vector3 direction = new Vector3(Mathf.Sin(radians), 0f, Mathf.Cos(radians));
|
||||
vertices[i + 1] = direction * radius;
|
||||
uv[i + 1] = new Vector2(progress, 1f);
|
||||
|
||||
if (i == segmentCount)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int triangleIndex = i * 3;
|
||||
triangles[triangleIndex] = 0;
|
||||
triangles[triangleIndex + 1] = i + 2;
|
||||
triangles[triangleIndex + 2] = i + 1;
|
||||
}
|
||||
|
||||
visionMesh.Clear();
|
||||
visionMesh.vertices = vertices;
|
||||
visionMesh.triangles = triangles;
|
||||
visionMesh.uv = uv;
|
||||
visionMesh.RecalculateNormals();
|
||||
visionMesh.RecalculateBounds();
|
||||
}
|
||||
|
||||
private void UpdateVisualState()
|
||||
{
|
||||
if (runtimeMaterial == null || stateMachine == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Color stateColor = new Color(0.2f, 0.95f, 0.35f, 0.22f);
|
||||
switch (stateMachine.CurrentState)
|
||||
{
|
||||
case EnemyStateMachine.State.Suspicion:
|
||||
stateColor = new Color(1f, 0.85f, 0.2f, 0.24f);
|
||||
break;
|
||||
case EnemyStateMachine.State.Alert:
|
||||
stateColor = new Color(1f, 0.25f, 0.2f, 0.28f);
|
||||
break;
|
||||
}
|
||||
|
||||
runtimeMaterial.color = stateColor;
|
||||
if (runtimeMaterial.HasProperty("_Color"))
|
||||
{
|
||||
runtimeMaterial.SetColor("_Color", stateColor);
|
||||
}
|
||||
}
|
||||
|
||||
private Material BuildTransparentMaterial()
|
||||
{
|
||||
Shader shader = Shader.Find("Standard");
|
||||
Material material = new Material(shader);
|
||||
material.SetFloat("_Mode", 3f);
|
||||
material.SetInt("_SrcBlend", (int)BlendMode.SrcAlpha);
|
||||
material.SetInt("_DstBlend", (int)BlendMode.OneMinusSrcAlpha);
|
||||
material.SetInt("_ZWrite", 0);
|
||||
material.DisableKeyword("_ALPHATEST_ON");
|
||||
material.EnableKeyword("_ALPHABLEND_ON");
|
||||
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
||||
material.renderQueue = (int)RenderQueue.Transparent;
|
||||
material.color = new Color(0.2f, 0.95f, 0.35f, 0.22f);
|
||||
return material;
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
if (vision == null)
|
||||
{
|
||||
vision = GetComponent<EnemyVision>();
|
||||
}
|
||||
|
||||
if (vision == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Gizmos.color = Color.cyan;
|
||||
Vector3 origin = transform.position + Vector3.up * 0.1f;
|
||||
Gizmos.DrawWireSphere(origin, vision.viewRadius);
|
||||
|
||||
Quaternion leftRotation = Quaternion.Euler(0f, -vision.viewAngle * 0.5f, 0f);
|
||||
Quaternion rightRotation = Quaternion.Euler(0f, vision.viewAngle * 0.5f, 0f);
|
||||
Gizmos.DrawLine(origin, origin + leftRotation * transform.forward * vision.viewRadius);
|
||||
Gizmos.DrawLine(origin, origin + rightRotation * transform.forward * vision.viewRadius);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user