using UnityEngine;
namespace Colosseum.Player
{
///
/// 보스가 플레이어를 가릴 때 플레이어 외곽선을 표시하는 컨트롤러
///
public class PlayerOcclusionOutline : MonoBehaviour
{
[Header("Settings")]
[Min(0.001f)] [SerializeField] private float outlineWidth = 0.02f;
[SerializeField] private Color outlineColor = Color.white;
[Min(0.01f)] [SerializeField] private float checkRadius = 0.3f;
private Transform cameraTransform;
private Transform playerTransform;
private SkinnedMeshRenderer originalRenderer;
private GameObject outlineHost;
private SkinnedMeshRenderer outlineRenderer;
private Material outlineMaterial;
private bool isShowingOutline;
public void Initialize(Transform camera, Transform player)
{
cameraTransform = camera;
playerTransform = player;
originalRenderer = player.GetComponentInChildren();
if (originalRenderer == null) return;
var shader = Shader.Find("Hidden/Colosseum/Outline");
if (shader == null)
{
Debug.LogError("[PlayerOcclusionOutline] Shader 'Hidden/Colosseum/Outline' not found");
return;
}
outlineMaterial = new Material(shader);
outlineMaterial.SetFloat("_OutlineWidth", outlineWidth);
outlineMaterial.SetColor("_OutlineColor", outlineColor);
if (originalRenderer.sharedMesh == null)
{
Debug.LogError("[PlayerOcclusionOutline] originalRenderer has no sharedMesh");
return;
}
outlineHost = new GameObject("OutlineRenderer");
outlineHost.transform.SetParent(originalRenderer.transform, false);
outlineRenderer = outlineHost.AddComponent();
outlineRenderer.sharedMesh = originalRenderer.sharedMesh;
outlineRenderer.bones = originalRenderer.bones;
outlineRenderer.rootBone = originalRenderer.rootBone;
outlineRenderer.sharedMaterials = new[] { outlineMaterial };
outlineRenderer.updateWhenOffscreen = true;
outlineRenderer.enabled = false;
Debug.Log($"[PlayerOcclusionOutline] Initialize: outlineRenderer on child {outlineHost.name}");
}
private void LateUpdate()
{
if (cameraTransform == null || playerTransform == null || outlineRenderer == null)
return;
outlineMaterial.SetFloat("_OutlineWidth", outlineWidth);
outlineMaterial.SetColor("_OutlineColor", outlineColor);
bool isOccluded = CheckBossOcclusion();
if (isOccluded && !isShowingOutline)
{
outlineRenderer.enabled = true;
isShowingOutline = true;
}
else if (!isOccluded && isShowingOutline)
{
outlineRenderer.enabled = false;
isShowingOutline = false;
}
}
private bool CheckBossOcclusion()
{
Vector3 origin = cameraTransform.position;
Vector3 direction = playerTransform.position - origin;
float distance = direction.magnitude;
if (distance < 0.01f) return false;
int enemyLayer = LayerMask.GetMask("Enemy");
if (Physics.SphereCast(origin, checkRadius, direction.normalized, out RaycastHit hit, distance, enemyLayer, QueryTriggerInteraction.Ignore))
{
return hit.collider.transform.IsChildOf(playerTransform) == false;
}
return false;
}
private void OnDestroy()
{
if (outlineHost != null)
Destroy(outlineHost);
if (outlineMaterial != null)
Destroy(outlineMaterial);
}
}
}