WX-Game1/Assets/Zion/Scripts/CameraOcclusionDetector.cs

99 lines
3.8 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraOcclusionDetector : MonoBehaviour
{
public Transform player; // 主角的Transform
public LayerMask obstacleLayer; // 障碍物层例如Default, Environment
public List<GameObject> objectsToCheck; // 要检测是否被遮挡的物体列表
public List<GameObject> OldhitObject=new List<GameObject>(); // 碰撞体的GameObject
public Vector3 Offset; // 偏移量,用于修正碰撞体的位置
public Vector3 OffsetCamera; // 偏移量,用于修正碰撞体的位置
public float minDistance = 1.5f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
foreach (var obj in objectsToCheck)
{
bool isOvvluded = IsPlayerOccluded(obj);
//Debug.Log(obj.name + "是否被遮挡:" + isOvvluded);
if (isOvvluded)
{
obj.SetActive(false);
if (!OldhitObject.Contains(obj))
OldhitObject.Add(obj);
}
}
if (OldhitObject.Count > 0)
{
// 恢复之前被遮挡但现在可见的物体
for (int i = OldhitObject.Count - 1; i >= 0; i--)
{
float distance = GetDistanceToPlayer(OldhitObject[i]);
//Debug.Log("距离:" + OldhitObject[i] + "距离:" + distance);
if (distance > minDistance)
{
OldhitObject[i].SetActive(true);
//OldhitObject.RemoveAt(i);
}
}
}
}
/// <summary>
/// 判断是否有物体遮挡了 "摄像机 -> 主角" 的视线
/// </summary>
/// <returns>被遮挡返回 true视野清晰返回 false</returns>
public bool IsPlayerOccluded(GameObject obj)
{
// 计算从主角指向摄像机的方向
Vector3 _player = player.position + Offset;
Vector3 _camera = transform.position + OffsetCamera;
Vector3 directionToCamera = _camera - _player;
float distance = directionToCamera.magnitude;
// 从主角向摄像机发射射线,并渲染射线
//Debug.DrawRay(_player, directionToCamera.normalized * distance, Color.red);
// 关键点:从主角向摄像机发射射线
if (Physics.Raycast(player.position, directionToCamera.normalized, out RaycastHit hit, distance, obstacleLayer))
{
// 1. 如果射线击中的距离非常近(几乎在主角身上),可能是主角自身的碰撞体,视为无遮挡
// 2. 如果射线击中了非主角物体(距离正常),则是被遮挡了
// 定义一个极小的距离阈值,用于忽略主角自身的碰撞体
float minDistance = 0.1f;
//Debug.Log("被遮挡了!击中物体:" + hit.collider.name + ",距离:" + hit.distance);
if (hit.distance > minDistance && obj == hit.transform.gameObject)
{
//Debug.Log("被遮挡了!击中物体:" + hit.collider.name + ",距离:" + hit.distance);
//hitObject= hit.transform.gameObject; // 记录碰撞体的GameObject
return true; // 视野被遮挡
}
}
//Debug.Log("视野清晰");
return false; // 视野未被遮挡
}
/// <summary>
/// 返回指定物体到玩家的距离
/// </summary>
/// <param name="obj">要检测距离的物体</param>
/// <returns>物体到玩家的距离</returns>
public float GetDistanceToPlayer(GameObject obj)
{
Vector3 objPosition = obj.transform.position;
Vector3 playerPosition = player.position;
return Vector3.Distance(objPosition, playerPosition);
}
}