no image
내일배움캠프 58일차 TIL [최종 프로젝트 Black Chamber]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 09:30 : 데일리 스크럼(AM) — 오늘 목표/이슈 공유09:30 ~ 12:30 : 인풋 시스템 Run 액션 추가, PlayerConditionManager 설계(스태미나 소모/재생), TopDownMovement 연동 및 애니메이션 블렌드(걷기 0.5 / 뛰기 1.0) 적용🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 16:00 : Fog of War 가시성 에이전트 페이드아웃 구현(스르륵 사라지는 처리)16:00 ~ 18:00 : Spot/LOS 임계값 튜닝, 히스테리시스 구상, 런타임 테스트 및 성능 점검🍽️ 저녁시간18:00 ~ 19:00 : 저녁시간✅ 저녁19:00 ~ 19:30 : 데일리 스크럼(PM) — 진행 상황 점검..
2025.09.18
no image
Unity - Fog of War, 3D(XZ)에서 2D(XY)로 바꾸기
“안개(=안 보이는 부분)를 2D 탑다운 게임에서도 쓰고 싶다!”이 글은 AOS Fog of War(3D XZ 기준)를 2D XY로 바꿔서 쓰는 과정을 정리한 블로그입니다. https://assetstore.unity.com/packages/vfx/shaders/fullscreen-camera-effects/aos-fog-of-war-249249 AOS Fog of War | 카메라 효과 | Unity Asset StoreAdd depth to your project with AOS Fog of War asset from Fischl Works. Find this & more 시각 효과 options on the Unity Asset Store.assetstore.unity.com사용한 에셋!미리보기 (..
2025.09.17
no image
내일배움캠프 57일차 TIL [최종 프로젝트 Black Chamber]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 09:30 : 데일리 스크럼 — 오늘 목표: 3D용 FOW를 2D 탑뷰 전용으로 전환09:30 ~ 10:30 : 기존 코드 리드(좌표·렌더 파이프라인 파악) — Plane(XZ), z축 참조 지점 목록화10:30 ~ 13:00 : 전환 설계메쉬: Plane→Quad(XY),좌표: z→y 치환 지점(리빌러/World↔Grid 변환 4곳) 확정,텍스처 초기화/머티리얼 1회 할당 규칙 수립🍽️ 점심시간13:00 ~ 14:00 : 점심✅ 오후14:00 ~ 14:30 : InitializeFog() 재작성 — Quad(XY), RGBA32 텍스처(Point/Clamp), 머티리얼 단 한 번만 new14:30 ~ 15:30 : 반대 이동 이슈 Fix — Z=180° 회전..
2025.09.17
no image
내일배움캠프 56일차 TIL [최종 프로젝트 Black Chamber]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 09:30 : 데일리 스크럼(AM) — 진행 상황 공유, 오늘 목표 확정09:30 ~ 10:30 : Fog of War(FOW) 구현 방식 리서치·비교(타일/CPU 마스크/RT 누적 등)10:30 ~ 12:30 : URP 2D 세팅 점검, 레이어·소팅 정리(FOWProbe/FOW), 전용 카메라/RT 설계🍽️ 점심시간13:00 ~ 14:00 : 점심✅ 오후14:00 ~ 15:00 : FOW 프로토타입 구성(ExplorationCam + RT_Frame/VisitedA/VisitedB)15:00 ~ 16:30 : 오버레이 셰이더·머티리얼 연결, 런타임 바인딩 구현16:30 ~ 17:30 : 디버깅(라이트 블렌드/레이어/컬링 마스크 이슈 추적)17:30 ~ 18:..
2025.09.16
no image
내일배움캠프 55일차 TIL [최종 프로젝트 Black Chamber]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 10:00 : 데일리 스크럼(업무 분담, 핵심 루프 목표 합의)10:00 ~ 11:30 : 레퍼런스 게임 Intravenous 2 플레이 & 분석11:30 ~ 12:50 : 차별점/시야 시스템 논의, 역할 확정 메모🍽️ 점심시간13:00 ~ 14:00 : 점심✅ 오후14:00 ~ 15:30 : MissionManager 이벤트(+1/–1) 연결, MissionEntityHook 부착15:30 ~ 16:30 : 레이어/레이어마스크 정리(AssassinationTarget, Enemy)16:30 ~ 17:30 : 카메라 감쇠/민감도 튜닝 검토(프로토타입 적용 준비)17:30 ~ 18:00 : 타이틀 화면 이미지 프롬프트 6안 정리🍽️ 저녁시간18:00 ~ 19:..
2025.09.15
no image
내일배움캠프 54일차 TIL [최종 프로젝트 기획+개발]
🗓️ 오늘 하루 일정✅ 오전10:00 ~ 10:30 : 오전 데일리 스크럼 — 진행 상황 공유, 오늘 작업 범위 정의10:30 ~ 12:00 : Shooter 발사 흐름 정리 (Shoot → SpawnBullet → VFX/SFX) 및 스프레드/쿨다운 점검🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 17:50 : 머즐 플래시 프리팹·스크립트 제작/연결(OnEnable 랜덤 스프라이트, 0.05초 유지)SFX 피치 랜덤화 검토 → 보류(단일 사운드 유지, 간결성 우선)🍽️ 저녁시간18:00 ~ 19:00 : 저녁시간✅ 저녁19:00 ~ 종료 : 오후 데일리 스크럼 — 오늘 작업 회고, 내일 계획 합의(소음기 권총용 트레이서 구현부터)✅ 오늘 학습 키워드Shooter 발사 로직..
2025.09.12
no image
내일배움캠프 53일차 TIL [최종 프로젝트 기획+개발]
🗓️ 오늘 하루 일정✅ 오전10:00 ~ 10:30 : 데일리 스크럼 진행(금일 작업 범위 확정)10:30 ~ 12:30 : 공용 사격 API 설계(Shoot(Vector2 dir) 한 함수로 통일)🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 16:00 : Shooter2D 제작(플레이어/적 공용), Bullet 정리16:00 ~ 17:30 : 레이어 분리 및 Physics2D 충돌 매트릭스 정리(태그 사용 제거)17:30 ~ 18:00 : 트레일 렌더러(총알 궤적) 적용 및 기본 튜닝🍽️ 저녁시간18:00 ~ 19:00 : 저녁시간✅ 저녁19:00 ~ 20:20 : 사격 테스트(권총/라이플 SO), 피격 전달 점검20:20 ~ 21:00 : 리팩터링 메모 정리 & TIL✅..
2025.09.11
no image
내일배움캠프 52일차 TIL [최종 프로젝트 기획+개발]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 12:00 : 입력 액션 맵 정리( Move/Run/Interact/Menu/Attack/Look ) 및 PlayerInput( Send Messages ) 세팅🍽️ 점심시간13:00 ~ 14:00 : 점심✅ 오후14:00 ~ 16:00 : 2D 탑다운 이동 완성 (Rigidbody2D.Kinematic + MovePosition) / 마우스 에임 바라보기 로직 적용 / InputValue → InputAction.CallbackContext 전환, PlayerInputController partial 분리16:00 ~ 18:00 : 팀 회의(진척 공유, 입력/조준 구조 리뷰)🍽️ 저녁시간18:00 ~ 19:00 : 저녁✅ 저녁19:00 ~ 21:00 : 기..
2025.09.10
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 09:30 : 데일리 스크럼(AM) — 오늘 목표/이슈 공유
  • 09:30 ~ 12:30 : 인풋 시스템 Run 액션 추가, PlayerConditionManager 설계(스태미나 소모/재생), TopDownMovement 연동 및 애니메이션 블렌드(걷기 0.5 / 뛰기 1.0) 적용

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심시간

✅ 오후

  • 14:00 ~ 16:00 : Fog of War 가시성 에이전트 페이드아웃 구현(스르륵 사라지는 처리)
  • 16:00 ~ 18:00 : Spot/LOS 임계값 튜닝, 히스테리시스 구상, 런타임 테스트 및 성능 점검

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁시간

✅ 저녁

  • 19:00 ~ 19:30 : 데일리 스크럼(PM) — 진행 상황 점검, 내일 할 일 확정
  • 19:30 ~ 21:00 : 스태미나/달리기 밸런싱(소모·재생 수치 조정), 페이드 타임 파라미터 보정

✅ 오늘 학습 키워드

  • Unity Input System: Run 액션(Press & Hold)
  • PlayerConditionManager: 스태미나 소모/재생·지연·최소치
  • TopDownMovement: 걷기/뛰기 전환, 애니메이션 블렌드(0.5/1.0)
  • Fog of War: 하드 토글 → 알파 보간 페이드아웃
  • MaterialPropertyBlock로 _BaseColor/_Color 알파 적용
  • 가시성 임계값(spot threshold)·히스테리시스로 깜빡임 방지

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

달리기 상태를 인풋(누르고 있음), 조건(스태미나 가능), **이동/애니메이션(실제 전환)**으로 나눠 책임을 분리했다. 인풋은 단순히 의도만 전달하고, 실제 달리기 여부는 CanRun(스태미나가 충분할 때)로 결정하도록 해서 버그 여지를 줄였다. 애니메이션은 걷기=0.5, 뛰기=1.0 블렌드를 기준으로 일관되게 갱신했다.

Fog of War는 “보인다/안 보인다”를 즉시 토글하던 부분을 알파 보간으로 바꿔 시각적 이질감을 해소했다. 런타임에서 머티리얼 인스턴싱을 피하려고 MaterialPropertyBlock을 사용했고, 셰이더에 _BaseColor 또는 _Color가 있는 경우에만 알파를 적용하도록 해 안전성을 높였다. 가시성 경계 근처에서 깜빡이는 현상은 임계값 + 히스테리시스로 완화 가능함을 확인했다.


🧩 학습하며 겪었던 문제점 & 에러

1) 가시성 토글이 “툭” 하고 꺼져서 위화감

  • 문제 정의: 적이 시야에서 벗어나면 즉시 Renderer.enabled = false가 되어 화면에서 갑자기 사라짐.
  • 내가 한 시도: 단순 토글에서 알파 보간으로 전환, 페이드 아웃 완료 시에만 렌더러 비활성.
  • 해결 방법(요지):
  •  
  • 새롭게 알게 된 점:
    • 런타임에 머티리얼을 직접 수정하면 드로우콜 증가/메모리 낭비가 발생할 수 있어 PropertyBlock이 안전.
    • 일부 셰이더는 알파 프로퍼티가 없어 투명 제어가 안 되므로, 셰이더 교체나 스프라이트 기반 대체가 필요.
  • 다시 만나면: 임계값 상·하한(예: 나타남 0.02, 사라짐 0.01) 히스테리시스를 바로 적용해 깜빡임을 선제 차단.
// 목표 알파(보이면 1, 아니면 0)
targetAlpha = isVisible ? 1f : 0f;

// 페이드 속도(초 단위)
float speed = isVisible ? 1f / fadeInTime : 1f / fadeOutTime;

// 현재 알파를 서서히 이동
currentAlpha = Mathf.MoveTowards(currentAlpha, targetAlpha, speed * Time.deltaTime);

// 머테리얼에 알파 적용 (PropertyBlock)
renderer.GetPropertyBlock(mpb);
if (mat.HasProperty("_BaseColor")) mpb.SetColor("_BaseColor", baseColor.WithA(currentAlpha));
if (mat.HasProperty("_Color"))     mpb.SetColor("_Color",     baseColor.WithA(currentAlpha));
renderer.SetPropertyBlock(mpb);

// 완전 0일 때만 끔
renderer.enabled = currentAlpha > 0.001f;

2) 스태미나 관리가 어색해서 달리기 급정지

  • 문제 정의: 스태미나가 0에 가까워질 때 달리기/걷기가 매 프레임 요동.
  • 내가 한 시도: minStaminaToRun을 두어 최소치 이상이어야만 달리기 허용, 달리기 종료 후 재생 지연 추가.
  • 해결 방법(요지):
  •  
  • 새롭게 알게 된 점: 입력 의도리소스 가능 여부를 분리하면, 애니메이션과 이동 로직이 깔끔해짐.
  • 다시 만나면: 체감 품질을 위해 runSpeedMultiplier, regenDelay, minStaminaToRun 세 값을 먼저 테이블로 잡고 QA.
// 조건
bool wantsToRun = input.RunHeld && moveInput.sqrMagnitude > 0f;
bool canRun = condition.Stamina > minStaminaToRun;
isRunning = wantsToRun && canRun;

// 소모/재생
if (isRunning) condition.ConsumeForRun(Time.fixedDeltaTime);
else           condition.TickRegen(Time.fixedDeltaTime); // regenDelay 이후 회복

📝 메모

오늘은 플레이어 이동/스태미나/애니메이션과 포그 가시성 흐름을 “자연스럽게 보이게” 만드는 데 집중했다. 기능 자체는 간단하지만, 상태 전이의 질감(페이드, 지연, 경계값)이 체감 완성도를 크게 올린다. 내일은 히스테리시스 수치와 스태미나 재생 속도를 더 미세 조정하고, UI에 스태미나 슬라이더를 연결해 피드백을 강화하겠다.


반응형
반응형

“안개(=안 보이는 부분)를 2D 탑다운 게임에서도 쓰고 싶다!”
이 글은 AOS Fog of War(3D XZ 기준)를 2D XY로 바꿔서 쓰는 과정을 정리한 블로그입니다.

 

https://assetstore.unity.com/packages/vfx/shaders/fullscreen-camera-effects/aos-fog-of-war-249249

 

AOS Fog of War | 카메라 효과 | Unity Asset Store

Add depth to your project with AOS Fog of War asset from Fischl Works. Find this & more 시각 효과 options on the Unity Asset Store.

assetstore.unity.com

사용한 에셋!

미리보기 (전/후)

원형 시야 느낌

 

손전등(부채꼴) 시야 느낌

 

1) 왜 XZ → XY로 바꾸나요?

    • 3D 프로젝트는 “바닥=X-Z 평면, 높이=Y”가 보통입니다.
    • 2D 탑다운은 “바닥=X-Y 평면, 깊이(Z)는 카메라 앞뒤만 사용”이 보통입니다.
    • 그래서 좌표와 메쉬 기준을 XY로 돌려놓아야 합니다. 그래야 타일 계산, 충돌, 정렬이 자연스럽습니다.

2) 좌표계와 메쉬를 XY에 맞추기 (핵심 3줄 요약)

    1. 타일 좌표 계산을 X,Y로 바꾸기
      • 리빌러(플레이어 등) 위치에서 x는 x, y는 y를 직접 읽어 씁니다. (XZ가 아니라 XY!)
      • 원본과 수정본 모두 GetUnitX(...) / GetUnitY(...) 를 써서 그리드 좌표로 바꿉니다.
    1.  
    2. 안개를 그릴 메쉬를 XY 평면에 놓기
      • PrimitiveType.Quad를 만들어 월드 중앙(XY) 에 두고, Z는 카메라 바로 앞(작은 음수) 로 둡니다.
      • 정렬은 Sorting Layer / Order 로 스프라이트 위에 오도록 맞춥니다. (콜라이더는 꺼두기)
    1.  
    2. 텍스처 해상도 = 타일 해상도
      • new Texture2D(levelDimensionX, levelDimensionY) 처럼 타일 수와 같은 크기의 텍스처를 만들어, 픽셀마다 “가림/공개”를 색으로 기록합니다.
  1.  

2-1. 좌표계: 리빌러가 어디 서 있는지 “XY 타일”로 바꾸기

    • 리빌러 Transform.position 의 x, y 값을 한 칸 크기(unitScale) 로 나눠 반올림하면 “몇 번째 칸인지”를 얻습니다.
    • 이 값은 안개 계산에서 “어느 타일을 밝힐지”에 쓰입니다.
    • 코드적으로는 GetCurrentLevelCoordinates → GetUnitX(pos.x), GetUnitY(pos.y) 흐름입니다. (XZ가 아닌 XY)

2-2. 메쉬: Quad를 XY에, 정렬은 스프라이트 위로

    • 안개를 실제로 그릴 ‘판’ = Quad(1×1) 를 만들어 레벨 중앙(XY) 에 깔고, 스케일을 레벨 크기만큼 키웁니다.
    • Z 살짝 음수(예: -0.1f)로 두면 카메라 앞에 오면서, 다른 2D 스프라이트 위에 올릴 수 있습니다.
    • Sorting Layer / Order 로 표시 순서를 고정합니다.
    • 원본은 초기 구현에서 180° 회전이 들어가지만, 2D에서는 보통 회전 없이 써도 됩니다. (수정본에선 이 회전이 제거되어 더 자연스럽습니다)

2-3. 텍스처: 타일 하나 = 텍스처 한 픽셀

    • 안개는 결국 텍스처 한 장입니다.
    • 텍스처의 각 픽셀 = 지도 타일 1칸 이라고 생각하고,
      “보이는 칸은 투명/연한 색, 보이지 않는 칸은 어두운 색(알파값 큼)”으로 칠합니다.
    • 원본은 fogPlaneTextureLerpTarget/Buffer 두 장을 써서 부드럽게 보간(Lerp) 합니다. 수정본은 XY 환경에 맞춘 동일 구조를 유지합니다.

손에 잡히는 체크리스트

    • 리빌러의 위치에서 X/Y 로 타일 좌표 뽑기 (GetUnitX, GetUnitY).
    • Quad를 만들어 XY 평면에 배치, Z는 -0.1f 근처, Sorting Layer/Order로 최상단 표시.
    • 텍스처 크기 = (타일X, 타일Y) 로 만들고, 각 픽셀을 타일처럼 사용.

다음 파트에서는 3) 장애물 스캔을 2D 물리로 바꾸기(Physics2D.OverlapBoxAll)
5) 손전등 시야(부채꼴) + 부드러운 가장자리(가중치) 를 이어서 정리할게요. (수정본에 이미 구현되어 있습니다)

csFogWar


참고

    • 에셋: AOS Fog of War (원본은 3D/XZ 기준)
    • 우리 프로젝트 스크립트(요지):
      • 원본 2D 포팅본: csFogWar1.cs – XY 정렬, Quad, 텍스처 보간 구조.

csFogWar1.cs
0.03MB

 

 

 

      • 수정본: csFogWar.cs – 부채꼴 시야(outer/inner 반경, 각도, 전방 축), 가중치 기반 알파, 회전 제거 등.
  •  

csFogWar.cs
0.03MB

 

 

 

 

사실 GPT의 도움을 많이 받았지만 3D에서 2D로 바꾸는게 마냥 쉽지는 않았네요 ㅎㅎ.. 900줄이나 되는 코드이다보니.. 하여튼!

수정본을 보시면 아시겠지만 원형 시야가아닌 부채꼴 시야로 제작했습니다! 현재 2D 탑뷰 암살 게임을 만드는중이라서요ㅎㅎ..

읽어주셔서 감사합니다아!!

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 09:30 : 데일리 스크럼 — 오늘 목표: 3D용 FOW를 2D 탑뷰 전용으로 전환
  • 09:30 ~ 10:30 : 기존 코드 리드(좌표·렌더 파이프라인 파악) — Plane(XZ), z축 참조 지점 목록화
  • 10:30 ~ 13:00 : 전환 설계
    • 메쉬: Plane→Quad(XY),
    • 좌표: z→y 치환 지점(리빌러/World↔Grid 변환 4곳) 확정,
    • 텍스처 초기화/머티리얼 1회 할당 규칙 수립

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심

✅ 오후

  • 14:00 ~ 14:30 : InitializeFog() 재작성 — Quad(XY), RGBA32 텍스처(Point/Clamp), 머티리얼 단 한 번만 new
  • 14:30 ~ 15:30 : 반대 이동 이슈 Fix — Z=180° 회전(또는 UV -1,-1) 중 하나만 적용 확인
  • 15:30 ~ 16:30 : 기즈모 XY 평면화 — OnDrawGizmos()의 Y↔Z 스왑 및 두께 최소화
  • 16:30 ~ 17:30 : 밝기 반전 Fix — 알파 매핑 a = Lerp(fogAlpha, revealedA, vis)로 교체

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁

✅ 저녁

  • 19:00 ~ 20:00 : Spot(FOV) 부채꼴 도입 — Light2D 연동/수동 파라미터 비교, 가중치 맵 spotWeight 구축
  • 20:00 ~ 21:00 : LOS×Spot 합성 및 전방 기준 forwardOverride(GunPoint) 적용
  • 21:00 ~ 21:30 : 가시성 에이전트 동기화 — CheckVisibilitySpot() 추가, SpriteRenderer 포함 토글
  • 21:30 ~ 21:45 : 로그·체크리스트로 회귀 테스트, TIL 작성 준비

✅ 오늘 학습 키워드

  • Quad(XY) 전환 / Plane(XZ) 제거
  • 좌표계 치환: z→y, GetWorldY/UnitY, WorldToLevel/LevelToWorld
  • UV 반전 vs Z=180° 회전(중복 금지)
  • 텍스처 초기화: RGBA32 + Point + Clamp, 초기 픽셀(검정, a=1)
  • 알파 매핑: vis=1 → 투명(또는 회색), vis=0 → 불투명
  • Spot(FOV) 가중치(거리·각도 소프트에지) × LOS
  • 전방 기준: forwardOverride(GunPoint/UpperBody) + right/up 축 선택
  • 가시성 통일: CheckVisibilitySpot()로 화면과 판정 1:1 일치
  • 디버그: 기즈모 XY 평면, 재현→원인→고정 플로우

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

 

Unity - Fog of War, 3D(XZ)에서 2D(XY)로 바꾸기

“안개(=안 보이는 부분)를 2D 탑다운 게임에서도 쓰고 싶다!”이 글은 AOS Fog of War(3D XZ 기준)를 2D XY로 바꿔서 쓰는 과정을 정리한 블로그입니다. https://assetstore.unity.com/packages/vfx/shaders/fullscreen-came

dev-jen.tistory.com

  • 3D 전제(Plane/XZ/z축)로 짜인 FOW를 2D 탑뷰에 맞추려면, 렌더·좌표·텍스처·머티리얼·기즈모같은 기준(XY) 으로 “세트”로 바꿔야 한다.
  • “플레이어가 오른쪽/위로 가는데 안개가 반대로”는 UV/회전 보정 문제다. 보정은 한 번만(Z=180° or UV -1,-1).
  • 밝기가 반대면 알파의 의미가 반대다. vis(0..1)를 알파에 선형으로 매핑하면 직관적으로 맞춰진다.
  • Spot(FOV)은 거리·각도·전방의 함수. 화면과 오브젝트 판정까지 일치시키려면 같은 스칼라(vis) 를 공유하고, 에이전트는 CheckVisibilitySpot()을 써야 한다.

🧩 학습하며 겪었던 문제점 & 에러

Fog of War 트러블슈팅 (3D → 2D Top-Down)

1) 안개가 XZ 바닥에 깔림 / 씬에서 한 줄처럼 보임

  • 원인: PrimitiveType.Plane(XZ 기준) 사용 + 기즈모도 XZ 기준으로 그림.
  • 해결
    • 메쉬: Plane → Quad(XY) 로 교체.
    • 위치/스케일: (mid.x, mid.y, fogZ), (w, h, 1).
    • 기즈모: new Vector3(GetWorldX(x), GetWorldY(y), fogZ)로 XY 평면에 그리기.

2) 플레이어가 오른쪽/위로 가면 안개는 왼쪽/아래로 밀림

  • 원인: 텍스처 UV 축과 우리가 채우는 픽셀 방향(그리드 순회)이 반대. 또는 머티리얼 재생성으로 UV 보정값 초기화.
  • 해결(둘 중 하나만 적용!)
    1. 쿼드 Z=180° 회전: fogPlane.transform.rotation = Quaternion.Euler(0,0,180);
    2. 머티리얼 UV 반전:
    3. mat.SetTextureScale("_MainTex", new Vector2(-1,-1)); mat.SetTextureOffset("_MainTex", new Vector2( 1, 1));
  • 주의: 두 보정을 동시에 쓰면 다시 반대로 돌아감.
  • 추가 주의: InitializeFog()에서 new Material(...)을 한 번만 호출. 두 번 만들면 위 보정이 초기화됨.

3) 지나간 곳이 더 어둡게 보임(밝기 반전)

  • 원인: 알파 의미가 반대(‘보임=1’을 그대로 쓰면서 머티리얼과 곱해 어둡게 됨).
  • 해결(알파 매핑 변경)→ 보이는 타일일수록 투명(또는 회색), 숨김일수록 불투명.
  • // vis: 0..1 (0=숨김, 1=보임) float a = Mathf.Lerp(fogPlaneAlpha, revealedTileOpacity /*또는 0f*/, vis); pixel = new Color(1,1,1, a); // 색은 머티리얼 색상(fogColor)로

4) 2D로 바꿨는데 여전히 Z축을 참조함

  • 원인: 좌표 변환이 3D 잔재(.z 사용).
  • 해결(핵심 4줄)
    • GetUnitVector(world): (x, **y**) 사용
    • GetWorldY(...) / GetUnitY(...): 피벗을 levelMidPoint.**y** 기준으로
    • 리빌러 좌표: revealerTransform.position.**y**

5) Light2D 기반 Spot(부채꼴)인데 화면이 안 나오거나 일부 각도만 나옴

  • 원인
    • 전방 벡터가 플레이어 루트 축을 봄(총구/상체 방향 아님).
    • 스팟 기준점을 그리드→월드로 다시 역산해 오프셋 생김.
    • LOS를 중간에 continue로 버려 가중치가 0됨.
  • 해결
    • 전방: forwardOverride(예: GunPoint/UpperBody) 사용 + right/up 중 맞는 축 선택.
    • 스팟 기준점: Vector2 revealerPos = revealerTransform.position; 월드 XY 직접 사용.
    • LOS는 마지막에 곱하기로 적용(중간 continue 제거) → 디버깅 용이.

6) 화면은 스팟인데, 오브젝트는 계속 보임(판정 불일치)

  • 원인: 화면은 Spot 가중치로, 에이전트는 원형/LOS로 판정.
  • 해결: CheckVisibilitySpot(world, radius, threshold) 추가 후 에이전트가 이걸 사용.
  • → spotWeight[x,y] > threshold 일 때만 보이도록 Sprite/Mesh 렌더러 enabled 토글.

7) NRE/텍스처가 안 바뀜/번들번들함

  • 원인: 텍스처 생성/초기화 순서 누락, 필터/래핑 미설정.
  • 해결
    • 텍스처: new Texture2D(w,h, RGBA32, false) → Point/Clamp 지정.
    • 초기 픽셀을 검정(알파=1) 으로 채운 뒤 Apply.
    • 매 프레임 버퍼↔타깃 보간 시 null 가드.

📝 메모

  • 전환 체크리스트(10개): Quad/XY, Z=180° or UV(-1,-1), 머티 1회 생성, RGBA32/Point/Clamp, 알파 매핑, 좌표 z→y, 기즈모 XY, Spot(거리·각도·전방), LOS는 곱셈, CheckVisibilitySpot + SpriteRenderer 토글
  • 디버깅 루틴: UpdateOnlyOnMove=OFF → 값 로그(outerR/angle/forward/vis) → 기즈모 XY에서 재현 → 보정 중복 제거
  • 성능: 가중치 영역을 min..max 타일로 한정, RefreshRate 10~20 유지, 라이트 반경/각도 과대 설정 금지

오늘은 Fog of War를 셋팅하는 날이였다 원래 3D라서 2D 탑뷰로 바꿨어야 했는데 이게 하루만에 될지 몰랐다.. 다행히 작업이 끝나서 다음 작업으로 넘어갈 수 있겠다! 내일도 화이팅!!

 


원래 Fog of War 에셋
수정한 버전!

적들까지 안보이게 잘 설정됐다!

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 09:30 : 데일리 스크럼(AM) — 진행 상황 공유, 오늘 목표 확정
  • 09:30 ~ 10:30 : Fog of War(FOW) 구현 방식 리서치·비교(타일/CPU 마스크/RT 누적 등)
  • 10:30 ~ 12:30 : URP 2D 세팅 점검, 레이어·소팅 정리(FOWProbe/FOW), 전용 카메라/RT 설계

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심

✅ 오후

  • 14:00 ~ 15:00 : FOW 프로토타입 구성(ExplorationCam + RT_Frame/VisitedA/VisitedB)
  • 15:00 ~ 16:30 : 오버레이 셰이더·머티리얼 연결, 런타임 바인딩 구현
  • 16:30 ~ 17:30 : 디버깅(라이트 블렌드/레이어/컬링 마스크 이슈 추적)
  • 17:30 ~ 18:00 : 정리(문제 목록화·대응 전략 메모)

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁

✅ 저녁

  • 19:00 ~ 20:00 : 프로토타입 재확인 및 로그 점검(미리보기 UI로 RT 상태 확인)
  • 20:00 ~ 20:30 : 레퍼런스 조사(레딧 FOW/LOS 사례)
  • 20:30 ~ 21:00 : 저녁 스크럼 — 내일 작업 배분 결정
  • 21:00 ~ 21:30 : 내일 에셋 기반 FOW 도입 계획 수립
  • 21:30 ~ 21:45 : TIL 작성

✅ 오늘 학습 키워드

  • URP 2D, Light2D(Additive vs Multiply), Target Sorting Layers
  • RenderTexture 누적(Graphics.Blit, max 합성)
  • UI 오버레이 합성 셰이더(현재 시야=투명 / 방문=회색 / 미탐색=검정)
  • 카메라 Culling Mask·레이어 분리 전략

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

  • “지금 비춘 영역”을 전용 카메라로 RT_Frame에 찍고, 이전 누적과 max로 합쳐 VisitedRT에 쌓는다.
  • 화면에는 RawImage 오버레이를 얹고, 셰이더에서 현재 프레임 밝은 픽셀은 완전 투명, 누적 픽셀은 회색, 미탐색은 검정으로 표현하면 플레이 가시성과 진행 흔적을 동시에 확보할 수 있다.
  • 핵심은 Additive 전용 Light2DGlobal Light2D의 레이어 분리, 그리고 런타임 머티리얼 텍스처 바인딩이다.

🧩 학습하며 겪었던 문제점 & 에러

1) 프로브 평면이 메인 카메라에 노출됨

  • 문제 정의: 게임 화면이 회색 부채꼴로 덮여 실제 월드가 가려짐.
  • 내가 한 시도: 오버레이 색/알파 조정.
  • 해결 방법: Main Camera의 Culling Mask에서 FOWProbe 해제(ExplorationCam만 보게).
  • 새롭게 알게 된 점: 프로브용 평면은 전용 카메라로만 렌더링해야 한다.
  • 다시 만나면: 씬 진입 시 카메라-레이어 매트릭스를 우선 점검.

2) 화면이 전부 어두움(오버레이만 보임)

  • 문제 정의: 현재 시야가 투명 처리되지 않아 월드가 안 보임.
  • 내가 한 시도: 셰이더 임계값 변경.
  • 해결 방법: overlay.material = new Material(overlayMat)로 인스턴스화,
  • overlay.texture = currentVisited, overlay.material.SetTexture("_CurrentTex", rtFrame) 런타임 바인딩. 컷오프 0.2로 조정.
  • 새롭게 알게 된 점: 에디터에서 Texture만 넣으면 동작 불가, 코드 바인딩 필수.
  • 다시 만나면: 실행 직후 디버그 RawImage로 RT_Frame/Visited 상태 먼저 확인.

3) RT_Frame가 항상 검정

  • 문제 정의: 누적 자체가 진행되지 않음.
  • 내가 한 시도: 카메라/RT 재설정.
  • 해결 방법: FOW 전용 Light2D를 Additive로 전환, Target Sorting Layers=FOW만, Global Light2D에서 FOW 타겟 해제.
  • 새롭게 알게 된 점: Multiply 라이트는 마스크 소스로 부적합.
  • 다시 만나면: 라이트 Blend/Target Layers부터 체크.

📝 메모

  • 내일은 FOW 에셋 기반으로 재구현(기능: 누적/감쇠/미니맵 연동 검토) → 데모 씬 확인 후 프로젝트 통합.
  • 내일 담당
    • 재은: Fog of War 에셋 도입·통합
    • 혜현: 적 상태
    • 도현: 컨디션(스태미나)
    • 현수: 맵 제작
    • 유경: UI 제작
  • 추가 아이디어: 방문 영역 감쇠(decay), 가장자리 블러, 세이브/로드 포맷 정의 및 미니맵 동기화.

오늘 하루는 플레이어가 라이트를 비췄던 자리를 회색으로 남기는 기능을 만들고싶었다 하지만.. 실패 ㅠㅜ 그리고 검색을 하다보니 Fog of War이라는 에셋을 찾았다.. 완전히 내가 원하는 기능! 그래서 내일은 이 에셋을 적용시켜보려고 한다! 쉽지는 않겠지만 화이팅!!!


반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 10:00 : 데일리 스크럼(업무 분담, 핵심 루프 목표 합의)
  • 10:00 ~ 11:30 : 레퍼런스 게임 Intravenous 2 플레이 & 분석
  • 11:30 ~ 12:50 : 차별점/시야 시스템 논의, 역할 확정 메모

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심

✅ 오후

  • 14:00 ~ 15:30 : MissionManager 이벤트(+1/–1) 연결, MissionEntityHook 부착
  • 15:30 ~ 16:30 : 레이어/레이어마스크 정리(AssassinationTarget, Enemy)
  • 16:30 ~ 17:30 : 카메라 감쇠/민감도 튜닝 검토(프로토타입 적용 준비)
  • 17:30 ~ 18:00 : 타이틀 화면 이미지 프롬프트 6안 정리

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁

✅ 저녁

  • 19:00 ~ 20:30 : 프로토타입 플레이테스트
  • 20:30 ~ 21:30 : 피드백 정리(적 AI/시야/카메라/맵 정보/목표 탐색 등)
  • 21:30 ~ 22:00 : 저녁 스크럼(내일 작업 분배·마일스톤 확인)
  • 22:00 ~ 22:20 : TIL 정리/기록

✅ 오늘 학습 키워드

  • 이벤트 기반 MissionManager (타깃/적 카운트, Escape 전환)
  • 시야(Vision) 제한 & 지나간 길 노출(Fog of War)
  • 카메라 스무딩/감쇠 튜닝 (어지러움 최소화)
  • AI 의심→수색 전이, 거리 기반 탐지 속도
  • 원킬/피격 반응(피격 방향 바라보기, 상태 전환)
  • 맵 정보 제공(미니맵/테두리 하이라이트)

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

https://dev-jen.tistory.com/entry/DesignPattern-이벤트-버스Event-Bus-패턴

  • 목표 체크는 씬 전역에서 폴링하지 않고, 적/암살 타깃이 활성/비활성 이벤트를 던질 때 카운트만 정확히 올리고 내리는 방식이 가장 깔끔했다. 이렇게 하니 타깃이 0이 되는 순간을 안정적으로 잡아 Escape 단계로 전환할 수 있었다.
  • 레퍼런스는 훌륭했지만, 우리 색은 제한 시야 + 지나간 길 누적 정보에서 만들어야 한다. “한 화면 정보 과다” 대신 “정보를 따서 쌓는 재미”를 핵심으로 삼자.
  • 카메라 스무딩은 멋있지만 조준에는 방해가 된다. 빠르게 멈추는 감쇠근거리 민감도 완화가 필요했다.
  • 전투 이슈(원킬/피격 반응, 의심→수색 텀 등)는 작은 파라미터명확한 시각 피드백(느낌표, 테두리)로 플레이 감각을 크게 바꿀 수 있다.

🧩 학습하며 겪었던 문제점 & 에러

1) MissionManager 폴링(UPDATE 스캔) → 이벤트 전환

  • 문제정의
  • Update()에서 씬의 오브젝트를 스캔하거나 레이어 카운트를 매 프레임 갱신하려다 보니, 풀링/활성화 타이밍에 따라 누락·중복 카운트가 발생하고 퍼포먼스도 불필요하게 사용됨.
  • 시도
  • FindObjectsOfType/레이어 스캔 주기로 재계산 → 특정 프레임에서 놓치는 케이스가 여전히 존재.
  • 해결 방법
    // MissionManager.cs (핵심만)
    public void TargetActivated()   { remainingTargets++; OnTargetsChanged?.Invoke(remainingTargets); EvaluatePhase(); }
    public void TargetDeactivated() { if (remainingTargets>0) remainingTargets--; OnTargetsChanged?.Invoke(remainingTargets); EvaluatePhase(); }
    
    public void EnemyActivated()    { remainingEnemies++;  OnEnemiesChanged?.Invoke(remainingEnemies); }
    public void EnemyDeactivated()  { if (remainingEnemies>0) remainingEnemies--; OnEnemiesChanged?.Invoke(remainingEnemies); }
    
    // MissionEntityHook.cs (각 적/타깃 프리팹 루트에 부착)
    private void OnEnable()  { if (kind==AssassinationTarget) mission.TargetActivated(); else mission.EnemyActivated(); }
    private void OnDisable() { if (kind==AssassinationTarget) mission.TargetDeactivated(); else mission.EnemyDeactivated(); }
    
  • 이벤트 기반으로 전환: 각 엔티티가 활성/비활성 시점에만 ±1 호출.
  • 새롭게 알게 된 점
  • “상태 변화 시점 이벤트”가 폴링보다 정확·간결하고, 풀링/활성화 패턴과도 찰떡.
  • 다시 만나게 된다면
  • 카운트가 필요한 다른 시스템(예: 아이템/트리거)도 OnEnable/OnDisable 이벤트 패턴으로 통일.

2) 구독/생명주기 레이스(매니저보다 훅이 먼저 켜지는 이슈)

  • 문제정의
  • 씬에 따라 MissionEntityHook.OnEnable()가 MissionManager 초기화보다 먼저 실행되어 첫 +1을 놓치는 경우 발생 가능.
  • 시도
  • 훅에서 FindFirstObjectByType<MissionManager>() 시도했지만 타이밍에 따라 실패.
  • 해결 방법
    1. 실행 순서 지정 + 2) 지연 보정 추가.
    // 권장: 실행 순서
    [DefaultExecutionOrder(-500)] public class MissionManager : MonoBehaviour {}
    [DefaultExecutionOrder(-400)] public class MissionEntityHook : MonoBehaviour {}
    
    // 보정: 훅에서 Start 재시도
    private bool registered;
    private void OnEnable() { TryRegister(); }
    private void Start()    { if (!registered) TryRegister(); }
    private void OnDisable(){ if (!mission) return; /* ...deactivate... */ registered=false; }
    
    void TryRegister() {
        if (!mission) mission = FindFirstObjectByType<MissionManager>();
        if (!mission) return;
        if (kind==AssassinationTarget) mission.TargetActivated(); else mission.EnemyActivated();
        registered = true;
    }
    
  • 새롭게 알게 된 점
  • DefaultExecutionOrder재시도 지점을 두면 씬별/프레임별 레이스를 안전하게 흡수.
  • 다시 만나게 된다면
  • 매니저에서 씬 시작 시 **초기 스냅샷(한 번만 스캔)**을 수행해 이미 켜진 훅들을 재등록.

📝 메모

  • 오늘 프로토타입 테스트에서 재미의 골자는 분명했다: 조심스러운 각 클리어(CQB). 이제 **정보 설계(시야/미니맵)**와 **조작성(카메라/이동 속도)**을 다듬으면 된다.
  • 금요일까지 “타이틀→로비→핵심 루프→종료”가 돌아가도록, 각자 파트를 작게라도 끝까지 꽂아보자. 작은 완성이 큰 방향성을 만든다.
  • 오늘도 고생했다 내읻로 화이티잉!!!!

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 10:00 ~ 10:30 : 오전 데일리 스크럼 — 진행 상황 공유, 오늘 작업 범위 정의
  • 10:30 ~ 12:00 : Shooter 발사 흐름 정리 (Shoot → SpawnBullet → VFX/SFX) 및 스프레드/쿨다운 점검

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심시간

✅ 오후

  • 14:00 ~ 17:50 : 머즐 플래시 프리팹·스크립트 제작/연결(OnEnable 랜덤 스프라이트, 0.05초 유지)
    • SFX 피치 랜덤화 검토 → 보류(단일 사운드 유지, 간결성 우선)

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁시간

✅ 저녁

  • 19:00 ~ 종료 : 오후 데일리 스크럼 — 오늘 작업 회고, 내일 계획 합의(소음기 권총용 트레이서 구현부터)

✅ 오늘 학습 키워드

  • Shooter 발사 로직 정리, fireRate 쿨다운
  • 탄 퍼짐(Spread) 계산
  • 머즐 플래시(랜덤 스프라이트, 짧은 수명)
  • SFX 전략(단일 샷 사운드 유지, 피치 랜덤화는 차후)
  • 다음 작업: 소음기 권총 트레이서(탄 궤적/잔광)

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

  • 발사 흐름을 간단하고 읽히게 재정렬했다: Shoot()에서 입력 처리와 스프레드, SpawnBullet()에서 초기화, 그 뒤 VFX/SFX 호출로 관심사 분리가 선명해졌다.
  • 머즐 플래시는 호출부를 가볍게 유지하기 위해 프리팹 OnEnable에서 랜덤 스프라이트를 고르고 짧게 노출 후 제거하는 방식으로 확정했다.
  • 샷 SFX는 오늘은 단일 클립 고정으로 두고, 피치 랜덤화는 오디오 풀 도입 시 함께 적용하는 게 전체 성능/관리성에 유리하다고 판단했다.
  • 내일은 “소음기 권총” 특성에 맞춰 짧고 얇은 트레이서 + 낮은 플래시/볼륨으로 차별화할 계획이다.

🧩 학습하며 겪었던 문제점 & 에러

1) PlayClipAtPoint의 피치 한계

  • 문제 정의: PlayClipAtPoint는 pitch 제어 불가 → 소리 한 종류만 쓰면 단조로울 수 있음.
  • 시도: 임시 AudioSource 생성해 pitch 랜덤 재생 검토.
  • 해결 방법(오늘 선택): 단순성 유지(기존 그대로). 추후 오디오 소스 풀 도입 때 함께 적용.
  • 새롭게 알게 된 점: 잦은 발사에서 오브젝트 생성/파괴는 GC 스파이크 위험.
  • 다시 만나면: 풀에서 꺼낸 AudioSource로 원샷 + pitch = Random.Range(0.96f, 1.06f).

2) 머즐 플래시 생성/파괴 비용

  • 문제 정의: Instantiate → 0.05s → Destroy가 연사 시 누적 비용 가능.
  • 시도/결정: 현재는 구현 단순성을 우선.
  • 대안 메모: 나중에 풀링 전환 후 SetActive(true/false) 토글 + 짧은 알파 페이드로 전환하기.

📝 메모

  • 생각보다 간결함이 힘이 됐다. 구조를 정리하니 다음 작업(소음기 트레이서) 진입이 훨씬 수월해졌다.
  • “모르는 걸 부끄러워하지 말자.” 오늘은 과하게 욕심내지 않고 핵심 흐름부터 단단히 묶었다.
  • 다음주도 화이팅!!!

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 10:00 ~ 10:30 : 데일리 스크럼 진행(금일 작업 범위 확정)
  • 10:30 ~ 12:30 : 공용 사격 API 설계(Shoot(Vector2 dir) 한 함수로 통일)

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심시간

✅ 오후

  • 14:00 ~ 16:00 : Shooter2D 제작(플레이어/적 공용), Bullet 정리
  • 16:00 ~ 17:30 : 레이어 분리 및 Physics2D 충돌 매트릭스 정리(태그 사용 제거)
  • 17:30 ~ 18:00 : 트레일 렌더러(총알 궤적) 적용 및 기본 튜닝

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁시간

✅ 저녁

  • 19:00 ~ 20:20 : 사격 테스트(권총/라이플 SO), 피격 전달 점검
  • 20:20 ~ 21:00 : 리팩터링 메모 정리 & TIL

✅ 오늘 학습 키워드

  • 2D 탑뷰 사격 시스템, 공용 사격 API(Shoot(dir)), ScriptableObject(GunData)
  • Rigidbody2D + Trigger 충돌, 레이어 충돌 매트릭스, LayerMask
  • TrailRenderer(궤적 이펙트), 발사 속도(fireRate)·스프레드(spread) 튜닝
  • 인터페이스 기반 데미지 전달(IDamageable) vs SendMessage 비교

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

사격 로직을 플레이어/적에서 각각 구현하지 않고, 한 함수(Shoot(Vector2 dir))로 공용화했다. 총의 스펙은 SO(GunData)로 분리하여 데미지/속도/연사/스프레드를 데이터만 바꿔도 다르게 동작하도록 만들었다. 충돌 판정은 태그 의존을 제거하고, 레이어 분리 + Physics2D 충돌 매트릭스로 관리해 아군 오사/셀프히트를 깔끔하게 막았다. 총알 비주얼은 TrailRenderer만으로도 충분히 가볍고 예쁘게 만들 수 있어 우선 적용했고, 이후 필요하면 머즐플래시/피격 이펙트도 단계적으로 붙일 계획이다.


🧩 학습하며 겪었던 문제점 & 에러

1. 데미지 중복 적용 가능성

  • 문제정의
  • Bullet.OnTriggerEnter2D에서 SendMessage("TakeDamage")와 IDamageable.TakeDamage를 둘 다 호출할 여지가 있음.
  • 내가 한 시도
  • 먼저 IDamageable을 시도하고, 성공 시 SendMessage를 생략하도록 분기.
  • 해결 방법 (코드)
  • private void OnTriggerEnter2D(Collider2D other) { if (other.gameObject.layer == ignoreLayer) return; var target = other.GetComponent<IDamageable>(); if (target != null) { target.TakeDamage(dmg); } else { other.SendMessage("TakeDamage", dmg, SendMessageOptions.DontRequireReceiver); } Destroy(gameObject); }
  • 새롭게 알게 된 점
  • 인터페이스가 있으면 강타입/빠른 호출이 가능하고, 없을 때만 SendMessage로 느슨한 결합을 보완하면 구조가 깔끔해진다.
  • 다시 만나게 된다면
  • IDamageable을 프로젝트 공통 인터페이스로 정착시키고, SendMessage는 임시 호환용으로만 제한하겠다.

2. 아군/자기 자신 피격 이슈

  • 문제정의
  • 발사자와 같은 레이어 오브젝트에 총알이 맞는 케이스가 간헐적으로 발생.
  • 내가 한 시도
  • 총알 생성 시 총알의 레이어를 명시 세팅하고, Physics2D 충돌 매트릭스에서 PlayerBullet↔Player를 비활성화.
  • 해결 방법 (코드)
  • // 스폰 시 var go = Instantiate(bulletPrefab); go.layer = LayerMask.NameToLayer("PlayerBullet"); // 혹은 EnemyBullet var bullet = go.GetComponent<Bullet>(); bullet.Init(gunPoint.position, dir, speed, damage, life, ignoreLayer: LayerMask.NameToLayer("Player"));
  • 새롭게 알게 된 점
  • 레이어/충돌 매트릭스만 잘 잡아도 복잡한 태그 분기 없이 안전한 피격 처리가 가능하다.
  • 다시 만나게 된다면
  • 기능 추가 전 레이어 설계 문서를 먼저 쓰고, 매트릭스를 표로 관리하겠다.

3. TrailRenderer 궤적이 너무 길거나 둔탁해 보이는 문제

  • 문제정의
  • 기본값으로는 궤적이 길고 두꺼워 보여 게임 템포와 맞지 않음.
  • 내가 한 시도
  • Time, Min Vertex Distance, Width Curve 조정.
  • 해결 방법 (권장값)
    • Time: 0.08 ~ 0.15s
    • Min Vertex Distance: 0.05 ~ 0.1
    • Width Curve: 앞부분 0.06 → 뒤 0
    • Material: Additive(URP면 Bloom과 함께 쓰면 광택 증가)
    // 필요 시 코드로도 가능
    var tr = bulletGO.GetComponent<TrailRenderer>();
    tr.time = 0.12f;
    tr.minVertexDistance = 0.08f;
    var curve = new AnimationCurve();
    curve.AddKey(0f, 0.06f);
    curve.AddKey(1f, 0f);
    tr.widthCurve = curve;
    
  • 새롭게 알게 된 점
  • 짧고 가는 궤적이 탑뷰 캐주얼에 더 잘 어울리고, 퍼포먼스에도 유리하다.
  • 다시 만나게 된다면
  • 색상 2~3안(노랑/청록/보라) 프리셋을 미리 만들어 맵 분위기에 맞춰 빠르게 교체하겠다.

📝 메모

오늘은 사격 시스템 핵심을 공용 API로 단순화한 게 가장 큰 수확이다. 태그를 과감히 빼고 레이어로만 정리하니 충돌/피격 흐름이 훨씬 명확해졌다. 궤적은 TrailRenderer만으로도 충분히 보기 좋아져서, 당장 게임의 피드백이 살아난 느낌이다. 내일은 머즐 플래시/히트 이펙트를 가볍게 붙이고, 오브젝트 풀링으로 총알 생성 비용을 줄여보겠다.

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 12:00 : 입력 액션 맵 정리( Move/Run/Interact/Menu/Attack/Look ) 및 PlayerInput( Send Messages ) 세팅

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심

✅ 오후

  • 14:00 ~ 16:00 : 2D 탑다운 이동 완성 (Rigidbody2D.Kinematic + MovePosition) / 마우스 에임 바라보기 로직 적용 / InputValue → InputAction.CallbackContext 전환, PlayerInputController partial 분리
  • 16:00 ~ 18:00 : 팀 회의(진척 공유, 입력/조준 구조 리뷰)

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁

✅ 저녁

  • 19:00 ~ 21:00 : 기획 회의 – 핵심 재미(“발각되지 않고 목표물 획득 후 흔적 없이 사라지는 쾌감”) 확정, 튜토리얼 플로우 초안(시야/각도‧소리‧경보‧탈출 루프) 정리

✅ 오늘 학습 키워드

  • Unity Input System / CallbackContext
  • PlayerInput Send Messages 규약
  • 2D 탑다운 이동: Rigidbody2D.Kinematic + MovePosition
  • 마우스 에임 고정 회전(속도 Fallback 제거)
  • DOTween UI 이펙트(크로스헤어 펄스)
  • 이벤트 허브: TopDownController / 컴포넌트 분리(partial)
  • MissingMethodException(메서드명 충돌) 트러블슈팅

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

  • 입력 레이어를 PlayerInputController(partial)로 깔끔히 분리하고, 실제 이동/회전은 TopDownMovement가 이벤트로만 받도록 만들어 의존성을 낮췄다.
  • 회전은 오직 마우스 에임만 기준으로 하여, 이동 방향에 영향을 받지 않도록 했다(스텔스 조작감에 더 적합).
  • UI 크로스헤어는 캔버스 기준으로 마우스를 추적하고, Attack 시 DOTween으로 작아졌다 커지는 펄스를 주어 타격감을 확보했다.
  • SendMessages는 런타임에 메서드명을 리플렉션으로 찾기 때문에 이름 충돌을 만들지 않는 것이 핵심. 입력 수신자는 OnMove/OnLook만 두고, 나머지 컴포넌트는 Handle*로 구독하게 했다.

🧩 학습하며 겪었던 문제점 & 에러

1. MissingMethodException: Method 'OnLook' not found

  • 문제 정의: PlayerInput(Send Messages)가 같은 오브젝트의 OnLook/OnMove를 호출하려다, 다른 컴포넌트에도 동일한 이름이 있어 충돌 발생.
  • 시도: 시그니처 정리만 했더니 여전히 예외 발생.
  • 해결 방법: 입력 수신자만 OnMove/OnLook(CallbackContext) 유지, 나머지는 이름 변경.
  • 핵심 코드
  • // TopDownMovement.cs private void OnEnable() { controller.OnMoveEvent += HandleMoveInput; controller.OnLookEvent += HandleLookInput; } private void HandleMoveInput(Vector2 v) => moveInput = v; private void HandleLookInput(Vector2 v) => lastLookDir = v.normalized;
  • 새롭게 알게 된 점: Send Messages는 메서드명 일치가 절대적.
  • 다시 만나면: 초기에 “입력 클래스 전용 On* / 나머지는 Handle*” 네이밍 규칙을 문서화.

2. 마우스 방향으로 안 돌아가는 문제

  • 문제 정의: 이동 방향으로 회전하는 Fallback 때문에 마우스 에임이 무시됨.
  • 해결 방법: 회전은 lastLookDir만 기준으로, 에임은 매 프레임 마우스 위치로 갱신.
  • // 회전부 var dir = lastLookDir; float ang = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f; rb.MoveRotation(Mathf.MoveTowardsAngle(rb.rotation, ang, rotationSpeed * Time.fixedDeltaTime));
  • 배움: 스텔스 조작감은 시선 고정이 중요. 이동/시선 역할을 분리하니 컨트롤이 깔끔해졌다.

3. 크로스헤어 UI 위치가 어긋남(카메라 모드별)

  • 문제 정의: Screen Space - Camera에서 RectTransform.position만 쓰면 오차.
  • 해결 방법: RectTransformUtility.ScreenPointToLocalPointInRectangle 사용.
  • if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, screen, uiCam, out var local)) crosshair.anchoredPosition = local;

📝 메모

오늘은 입력/조준/이펙트까지 “핵심 조작감” 뼈대를 깔끔히 잡았다. 팀 회의로 기획 방향도 선명해졌고, 내가 구현한 구조가 그 방향과 잘 맞아서 뿌듯했다.

내일은 나머지 플레이어 공격에 대한 조작과 애니메이션을 추가해봐야겠다 재밌는 게임이 완성될듯하다!! 내일도 화이팅!!!!


반응형