99 lines
3.8 KiB
C#
99 lines
3.8 KiB
C#
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);
|
||
}
|
||
}
|