Files
Colosseum/Assets/_Game/Scripts/Player/ObstacleTransparencyController.cs
dal4segno 60275c6cd9 feat: 보스 가림 시 플레이어 외곽선 표시
- PlayerOcclusionOutline: 보스(Enemy 레이어)가 플레이어를 가릴 때 외곽선 활성화
- Outline.shader: URP 법선 확장 외곽선 셰이더 (Fresnel 기반 알파)
- 외곽선용 별도 SkinnedMeshRenderer를 자식 GameObject에 생성
- ObstacleTransparencyController: Enemy 레이어 장애물 숨김 제외
- PlayerCamera: PlayerOcclusionOutline 초기화 연동

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-04 10:51:10 +09:00

108 lines
3.3 KiB
C#

using System.Collections.Generic;
using UnityEngine;
namespace Colosseum.Player
{
/// <summary>
/// 카메라와 타겟 사이의 장애물을 숨기는 컨트롤러
/// </summary>
public class ObstacleTransparencyController : MonoBehaviour
{
[Header("Occlusion Settings")]
[Min(0.01f)] [SerializeField] private float checkRadius = 0.3f;
private Transform cameraTransform;
private Transform targetTransform;
private LayerMask occlusionMask;
private readonly HashSet<Renderer> hiddenRenderers = new();
public void Initialize(Transform target, LayerMask mask)
{
cameraTransform = GetComponent<Camera>().transform;
targetTransform = target;
occlusionMask = mask;
}
private void LateUpdate()
{
if (cameraTransform == null || targetTransform == null) return;
Vector3 origin = cameraTransform.position;
Vector3 direction = targetTransform.position - origin;
float maxDistance = direction.magnitude;
if (maxDistance < 0.01f) return;
direction.Normalize();
HashSet<Renderer> currentHits = CollectHits(origin, direction, maxDistance);
foreach (Renderer renderer in currentHits)
{
if (!hiddenRenderers.Contains(renderer))
{
renderer.enabled = false;
hiddenRenderers.Add(renderer);
}
}
List<Renderer> toShow = null;
foreach (Renderer renderer in hiddenRenderers)
{
if (renderer == null || !currentHits.Contains(renderer))
{
if (renderer != null)
renderer.enabled = true;
(toShow ??= new List<Renderer>()).Add(renderer);
}
}
if (toShow != null)
{
foreach (Renderer renderer in toShow)
hiddenRenderers.Remove(renderer);
}
}
private HashSet<Renderer> CollectHits(Vector3 origin, Vector3 direction, float maxDistance)
{
var hits = new HashSet<Renderer>();
int enemyLayer = LayerMask.GetMask("Enemy");
int mask = occlusionMask & ~enemyLayer;
RaycastHit[] rayHits = Physics.SphereCastAll(origin, checkRadius, direction, maxDistance, mask, QueryTriggerInteraction.Ignore);
float targetY = targetTransform.position.y;
foreach (RaycastHit hit in rayHits)
{
if (hit.point.y <= targetY) continue;
Renderer renderer = hit.collider.GetComponent<Renderer>();
if (renderer == null) continue;
if (renderer is ParticleSystemRenderer || renderer is TrailRenderer) continue;
hits.Add(renderer);
}
return hits;
}
public void ClearHidden()
{
foreach (Renderer renderer in hiddenRenderers)
{
if (renderer != null)
renderer.enabled = true;
}
hiddenRenderers.Clear();
}
private void OnDestroy()
{
ClearHidden();
}
}
}