- ToonPostProcess.shader: 횃불 고딕 스타일 후처리 쉐이더 (Built-in RP) - ToonCameraEffect.cs: 카메라 자동 부착 후처리 스크립트 - 중복 UI 스크립트 제거 (MenuIntroController, ToggleCustom) - 씬, 프리팹, 애니메이션 등 전체 업데이트 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
157 lines
8.0 KiB
C#
157 lines
8.0 KiB
C#
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
|
|
using UnityEngine.UI; // UI 기능을 불러올거에요 -> Image 컴포넌트를
|
|
|
|
// ============================================================
|
|
// CrosshairCursor — 마우스 커서 위치에 크로스헤어 이미지를 실시간 표시
|
|
//
|
|
// [셋업 방법]
|
|
// ① Canvas (Screen Space - Overlay 권장) 아래에 빈 오브젝트 생성
|
|
// ② Image 컴포넌트 추가 → 크로스헤어 스프라이트 할당
|
|
// (Raycast Target 체크 해제! → 클릭이 크로스헤어에 막히지 않도록)
|
|
// ③ 이 스크립트를 같은 오브젝트에 추가
|
|
// ④ Inspector에서 crosshairImage에 방금 추가한 Image를 드래그
|
|
//
|
|
// [기능]
|
|
// - 시스템 마우스 커서 숨기고 크로스헤어 이미지로 대체
|
|
// - 차징 중 크기가 점점 커짐 (진행률에 비례)
|
|
// - 차징 중 색상이 단계별로 변화 (흰색 → 주황 → 빨강)
|
|
// - 포커스 잃으면 시스템 커서 복원 (에디터 편의)
|
|
// ============================================================
|
|
|
|
public class CrosshairCursor : MonoBehaviour // 클래스를 선언할거에요 -> 크로스헤어 커서를 관리하는
|
|
{
|
|
[Header("--- 크로스헤어 이미지 ---")]
|
|
[SerializeField] private Image crosshairImage; // 변수를 선언할거에요 -> 크로스헤어 Image 컴포넌트를
|
|
|
|
[Header("--- 크기 설정 ---")]
|
|
[SerializeField] private float baseSize = 40f; // 변수를 선언할거에요 -> 기본 크기(픽셀)를
|
|
[SerializeField] private float maxChargeSize = 70f; // 변수를 선언할거에요 -> 풀차징 시 최대 크기를
|
|
|
|
[Header("--- 색상 설정 ---")]
|
|
[SerializeField] private Color normalColor = Color.white; // 변수를 선언할거에요 -> 기본 상태 색상을
|
|
[SerializeField] private Color chargingColor = new Color(1f, 0.6f, 0f, 1f); // 변수를 선언할거에요 -> 차징 중간 색상(주황)을
|
|
[SerializeField] private Color maxChargeColor = new Color(1f, 0.2f, 0f, 1f); // 변수를 선언할거에요 -> 풀차징 색상(빨강)을
|
|
|
|
[Header("--- 시스템 커서 ---")]
|
|
[SerializeField] private bool hideSystemCursor = true; // 변수를 선언할거에요 -> 시스템 커서 숨김 여부를
|
|
|
|
[Header("--- 참조 (비워두면 자동 탐색) ---")]
|
|
[SerializeField] private PlayerAttack playerAttack; // 변수를 선언할거에요 -> 차징 상태 확인용 공격 스크립트를
|
|
|
|
private RectTransform _rect; // 변수를 선언할거에요 -> 크로스헤어 RectTransform을
|
|
private Canvas _canvas; // 변수를 선언할거에요 -> 부모 Canvas를
|
|
|
|
// ── 초기화 ──────────────────────────────────────────────
|
|
|
|
private void Awake() // 함수를 실행할거에요 -> 초기화를
|
|
{
|
|
if (crosshairImage != null) // 조건이 맞으면 실행할거에요 -> 이미지가 있다면
|
|
{
|
|
_rect = crosshairImage.GetComponent<RectTransform>(); // 가져올거에요 -> RectTransform을
|
|
_canvas = crosshairImage.GetComponentInParent<Canvas>(); // 가져올거에요 -> 부모 Canvas를
|
|
|
|
// 초기 크기 설정
|
|
_rect.sizeDelta = new Vector2(baseSize, baseSize); // 설정할거에요 -> 기본 크기를
|
|
|
|
// Raycast Target 꺼두기 (크로스헤어가 클릭을 가로채지 않도록)
|
|
crosshairImage.raycastTarget = false; // 끌거에요 -> 레이캐스트 타겟을
|
|
}
|
|
}
|
|
|
|
private void Start() // 함수를 실행할거에요 -> 시작 시
|
|
{
|
|
if (hideSystemCursor) Cursor.visible = false; // 숨길거에요 -> 시스템 커서를
|
|
|
|
// 자동 탐색
|
|
if (playerAttack == null) // 조건이 맞으면 실행할거에요 -> 참조가 비어있다면
|
|
playerAttack = FindObjectOfType<PlayerAttack>(); // 찾을거에요 -> 씬에서 PlayerAttack을
|
|
}
|
|
|
|
// ── 매 프레임 갱신 ──────────────────────────────────────
|
|
|
|
private void Update() // 함수를 실행할거에요 -> 매 프레임
|
|
{
|
|
if (crosshairImage == null || _rect == null) return; // 중단할거에요 -> 이미지 없으면
|
|
|
|
// 1. 마우스 위치로 이동
|
|
MoveToMouse(); // 실행할거에요 -> 위치 갱신을
|
|
|
|
// 2. 차징 시각 피드백
|
|
UpdateChargeFeedback(); // 실행할거에요 -> 크기/색상 갱신을
|
|
}
|
|
|
|
// ── 위치 이동 ──────────────────────────────────────────
|
|
|
|
private void MoveToMouse() // 함수를 선언할거에요 -> 크로스헤어를 마우스 위치로 이동하는
|
|
{
|
|
if (_canvas == null) return; // 중단할거에요 -> 캔버스 없으면
|
|
|
|
if (_canvas.renderMode == RenderMode.ScreenSpaceOverlay) // Overlay 모드
|
|
{
|
|
// Overlay: 스크린 좌표 그대로 사용
|
|
_rect.position = Input.mousePosition; // 이동할거에요 -> 마우스 위치로
|
|
}
|
|
else // Camera / World Space 모드
|
|
{
|
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
|
_canvas.transform as RectTransform,
|
|
Input.mousePosition,
|
|
_canvas.worldCamera,
|
|
out Vector2 localPos
|
|
); // 변환할거에요 -> 스크린→캔버스 로컬 좌표로
|
|
_rect.localPosition = localPos; // 이동할거에요 -> 변환된 위치로
|
|
}
|
|
}
|
|
|
|
// ── 차징 시각 피드백 (크기 + 색상) ──────────────────────
|
|
|
|
private void UpdateChargeFeedback() // 함수를 선언할거에요 -> 차징 피드백을 갱신하는
|
|
{
|
|
bool charging = (playerAttack != null && playerAttack.IsCharging); // 판단할거에요 -> 차징 중인지
|
|
|
|
if (charging) // 차징 중이면
|
|
{
|
|
float progress = playerAttack.ChargeProgress; // 가져올거에요 -> 진행률(0~1)을
|
|
|
|
// ── 크기 보간 ──
|
|
float size = Mathf.Lerp(baseSize, maxChargeSize, progress); // 보간할거에요 -> 진행률에 따른 크기를
|
|
_rect.sizeDelta = new Vector2(size, size); // 적용할거에요 -> 크기를
|
|
|
|
// ── 색상 보간 (2단 그라데이션) ──
|
|
Color color;
|
|
if (progress < 0.5f) // 전반부
|
|
color = Color.Lerp(normalColor, chargingColor, progress * 2f); // 흰색 → 주황
|
|
else // 후반부
|
|
color = Color.Lerp(chargingColor, maxChargeColor, (progress - 0.5f) * 2f); // 주황 → 빨강
|
|
|
|
crosshairImage.color = color; // 적용할거에요 -> 색상을
|
|
}
|
|
else // 차징 아닐 때
|
|
{
|
|
_rect.sizeDelta = new Vector2(baseSize, baseSize); // 복원할거에요 -> 기본 크기로
|
|
crosshairImage.color = normalColor; // 복원할거에요 -> 기본 색상으로
|
|
}
|
|
}
|
|
|
|
// ── 포커스/비활성화 시 커서 복원 ─────────────────────────
|
|
|
|
private void OnDisable() // 함수를 실행할거에요 -> 비활성화 시
|
|
{
|
|
Cursor.visible = true; // 복원할거에요 -> 시스템 커서를 (에디터/게임 종료 시 안전장치)
|
|
}
|
|
|
|
private void OnApplicationFocus(bool hasFocus) // 함수를 실행할거에요 -> 창 포커스 변경 시
|
|
{
|
|
if (hideSystemCursor) // 커서 숨김 모드라면
|
|
Cursor.visible = !hasFocus; // 포커스 잃으면 보이게, 돌아오면 숨기게
|
|
}
|
|
|
|
// ── 외부 연결 API (DungeonSceneSetup 등에서 런타임 설정) ──
|
|
|
|
/// <summary>런타임에서 PlayerAttack 참조를 설정합니다.</summary>
|
|
public void SetPlayerAttack(PlayerAttack attack) // 함수를 선언할거에요 -> 런타임 참조 설정을
|
|
{
|
|
playerAttack = attack; // 저장할거에요 -> 공격 스크립트 참조를
|
|
}
|
|
}
|