no image
DesignPattern - 옵저버(Observer) 패턴
🔭 Unity 디자인 패턴 - 옵저버(Observer) 패턴1. 옵저버 패턴이란?옵저버(Observer) 패턴은 어떤 객체의 상태가 변경될 때, 그 객체를 "구독"하고 있는 다른 객체들에게 자동으로 알림을 보내는 구조입니다. Unity에서는 UI나 게임 오브젝트가 데이터나 이벤트의 변경을 실시간으로 반영해야 할 때 자주 사용됩니다."플레이어의 체력이 변하면 체력바가 자동으로 바뀌는 것"이 대표적인 예입니다.2. 언제 사용하나요?플레이어 체력/마나 등의 수치 변화 → UI 업데이트게임 설정 변경 → 여러 오브젝트에 즉시 반영이벤트 중심 구조로 게임 로직을 관리할 때3. 구조 설명Subject (발행자): 상태를 가지고 있는 객체. 변화가 생기면 옵저버에게 알림Observer (구독자): Subject의 ..
2025.08.06
no image
Unity - Input System - InputAction
🎮 Unity Input System - InputAction 완전 정복1. 🧭 InputAction이란?InputAction은 Unity의 새 Input System에서 사용자의 입력을 추상화하여 "행동" 단위로 정의하는 구성 요소입니다.예를 들어 Jump, Move, Shoot 같은 게임 내 행동(행위) 을 정의하고, 여기에 어떤 키보드/마우스/게임패드 입력이 연결될지를 설정합니다.📦 InputAction 구성 구조InputActionAsset └─ Action Map (예: Player) └─ InputAction (예: Move, Jump) └─ Binding (예: WASD, Spacebar, Gamepad A버튼)InputActionAsset: 모든 입력 행동을 담는..
2025.08.06
no image
내일배움캠프 27일차 TIL [팀프로젝트 마무리 + 발표]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 13:00 :프로젝트 시연 영상 2종 촬영GitHub README 파일 최종 수정결과보고서 최종 점검프로젝트 기능 최종 확인 및 점검최종 발표 준비 진행🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 18:00 :최종 프로젝트 발표 및 발표 시청🍽️ 저녁시간18:00 ~ 19:00 : 저녁시간✅ 저녁19:00 ~ 21:00 :객체지향 프로그래밍 강의 수강✅ 오늘 학습 키워드프로젝트 최종 점검 및 발표GitHub 리드미 수정객체지향 프로그래밍 강의 수강✅ 오늘 학습 한 내용을 나만의 언어로 정리하기오늘은 그동안 진행했던 팀 프로젝트의 마무리 단계로, 오전에는 결과물 점검과 발표 준비에 집중했습니다. 먼저 게임 시연을 위한 영상 2개를 촬영..
2025.08.05
no image
프로젝트 소개 - 「현대세계 최후의 궁수」
🎮 1. 게임 소개이번 프로젝트는 '궁수의 전설(Archero)'에서 영감을 받아 제작한 탑다운 슈팅 기반의 액션 게임입니다.현대 세계를 배경으로, 마지막 남은 궁수가 되어 적들을 물리치고 스테이지를 클리어하는 것이 목표입니다.게임의 제목은 **「현대세계 최후의 궁수」**입니다.유저는 다양한 무기와 스킬을 활용하여 몬스터와 보스를 처치하고, 방을 클리어하며 점점 더 강해지는 전투를 경험할 수 있습니다.🕹️ 2. 플레이 방법이동 조작 : W, A, S, D 키로 캐릭터를 상하좌우로 움직입니다.공격 조작 : 마우스 좌클릭으로 공격합니다. 자동 발사 방식이 아니며, 직접 눌러야 발사됩니다.스킬 선택 : 방을 클리어할 때마다 3개의 스킬 중 하나를 무작위로 선택하여 강화할 수 있습니다.스테이지 진행 : 각 ..
2025.08.05
no image
내일배움캠프 26일차 TIL [팀프로젝트(Archero)]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 11:00 : StageChangeTrigger 조건문 로직 디버깅11:00 ~ 12:30 : MonsterSpawnManager 개선 (스폰 포인트별로 몬스터 순차 소환 / 프리팹 랜덤)🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 15:30 : 카메라와 Canvas 연결 이슈 해결 (CanvasCameraSetter.cs)15:30 ~ 17:00 : MainCamera 정리 및 Orthographic vs Perspective 비교 학습17:00 ~ 18:00 : GitHub 커밋 히스토리 기반 금요일/월요일 작업 정리, 스크립트 구조 설계 리팩토링🍽️ 저녁시간18:00 ~ 19:00 : 저녁시간✅ 저녁19:00 ~ 21:00 : ..
2025.08.04
no image
Unity - Unity의 메인 카메라(Main Camera) & Projection
🎥 Unity의 메인 카메라(Main Camera)란?✅ 1. 기본 정의Unity 씬(Scene)에서 **플레이어가 보는 시점(Viewport)**을 결정하는 렌더링 카메라기본적으로 Main Camera 태그를 가진 GameObject로 자동 생성됨Camera.main 으로 쉽게 접근할 수 있음 (GameObject.FindWithTag("MainCamera")의 성능 최적화 버전)✅ 2. Camera 주요 설정속성설명Clear Flags배경을 어떻게 처리할지 결정 (Skybox, Solid Color, Depth Only, Don't Clear)Culling Mask어떤 레이어의 오브젝트만 렌더링할지 선택Projection카메라 투영 방식 (Perspective: 원근, Orthographic: 평면..
2025.08.04
no image
WIL - 본 캠프 5주차(25.07.28~08.01)
1. 이번 주 가장 인상 깊었던 배움은 무엇이었나요?Skill & Upgrade System을 ScriptableObject 기반으로 설계하고, 실제 게임 흐름에 연동시켜본 경험이 가장 인상 깊었다.그동안 ScriptableObject를 단순 데이터 저장 용도로만 이해하고 있었는데, 이번 주에는 게임 흐름 안에서 그 데이터를 실시간으로 불러오고 UI와 연동해, 유저가 스킬을 선택하고 실제로 적용되도록 구현해봤다.특히 방을 클리어할 때 무작위 스킬 카드들이 뜨고, 선택된 스킬이 플레이어 능력치나 특성에 영향을 미치는 흐름을 만들면서,단순한 데이터 보관이 아니라 확장성과 유지보수를 고려한 설계 방식이라는 걸 직접 체감했다.단순히 기능을 넣은 것이 아니라, UI 흐름과 연계하고 PlayerState에 적용되도..
2025.08.04
no image
내일배움캠프 25일차 TIL [팀프로젝트(Archero)]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 13:00 : GitHub 커밋 및 기능 구현보스 일반 공격 충돌 문제 해결스테이지 클리어 UI 기능 마무리보스 중력 및 히트 애니메이션, 붉은색 피격 효과 적용몬스터 사운드, 파티클, HP Bar 상호작용 기능 추가 및 수정튜토리얼 관련 버그 수정 및 기능 개선StageChangeButton 관련 로직 개선 시도🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 18:00 :몬스터 FSM과 SpawnManager 연결 로직 점검스테이지 전환 중 클리어 처리 예외 상황 확인보스 태그/프리팹 설정 및 애니메이션 처리 개선GitHub 정리 및 커밋 다수 진행🍽️ 저녁시간18:00 ~ 19:00 : 저녁시간✅ 저녁19:00 ~ 21:00 : 팀원..
2025.08.01
반응형

🔭 Unity 디자인 패턴 - 옵저버(Observer) 패턴

1. 옵저버 패턴이란?

옵저버(Observer) 패턴은 어떤 객체의 상태가 변경될 때, 그 객체를 "구독"하고 있는 다른 객체들에게 자동으로 알림을 보내는 구조입니다. Unity에서는 UI나 게임 오브젝트가 데이터나 이벤트의 변경을 실시간으로 반영해야 할 때 자주 사용됩니다.

"플레이어의 체력이 변하면 체력바가 자동으로 바뀌는 것"이 대표적인 예입니다.


2. 언제 사용하나요?

  • 플레이어 체력/마나 등의 수치 변화 → UI 업데이트
  • 게임 설정 변경 → 여러 오브젝트에 즉시 반영
  • 이벤트 중심 구조로 게임 로직을 관리할 때

3. 구조 설명

  • Subject (발행자): 상태를 가지고 있는 객체. 변화가 생기면 옵저버에게 알림
  • Observer (구독자): Subject의 변화를 감지하고 반응하는 객체들

4. Unity 예제: 플레이어 체력 변화 → 체력바 UI 갱신

📦 인터페이스 정의 (옵저버 공통)

public interface IHealthObserver
{
    void OnHealthChanged(int current, int max);
}

🎮 Subject: Player

using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    private int maxHp = 100;
    private int currentHp;

    private List<IHealthObserver> observers = new();

    private void Start()
    {
        currentHp = maxHp;
    }

    public void TakeDamage(int damage)
    {
        currentHp = Mathf.Max(currentHp - damage, 0);
        NotifyObservers();
    }

    public void Heal(int amount)
    {
        currentHp = Mathf.Min(currentHp + amount, maxHp);
        NotifyObservers();
    }

    public void AddObserver(IHealthObserver observer)
    {
        if (!observers.Contains(observer)) observers.Add(observer);
    }

    public void RemoveObserver(IHealthObserver observer)
    {
        if (observers.Contains(observer)) observers.Remove(observer);
    }

    private void NotifyObservers()
    {
        foreach (var observer in observers)
        {
            observer.OnHealthChanged(currentHp, maxHp);
        }
    }
}

🖼️ Observer: HealthBar

using UnityEngine;
using UnityEngine.UI;

public class HealthBar : MonoBehaviour, IHealthObserver
{
    [SerializeField] private Slider slider;
    private Player player;

    private void Start()
    {
        player = FindObjectOfType<Player>();
        player?.AddObserver(this);
        OnHealthChanged(playerHp: 100, maxHp: 100); // 초기화
    }

    public void OnHealthChanged(int playerHp, int maxHp)
    {
        slider.value = (float)playerHp / maxHp;
    }

    private void OnDestroy()
    {
        player?.RemoveObserver(this);
    }
}

5. 정리 및 장단점

✅ 장점

  • 느슨한 결합 (Player와 UI는 서로 직접 몰라도 됨)
  • 실시간 반응 구조
  • 여러 객체에 동일한 변화 전파 가능

❌ 단점

  • Observer 등록/해제 누락 시 예기치 않은 동작 발생
  • 규모가 커지면 디버깅이 어려워질 수 있음

✅ 마무리 한 줄 요약

옵저버 패턴은 "어떤 일이 생기면 알려줄게" 라는 약속으로, 게임 내 실시간 반응형 구조를 만드는 데 매우 유용한 패턴입니다.

 

반응형
반응형

🎮 Unity Input System - InputAction 완전 정복

1. 🧭 InputAction이란?

InputAction은 Unity의 새 Input System에서 사용자의 입력을 추상화하여 "행동" 단위로 정의하는 구성 요소입니다.

예를 들어 Jump, Move, Shoot 같은 게임 내 행동(행위) 을 정의하고, 여기에 어떤 키보드/마우스/게임패드 입력이 연결될지를 설정합니다.


📦 InputAction 구성 구조

InputActionAsset
 └─ Action Map (예: Player)
     └─ InputAction (예: Move, Jump)
         └─ Binding (예: WASD, Spacebar, Gamepad A버튼)
  • InputActionAsset: 모든 입력 행동을 담는 설정 파일 (보통 .inputactions 확장자)
  • Action Map: 논리적인 입력 그룹 (예: Player, UI, Vehicle 등)
  • InputAction: 실제 행동 정의 (Move, Jump, Fire 등)
  • Binding: 특정 입력 장치와의 연결 (키보드, 마우스, 게임패드 등)

⚙️ 기존 방식 vs InputAction

기존 방식 InputAction
Input.GetKeyDown(KeyCode.Space) InputAction("Jump").performed += ...
코드 내에 직접 키 입력 체크 행동 단위로 추상화된 구조
입력마다 조건문 필요 입력 행동별로 분리 가능
디바이스 변경 시 코드 수정 하나의 Action에 여러 디바이스 바인딩 가능

💬 한 마디로 정리하면?

"InputAction은 '어떤 키를 눌렀는가'가 아니라, '어떤 행동을 실행할 것인가'에 집중하는 시스템입니다."

이 방식은 복잡한 입력 처리, 다양한 디바이스 대응, 깔끔한 코드 구조 등을 모두 만족시킬 수 있어 중대형 프로젝트에서 특히 강력한 입력 처리 구조입니다.


2. 🎯 InputAction 타입 종류

InputAction을 만들 때 선택할 수 있는 Action Type은 세 가지가 있습니다:

① Button (버튼 입력)

  • 가장 기본적인 입력 방식입니다.
  • 키보드나 게임패드의 특정 버튼처럼 눌렀다 뗐다의 이벤트를 감지합니다.
  • 예: 점프, 공격, 상호작용 등
InputAction jumpAction = new InputAction(type: InputActionType.Button);
jumpAction.performed += ctx => Jump();
  • 관련 phase:
    • started: 버튼이 눌리는 순간
    • performed: 동작이 수행된 순간
    • canceled: 버튼에서 손을 뗀 순간

② Value (값 입력)

  • 방향키, 스틱, 마우스 이동 등 연속적인 값을 처리할 때 사용합니다.
  • Vector2, float, int 등 다양한 타입의 값을 받아 처리할 수 있습니다.
  • 예: 이동, 마우스 위치, 줌 레벨 등
InputAction moveAction = new InputAction(type: InputActionType.Value);
Vector2 moveDir = moveAction.ReadValue<Vector2>();

③ Pass-through (즉시 전달형)

  • Unity 이벤트나 다른 처리 로직을 통하지 않고 바로 값 전달이 필요한 경우 사용합니다.
  • performed만 호출되며 started, canceled은 호출되지 않습니다.
  • 보통 처리 과정을 생략하고 입력 값을 그대로 넘겨야 할 때 사용됩니다.
InputAction lookAction = new InputAction(type: InputActionType.PassThrough);
lookAction.performed += ctx => Look(ctx.ReadValue<Vector2>());

✅ 타입 선택 기준 요약

타입 사용 예시 특징
Button 점프, 공격 상태 변화가 있는 단순 입력 처리
Value 이동, 카메라, 줌 값의 변화량을 지속적으로 감지
Pass-through 마우스 이동 빠르고 직접적인 값 전달, 필터 없음

 

3. 🧠 InputAction 이벤트 처리 완전 이해

InputAction의 입력 이벤트는 CallbackContext를 통해 다양한 정보를 제공합니다.

📌 CallbackContext란?

InputAction.CallbackContext는 입력 이벤트가 발생했을 때 전달되는 구조체입니다. 이 안에는 어떤 값이 눌렸는지, 어떤 상태인지 등 중요한 정보가 담겨 있습니다.


📍 주요 속성 설명

속성 설명
ctx.phase 입력의 현재 상태 (Started, Performed, Canceled)
ctx.ReadValue<T>() 입력값을 원하는 타입으로 받아옴 (예: Vector2, float, bool)
ctx.control.name 어떤 입력 컨트롤이 눌렸는지 확인 가능

✅ phase란?

  • Started: 키가 눌리기 시작했을 때 호출
  • Performed: 실제 동작이 완료되었을 때 호출 (ex. 스페이스바 눌러서 점프)
  • Canceled: 입력이 해제됐을 때 호출 (ex. 키에서 손 뗌)
public void OnJumpInput(InputAction.CallbackContext context)
{
    if (context.phase == InputActionPhase.Started)
    {
        Debug.Log("점프 시작!");
    }
    else if (context.phase == InputActionPhase.Performed)
    {
        Debug.Log("점프 실행!");
    }
    else if (context.phase == InputActionPhase.Canceled)
    {
        Debug.Log("점프 해제!");
    }
}

✅ ReadValue()란?

입력으로부터 값을 받을 때 사용되는 함수입니다.

  • ReadValue<Vector2>() → 방향키 입력
  • ReadValue<float>() → 마우스 휠, 트리거 압력
  • ReadValue<bool>() → 단순 버튼 on/off
Vector2 movement = context.ReadValue<Vector2>();

※ 제네릭 타입을 잘못 입력하면 런타임 에러가 발생할 수 있으니 주의해야 합니다.

 

 

 

4. 🧩 PlayerInput 컴포넌트와 InputAction 연동

InputAction을 사용하려면 Unity 오브젝트에 실제 입력을 받을 수단이 필요합니다. 바로 그것이 PlayerInput 컴포넌트입니다.

PlayerInput은 InputActionAsset과 연동되어 입력을 받아 동작을 실행하도록 해주는 중계자 역할을 합니다.


✅ PlayerInput의 구성 요소

항목 설명
Actions 사용할 InputActionAsset 파일 지정
Default Map 시작 시 활성화할 Action Map 선택 (예: "Player")
Behavior 이벤트 처리 방식 선택 (SendMessage, UnityEvents, Invoke C# Events 등)
Camera Look 입력을 카메라 기준으로 보정할 경우 연결

⚙️ Behavior 방식 비교

① SendMessage 방식

  • Unity의 기본 메시지 시스템 활용
  • 액션 이름과 같은 이름의 함수를 MonoBehaviour에서 자동으로 찾아 호출
void OnJump(InputValue value) { ... }
  • ✅ 빠른 구현 가능 / ❌ 퍼포먼스 이슈 가능, 함수명 일치 필수

② UnityEvents 방식

  • 인스펙터에서 액션별로 함수 연결 가능
  • 비개발자도 설정 가능하여 협업에 유리
  • PlayerInputEvents 탭에서 직접 함수 연결
// PlayerController.cs
public void OnMove(InputAction.CallbackContext context) { ... }

③ C# Events 방식

  • 가장 유연하고 퍼포먼스가 좋은 방식
  • 코드에서 직접 InputAction에 접근하고 .performed += 으로 연결
playerInput.actions["Jump"].performed += ctx => Jump();
  • ✅ 코드 기반으로 철저히 제어 가능 / ❌ 초보자에겐 진입장벽 있음

🎮 실습 예시: UnityEvents 방식 연결

  1. Player 오브젝트에 PlayerInput 컴포넌트 추가
  2. Actions에 .inputactions 파일 연결
  3. Behavior를 Invoke Unity Events로 설정
  4. PlayerController 스크립트에 이벤트 함수 작성
  5. 인스펙터에서 해당 액션에 함수 연결
public void OnMove(InputAction.CallbackContext context)
{
    Vector2 input = context.ReadValue<Vector2>();
    // 이동 처리
}

🔍 팁: PlayerInput 자동 생성 방지하기

PlayerInput 컴포넌트를 수동으로 붙여 쓰는 경우, 코드나 다른 매니저에서 InputAction을 생성하면 중복 생성될 수 있습니다. 항상 하나의 PlayerInput만 사용하도록 주의.

 

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 13:00 :
    • 프로젝트 시연 영상 2종 촬영
    • GitHub README 파일 최종 수정
    • 결과보고서 최종 점검
    • 프로젝트 기능 최종 확인 및 점검
    • 최종 발표 준비 진행

🍽️ 점심시간

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

✅ 오후

  • 14:00 ~ 18:00 :
    • 최종 프로젝트 발표 및 발표 시청

🍽️ 저녁시간

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

✅ 저녁

  • 19:00 ~ 21:00 :
    • 객체지향 프로그래밍 강의 수강

✅ 오늘 학습 키워드

  • 프로젝트 최종 점검 및 발표
  • GitHub 리드미 수정
  • 객체지향 프로그래밍 강의 수강

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

오늘은 그동안 진행했던 팀 프로젝트의 마무리 단계로, 오전에는 결과물 점검과 발표 준비에 집중했습니다. 먼저 게임 시연을 위한 영상 2개를 촬영하고, GitHub의 README를 최종적으로 다듬어 프로젝트를 보다 이해하기 쉽고 보기 좋게 구성했습니다. 이후 결과보고서를 다시 확인하며 누락된 내용이 없는지 꼼꼼히 점검했고, 실제로 게임 기능을 최종 점검하면서 발생할 수 있는 예외 상황도 다시 확인했습니다.

오후에는 팀원들과 함께 프로젝트를 발표하고, 다른 팀의 발표도 시청하며 다양한 아이디어를 접할 수 있었습니다. 발표를 통해 우리 팀의 작업이 체계적으로 잘 정리되었다는 느낌을 받았고, 다른 팀의 피드백을 들으며 앞으로 개선할 점도 생각해볼 수 있었습니다.


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


📝 메모

오늘은 일주일 동안 집중해서 달려온 팀 프로젝트의 마지막 날이었습니다. 결과물을 발표하면서 다른 팀의 작업을 보며 비교도 해보고, 우리 팀만의 강점과 앞으로 보완하면 좋을 점도 함께 느낄 수 있는 시간이었습니다.

무엇보다 이번 팀원들과의 호흡이 너무 좋아서 헤어지는 것이 유난히 아쉽게 느껴졌습니다. 새로운 팀으로 배정받을 때마다 항상 이별의 아쉬움은 있었지만, 이번에는 특히 마음이 많이 가서 그런지 더 깊은 여운이 남습니다.

용민님, 유경님, 노아님, 세윤님, 우리 팀원들! 팀장 잘못 만나서 3D로 고생 많으셨죠ㅎㅎ… 그럼에도 불구하고 묵묵히 따라와 주셔서 정말 고맙습니다. 여러분 덕분에 이 프로젝트가 끝까지 완성될 수 있었습니다.

언젠가 또 만나 함께 웃으며 개발할 수 있기를 진심으로 바랍니다. 감사했고, 또 고마웠어요! 😊

 

 

프로젝트 소개 - 「현대세계 최후의 궁수」

🎮 1. 게임 소개이번 프로젝트는 '궁수의 전설(Archero)'에서 영감을 받아 제작한 탑다운 슈팅 기반의 액션 게임입니다.현대 세계를 배경으로, 마지막 남은 궁수가 되어 적들을 물리치고 스테이지

dev-jen.tistory.com

이번에 진행한 현대세계 최후의 궁수 프로젝트입니다!

반응형
반응형

🎮 1. 게임 소개

이번 프로젝트는 '궁수의 전설(Archero)'에서 영감을 받아 제작한 탑다운 슈팅 기반의 액션 게임입니다.
현대 세계를 배경으로, 마지막 남은 궁수가 되어 적들을 물리치고 스테이지를 클리어하는 것이 목표입니다.
게임의 제목은 **「현대세계 최후의 궁수」**입니다.
유저는 다양한 무기와 스킬을 활용하여 몬스터와 보스를 처치하고, 방을 클리어하며 점점 더 강해지는 전투를 경험할 수 있습니다.


🕹️ 2. 플레이 방법

  • 이동 조작 : W, A, S, D 키로 캐릭터를 상하좌우로 움직입니다.
  • 공격 조작 : 마우스 좌클릭으로 공격합니다. 자동 발사 방식이 아니며, 직접 눌러야 발사됩니다.
  • 스킬 선택 : 방을 클리어할 때마다 3개의 스킬 중 하나를 무작위로 선택하여 강화할 수 있습니다.
  • 스테이지 진행 : 각 방을 클리어하면 자동으로 다음 방으로 이동되며, 최종 방에서는 보스가 등장합니다.

🛠 3. 사용 기술

본 프로젝트는 Unity 엔진을 기반으로 개발되었으며, 다음과 같은 기술들을 활용하였습니다:

  • Unity 2022.3.4f1 : 프로젝트 전체 구성 및 게임 구현
  • C# : 게임 로직 전반 구현
  • GitHub : 협업을 위한 형상 관리 및 버전 관리
  • ScriptableObject : 스킬 데이터 관리 및 확장성 있는 구조 구성
  • Singleton + Manager Pattern : GameManager, SoundManager 등 핵심 매니저 구조 설계
  • FSM 기반 보스 AI : 상태 전이에 따라 공격, 이동, 스킬 등을 제어
  • 랜덤 방 생성 알고리즘 : 던전 구조를 무작위로 생성하여 반복 플레이 요소 강화
  • 2D Sprite Animation : 플레이어 및 적 애니메이션 구현
  • Sound System : BGM 및 효과음 관리

✨ 4. 주요 구현 기능

  • 무작위 스킬 선택 시스템
    방을 클리어할 때마다 3개의 스킬 중 1개를 선택해 능력을 강화할 수 있으며, ScriptableObject 기반으로 유연하게 확장 가능합니다.
  • 스테이지 클리어 흐름 및 UI 연결
    플레이어가 모든 몬스터를 처치하면 스테이지가 클리어되고, 이후 보상 및 다음 스테이지로 자연스럽게 넘어가는 구조를 구현하였습니다.
  • 보스 패턴 구현
    FSM 구조를 기반으로 한 보스의 다양한 패턴 공격과 애니메이션 전환 로직을 구현하였습니다.
  • 사운드 매니저 및 효과음 시스템
    배경음과 효과음을 상황에 따라 다르게 출력하고, 중복 재생 방지 및 볼륨 설정 기능을 추가하였습니다.

🖼 5. 게임 화면

아래는 실제 게임 실행 화면 일부입니다. 플레이어 조작, 스킬 선택, 보스전, UI 구성이 포함된 장면으로, 다양한 게임 요소들이 조화를 이루도록 구현하였습니다.

  • 기본 전투 화면: 플레이어가 적을 향해 자동으로 공격하며, 일정 시간마다 보조 스킬을 사용할 수 있도록 구성하였습니다.
  • 스킬 선택 UI: 스테이지 클리어 시 3개의 스킬 중 1개를 선택하여 성장하는 방식이며, 시각적 피드백을 강화한 UI 디자인으로 몰입감을 높였습니다.
  • 보스 전투 화면: 보스의 다양한 공격 패턴이 적용되며, 체력 바 및 연출이 강화된 별도 스테이지에서 진행됩니다.
  • 게임 클리어 화면: 최종 보스를 처치하면 승리 연출과 함께 엔딩 씬으로 전환됩니다.
  • 타이틀 화면, 튜토리얼 화면 등등..

 

설명 추가 되어있는 영상

 

짧은 설명 X 영상

 


📂 6. 프로젝트 폴더 구조

📦 02. Scripts/
├── 📂Boss/ # 보스 관련 제어 스크립트
│ ├── Axe.cs # 보스 무기 충돌 감지
│ ├── BossController.cs # 보스 상태 전이 및 FSM
│ └── BossHpBar.cs # 보스 체력 UI
├── 📂Camera/
│ └── CanvasCameraSetter.cs # UI 캔버스에 메인 카메라 자동 연결
├── 📂Manager/ # 전역 시스템 관리자 클래스들
│ ├── 📂Camera/
│ │ └── CameraManager.cs
│ ├── 📂Monster/
│ │ └── MonsterSpawnManager.cs
│ ├── 📂PlayerSpawn/
│ │ └── PlayerSpawnManager.cs
│ ├── 📂Skill/
│ │ └── SkillManager.cs
│ ├── 📂Sound/
│ │ ├── PlayerSound.cs
│ │ └── SoundManager.cs
│ ├── 📂Stage/
│ │ ├── NextStageParticle.cs
│ │ └── StageManager.cs
│ ├── 📂Tutorial/
│ │ └── SkillTutorialUIManager.cs
│ ├── 📂UI/
│ │ ├── 📂Player/
│ │ │ ├── PlayerHpBar.cs
│ │ │ └── PlayerStatUI.cs
│ │ ├── 📂SettingUI/
│ │ │ └── SoundUI.cs
│ │ ├── 📂Skill/
│ │ │ └── SkillUIManager.cs
│ │ ├── 📂Tutorial/
│ │ │ └── TutorialSlotUI.cs
│ │ └── UIManager.cs
│ └── GameManager.cs # 게임 전반 흐름 관리
├── 📂Monster/ # 일반 몬스터 AI 및 전투 관련 스크립트
│ ├── Melee_Damage.cs
│ ├── MonsterFSM.cs
│ ├── MonsterHpBar.cs
│ ├── MonsterParticleControl.cs
│ ├── MonsterProjectile.cs
│ └── MonsterStat.cs
├── 📂Player/ # 플레이어 조작 및 상태 관리
│ ├── Bullet.cs
│ ├── PlayerMovement.cs
│ ├── PlayerShooting.cs
│ └── PlayerStat.cs
├── 📂ScriptableObject/ # 스킬 데이터 저장용 ScriptableObject
│ └── SkillData_ScriptableObject.cs
├── 📂Singleton/ # 제너릭 싱글톤 베이스 클래스
│ └── Singleton.cs
├── 📂Sound/ # 사운드 재생 소스
│ └── SoundSource.cs
├── 📂Stage/ # 스테이지 전환 로직
│ └── StageChanger.cs
├── 📂Test/ # 테스트 및 디버깅용
│ ├── End.cs
│ └── TimeController.cs
├── 📂UI/ # UI 관련 스크립트
│ ├── 📂Animation/
│ │ └── UIAnimationHandler.cs
│ ├── 📂Production/
│ │ └── Siren.cs
│ ├── 📂Skill/
│ │ └── SkillSlotUI.cs
│ └── 📂Title/
│ ├── StageChangeButton.cs
│ └── StateChangeButton.cs
├── 📂Utils/ # 유틸리티 스크립트
└── └── EnemyUtil.cs

 


👤 7. 개발자

이름 역할 담당 업무 요약
이재은 팀장 스킬 및 업그레이드 시스템 구현, UI 시스템 제작, 전체 프로젝트 구조 설계 및 총괄
김용민 팀원 랜덤 방 생성 로직 구현, 배경 및 사운드 전반 설정
정세윤 팀원 보스전 로직 설계 및 구현 (AI, 애니메이션 전환, 보스 연출 등)
김유경 팀원 적 AI 설계, 공격 패턴 작성 및 난이도 조정
김노아 팀원 플레이어 이동 및 공격 시스템 구현, QA 테스트 및 전반적 기능 보완

🛠 8. 트러블슈팅 (문제 해결 기록)

 

 

👤 9. 자체 평가 의견

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 11:00 : StageChangeTrigger 조건문 로직 디버깅
  • 11:00 ~ 12:30 : MonsterSpawnManager 개선 (스폰 포인트별로 몬스터 순차 소환 / 프리팹 랜덤)

🍽️ 점심시간

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

✅ 오후

  • 14:00 ~ 15:30 : 카메라와 Canvas 연결 이슈 해결 (CanvasCameraSetter.cs)
  • 15:30 ~ 17:00 : MainCamera 정리 및 Orthographic vs Perspective 비교 학습
  • 17:00 ~ 18:00 : GitHub 커밋 히스토리 기반 금요일/월요일 작업 정리, 스크립트 구조 설계 리팩토링

🍽️ 저녁시간

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

✅ 저녁

  • 19:00 ~ 21:00 : 팀원들과 함께 프로젝트 결과 보고서 작성
  • 21:00 ~ 22:00 : 트러블슈팅 정리 (제너릭 싱글톤 적용 / ScriptableObject 스킬 시스템 구조 정리)

✅ 오늘 학습 키워드

 

Unity - Unity의 메인 카메라(Main Camera) & Projection

🎥 Unity의 메인 카메라(Main Camera)란?✅ 1. 기본 정의Unity 씬(Scene)에서 **플레이어가 보는 시점(Viewport)**을 결정하는 렌더링 카메라기본적으로 Main Camera 태그를 가진 GameObject로 자동 생성됨Camera.main

dev-jen.tistory.com

  • StageChangeTrigger 조건문 수정 및 디버깅
  • 몬스터 스폰 방식 개선 (스폰 포인트 순서대로 / 프리팹 랜덤)
  • Canvas에 MainCamera 자동 할당 (CanvasCameraSetter.cs)
  • MainCamera와 UI RenderMode 간 연동 구조 이해
  • 3D에서 Orthographic 카메라 사용 시의 효과
  • GitHub 커밋 로그 기반 개발 작업 히스토리 정리
  • 스크립트 폴더 구조 시각화 및 역할별 분류

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

오늘은 주로 게임 흐름과 UI, 몬스터 스폰 관련 시스템을 다듬는 데 집중했다.

우선 StageChangeTrigger에서 조건식 오류가 있어,

스킬 UI가 불필요한 스테이지에서도 출력되는 문제를 발견하고 조건문을 다시 점검했다.

기존에는 ||(or) 연산자를 사용해서 항상 true가 되는 구조였기 때문에 &&로 바꾸는 식으로 로직을 수정했다.

또한, MonsterSpawnManager에서는 기존에 몬스터가 스폰 포인트에 무작위로 겹쳐 나오는 문제가 있었는데,

스폰 위치는 고정(순차적), 몬스터 프리팹은 랜덤하게 생성되도록 구조를 바꿨다.

이후 다시 겹치지 않도록 로직을 다듬으면서 각 스테이지별 마릿수도 조정했다.

UI 쪽에서는 Canvas의 RenderMode가 Screen Space - Camera일 때

MainCamera가 수동으로 연결되지 않아 발생하는 문제를 해결하기 위해,

CanvasCameraSetter.cs 스크립트를 만들어 자동 연결되도록 처리했다.

이를 통해 씬 내 모든 Canvas들이 메인 카메라를 자동 참조하게 되어 UI 출력 문제가 해소되었다.

그리고 Camera 설정에서 Orthographic 모드와 Perspective 모드의 차이도 실제 씬을 통해 확인했다.

Orthographic은 3D 환경에서도 깊이감이 없이 평면적으로 보이기 때문에,

UI나 미니맵처럼 깊이 정보가 필요 없는 영역에 적합하다는 걸 알게 되었다.

마지막으로 GitHub 커밋 로그를 정리하면서 금요일~오늘까지의 작업 흐름을 팀원들과 함께 정리했고,

전체 스크립트 폴더 구조를 정돈하면서 각 스크립트가 어떤 역할을 하는지 다시 정리해보는 시간을 가졌다.


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

1. 스킬 UI가 불필요한 스테이지에서 출력되는 문제

  • 문제정의: StageChangeTrigger에서 스킬 UI를 출력하는 조건이 잘못되어, Boss, Tutorial, MainStage에서도 스킬 UI가 계속 뜨는 현상이 발생함.
  • 시도: ||(or) 연산자를 사용해서 특정 스테이지가 아닐 때 UI를 띄우려 했지만, 조건이 항상 true로 작동함.
  • 해결 방법:
  • // 잘못된 코드 if(GameManager.Instance.CurrentStage != StageType.Boss || GameManager.Instance.CurrentStage != StageType.Tutorial) // 수정된 코드 if (GameManager.Instance.CurrentStage != StageType.Boss && GameManager.Instance.CurrentStage != StageType.Tutorial && GameManager.Instance.CurrentStage != StageType.MainStage) { SkillUIManager.Instance.ShowSkillUI(); }
  • 새롭게 알게 된 점: ||를 사용할 경우 어느 하나만 참이어도 전체 조건이 참이 되므로, "모두 아닐 때"의 조건엔 &&를 써야 정확함.
  • 다시 만나게 된다면: 조건문은 먼저 논리적으로 반례를 떠올려보고, 필요한 경우 Debug로 흐름을 직접 찍어보자.

2. 몬스터가 스폰 포인트에 겹쳐서 생성되는 문제

  • 문제정의: MonsterSpawnManager에서 몬스터가 랜덤 위치에 랜덤하게 스폰되다 보니, 동일 위치에 여러 마리가 겹치는 경우 발생.
  • 시도: 위치와 프리팹 모두 랜덤 선택 → 스폰 위치는 고정, 프리팹만 랜덤으로 조정.
  • 해결 방법:
  • for (int i = 0; i < spawnPoints.Length; i++) { int prefabIndex = Random.Range(0, monsterPrefabs.Length); Transform spawnPoint = spawnPoints[i]; GameObject prefabToSpawn = monsterPrefabs[prefabIndex]; GameObject monster = Instantiate(prefabToSpawn, spawnPoint.position, Quaternion.identity); spawnedMonsters.Add(monster); }
  • 새롭게 알게 된 점: 랜덤 스폰도 조건에 따라 순서를 고정하거나, 위치 중복을 제한하는 로직이 필요함.
  • 다시 만나게 된다면: 상황에 따라 “랜덤성”과 “질서”의 균형이 필요함을 염두에 두자.

📝 메모

오늘은 팀 프로젝트의 거의 마무리 단계에서 각종 UI 조건 처리나 몬스터 스폰 방식 같은 세세한 부분들을 계속 다듬었고, 결과적으로 훨씬 완성도 있는 흐름이 만들어진 것 같아서 뿌듯하다. 특히 조건문에서 자주 쓰는 ||와 &&의 차이를 다시금 체감했고, 작은 실수가 전체 흐름을 망칠 수 있다는 걸 또 배웠다.

또한, 겹침 없이 몬스터가 순서대로 등장할 수 있도록 고정된 포인트를 활용한 구조가 적용되면서, 전투의 시작이 더 자연스러워졌다.

무엇보다 오늘은 팀원들과 마지막까지 함께 앉아 결과보고서를 정리했다. 각자 기능을 담당하면서도 끝까지 책임감을 갖고 마무리한 게 느껴졌고, 서로서로 수고했다는 말 한마디가 참 고맙고 따뜻했다.

이제 마지막 피드백만 잘 반영하고 마무리까지 멋지게 달려보자!

끝날 때까지 끝난 게 아니다. 내일도 화이팅!!!! 🌟


테스트 이미지

반응형
반응형

🎥 Unity의 메인 카메라(Main Camera)란?

✅ 1. 기본 정의

  • Unity 씬(Scene)에서 **플레이어가 보는 시점(Viewport)**을 결정하는 렌더링 카메라
  • 기본적으로 Main Camera 태그를 가진 GameObject로 자동 생성됨
  • Camera.main 으로 쉽게 접근할 수 있음 (GameObject.FindWithTag("MainCamera")의 성능 최적화 버전)

✅ 2. Camera 주요 설정

속성 설명
Clear Flags 배경을 어떻게 처리할지 결정 (Skybox, Solid Color, Depth Only, Don't Clear)
Culling Mask 어떤 레이어의 오브젝트만 렌더링할지 선택
Projection 카메라 투영 방식 (Perspective: 원근, Orthographic: 평면)
Field of View 시야각 (Perspective일 때만 적용)
Clipping Planes 카메라가 렌더링할 최소/최대 거리
Depth 여러 카메라가 있을 때 그리는 순서 (높을수록 위에 그려짐)
Target Texture RenderTexture에 출력하고 싶을 때 사용 (예: 포탈, CCTV 효과)

✅ 3. 카메라 제어 예시

🎮 플레이어 따라가기

public class FollowCamera : MonoBehaviour
{
    public Transform target;
    public Vector3 offset;

    void LateUpdate()
    {
        if (target != null)
            transform.position = target.position + offset;
    }
}

🎞 카메라 흔들기 (Shake)

public IEnumerator CameraShake(float duration, float magnitude)
{
    Vector3 originalPos = transform.localPosition;

    float elapsed = 0f;
    while (elapsed < duration)
    {
        float x = Random.Range(-1f, 1f) * magnitude;
        float y = Random.Range(-1f, 1f) * magnitude;

        transform.localPosition = new Vector3(x, y, originalPos.z);
        elapsed += Time.deltaTime;
        yield return null;
    }

    transform.localPosition = originalPos;
}

✅ 4. 메인 카메라 관련 실전 예시

예시 설명
2D 게임 Orthographic 투영 사용, 플레이어를 따라다니며 흔들림 없음
3D 게임 Perspective 투영 사용, 자유 시점 회전, 줌 인/아웃
미니맵 별도 카메라 사용 + RenderTexture
포탈/거울 카메라 + RenderTexture + RawImage 사용

✅ 5. 자주 하는 실수

  • 카메라가 씬에 두 개 이상 있을 때, Camera.main은 가장 먼저 찾은 MainCamera 태그만 사용함 → 명확한 참조 권장
  • 카메라 Depth 설정 안 해서 UI용 카메라가 게임 씬을 덮어버리는 경우 발생
  • 클리핑 거리 조정 실패 → 너무 멀거나 가까운 물체가 안 보이는 경우

🧠 마무리 정리

개념 기억 포인트
Main Camera 태그 Camera.main 접근 대상
Projection 설정 2D: Orthographic / 3D: Perspective
이동 LateUpdate로 자연스럽게 따라가기
다중 카메라 Depth, Culling Mask, RenderTexture 활용
최적화 너무 많은 카메라 활성화는 성능 저하 가능

 

 

🎯 3D에서 Orthographic 카메라를 쓰면?

✅ 핵심 효과

  • **원근감(Perspective)**이 없어진다
  • 카메라와의 거리에 상관없이 모든 오브젝트가 같은 크기로 보인다
  • 멀리 있는 물체도 작아지지 않음
  • 투시 왜곡 없음 → 마치 2D처럼 보이는 3D

👀 비교 예시

항목 Perspective (원근) Orthographic (직교)
가까운 물체 크게 보임 동일하게 보임
먼 물체 작게 보임 동일하게 보임
시야각 Field of View 설정 Size로 보기 범위 설정
대표 사용 일반 3D 게임, FPS, 3인칭 등 전략 시점, 건축 시뮬, 퍼즐, 등각 뷰 게임 등
 

🎮 시각적 차이 예시

  • Perspective
    캐릭터 앞에 있는 적은 큼직하게, 멀리 있는 적은 작게 보임 → 자연스러운 현실 느낌
    예: FPS, RPG
  • Orthographic
    앞에 있는 적이든, 멀리 있는 적이든 크기가 똑같이 보임 → 깊이 구분이 없음
    예: 전통적 RTS, 스타듀밸리 같은 탑뷰, 건축 프리뷰, 에디터 툴

🧪 Unity 실습: 전환 방법

Camera.main.orthographic = true;      // 직교 투영 모드로 전환
Camera.main.orthographicSize = 5f;    // 보이는 영역 범위 조정

🧠 언제 Orthographic을 쓰면 좋을까?

쓰면 좋은 경우 이유
등각뷰 게임 (ex: 시뮬레이션, 탑뷰 퍼즐) 모든 오브젝트를 동일한 크기로 정밀하게 보여주고 싶을 때
건축/에디터 툴 정확한 위치 비교와 거리감 없는 작업이 필요할 때
2.5D 게임 3D 모델을 사용하지만 카메라 뷰는 2D처럼 고정할 때

 


✅ 요약

  • Orthographic은 원근이 없는 평면적 시점
  • 3D 씬에서도 2D처럼 연출 가능
  • 객체가 카메라에서 멀어져도 크기 변화 없음
  • 2D UI 느낌이나 등각뷰 게임에 적합

 

사실 이걸 작성하는건 이번에 궁수의 전설 모티브로 2.5D 게임을 만들었어야 했는데 어떻게해도 잘 안됐었다..그러다보니 3D 메인 카메라에서 Orhographic을 쓰면 된다고 그러길래 해봤더니..완벽했다 허허.. 새로운걸 하나 배워간다.

왼쪽은 Projection - Perspective 오른쪽은 Projection - Orhograpihc

 

반응형
반응형

1. 이번 주 가장 인상 깊었던 배움은 무엇이었나요?

Skill & Upgrade System을 ScriptableObject 기반으로 설계하고, 실제 게임 흐름에 연동시켜본 경험이 가장 인상 깊었다.

그동안 ScriptableObject를 단순 데이터 저장 용도로만 이해하고 있었는데, 이번 주에는 게임 흐름 안에서 그 데이터를 실시간으로 불러오고 UI와 연동해, 유저가 스킬을 선택하고 실제로 적용되도록 구현해봤다.

특히 방을 클리어할 때 무작위 스킬 카드들이 뜨고, 선택된 스킬이 플레이어 능력치나 특성에 영향을 미치는 흐름을 만들면서,
단순한 데이터 보관이 아니라 확장성과 유지보수를 고려한 설계 방식이라는 걸 직접 체감했다.

단순히 기능을 넣은 것이 아니라, UI 흐름과 연계하고 PlayerState에 적용되도록 설계한 전체적인 흐름이
'아, 이게 진짜 시스템을 만드는 거구나' 하고 느끼게 해준 아주 좋은 경험이었다.

 

2. 그 배움을 얻기까지 어떤 어려움이 있었나요?

처음엔 ScriptableObject로 어떻게 스킬 정보를 관리하고 UI에 적용할지 구조가 머릿속에 잘 그려지지 않았다.
데이터는 분리했지만, 방 클리어 → UI 출력 → 스킬 선택 → 선택된 스킬의 효과 적용이라는 전체 흐름을 유기적으로 연결하는 로직을 구성하는 데 어려움이 있었다.

또한, UI에서 무작위로 3개의 스킬을 고르고, 버튼 클릭 시 해당 스킬이 Player에게 제대로 적용되는지 확인하는 과정도 만만치 않았다.
ScriptableObject를 통해 스킬을 전달했는데, 내부 값을 가져오는 과정에서 참조/복사 이슈로 적용이 안 되는 버그가 발생했다.

그리고 선택된 스킬을 Player의 상태에 반영하는 구조를 어디에 둘지,
SkillUIManager와 Player 사이의 역할을 어떻게 분리할지 고민하다가 UIManager → GameManager → Player 흐름으로 정리하게 되었다.

이 흐름을 다 잡고 나서야 스킬 시스템이 자연스럽게 동작했고, 전체 설계가 안정감을 갖게 되었다.

 

3. 그 과정에서 나는 무엇을 깨달았고, 어떤 감정/생각이 들었나요?

처음에는 단순히 "데이터를 나눠서 관리하면 좋겠지"라는 생각으로 ScriptableObject를 사용했는데,
이번에 시스템 전체를 연결하면서 **'데이터 구조 설계가 곧 게임의 흐름을 좌우한다'**는 걸 실감하게 됐다.

처음에는 생각보다 복잡하고 잘 안 풀려서 머릿속이 뒤죽박죽이었다.
UI도 따로, Player도 따로, 스킬도 따로 움직이는 느낌이라 "내가 잘못 짠 건가?" 하는 불안도 있었고,
스킬이 적용되지 않을 때는 어디서 문제인지 몰라서 한참을 디버깅했다.

하지만 결국 전체 흐름을 정리하고 나서 스킬이 적용되고 플레이어가 변화하는 걸 보니까
"아, 내가 만든 구조가 플레이어 경험에 직접적으로 영향을 주는구나" 하는 뿌듯함이 크게 느껴졌다.

그리고 이 경험을 통해 나는, 단순히 로직을 구현하는 개발자가 아니라
플레이어의 선택과 경험을 설계하는 사람이 되고 있다는 걸 깨달았다.

 

4. 메모 (느낀 점, 다짐)

이번 주는 "시스템을 만들었다"는 느낌이 뚜렷한 한 주였다.
단순히 기능을 구현하는 걸 넘어서, 플레이어 경험을 설계하고 연결하는 과정을 직접 만들어갔다.
특히 ScriptableObject를 사용해서 스킬 시스템을 구성한 건 내 개발자 인생에서도 **첫 번째로 제대로 된 '설계 중심의 개발 경험'**이었다고 생각한다.

구현이 잘 안 풀릴 땐 답답했지만, 팀원들이랑 함께 구조를 나누고 흐름을 정리하면서
같이 만들어가는 협업의 재미와 뿌듯함도 강하게 느꼈다.

앞으로도 복잡해 보여도 직접 부딪혀보면서 흐름을 하나하나 만들어가고 싶다.
다음주는 게임의 완성도를 더 끌어올릴 수 있는 디테일에 집중해서,
"직관적이고 몰입도 있는 게임 시스템"을 만드는 데 힘을 쏟자.

"내가 만든 시스템이 플레이어의 선택을 변화시키고,
그 선택이 게임 전체 흐름을 만들어간다"는 사실을 잊지 말자.

 

 

📅이번주 TIL 목록

 

내일배움캠프 21일차 TIL [Unity 생명주기와 C# 알고리즘 핵심 복습]

🗓️ 오늘 하루 일정✅ 오전09:00 ~ 11:00 : GitHub 과제 업로드, 제출 및 README.md 정리🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 17:00 :Unity 학습 내용 복습 (라이프사이클, 코루틴, Instantiate 등)

dev-jen.tistory.com

 

내일배움캠프 22일차 TIL [팀 프로젝트(Archero)]

🗓️ 오늘 하루 일정✅ 오전09:00 ~ 10:00 : Unity 입문 프로젝트 발제 자료 확인10:00 ~ 11:00 : Unity 강의 수강 (입문 프로젝트 소개 중심)11:00 ~ 13:00 : 팀 회의 및 주제 결정 (궁수의 전설 기반), 역할 분담

dev-jen.tistory.com

 

내일배움캠프 23일차 TIL [팀프로젝트(Archero)]

🗓️ 오늘 하루 일정✅ 오전09:00 ~ 12:30 :CameraManager 스크립트 구조 설계 및 기본 구현2.5D 스타일 카메라 구현 (Z축만 따라가고 X축/Y축 고정)타이틀 상태에서는 고정 위치로 이동하도록 상태 분기

dev-jen.tistory.com

 

내일배움캠프 24일차 TIL [팀프로젝트(Archero)]

🗓️ 오늘 하루 일정✅ 오전09:00 ~ 12:00 :MonsterSpawnManager 수정 및 커밋Skill&UpgradeSystem_LeeJaeEun 브랜치 병합MainScene UI 테스트 및 사운드 추가Read-Only 애니메이션 클립 복제 방법 팀원에게 설명애니메

dev-jen.tistory.com

 

내일배움캠프 25일차 TIL [팀프로젝트(Archero)]

🗓️ 오늘 하루 일정✅ 오전09:00 ~ 13:00 : GitHub 커밋 및 기능 구현보스 일반 공격 충돌 문제 해결스테이지 클리어 UI 기능 마무리보스 중력 및 히트 애니메이션, 붉은색 피격 효과 적용몬스터 사운

dev-jen.tistory.com

 

 

📅이번주 Study 목록

 

Unity - Unity MonoBehaviour 생명주기 (Lifecycle) 정리

🌀 Unity MonoBehaviour 생명주기 (Lifecycle) 정리Unity는 MonoBehaviour 기반의 스크립트를 일정한 순서로 호출하며, 게임 오브젝트의 생성부터 종료까지 다양한 이벤트 함수를 실행한다. 아래는 각 단계별

dev-jen.tistory.com

 

Unity - Unity Coroutine(코루틴)

📌 Coroutine이란?**코루틴(Coroutine)**은 Unity에서 제공하는 특별한 함수로, 작업의 흐름을 중간에 일시정지하고, 조건이 충족되면 다시 이어서 실행할 수 있다.코루틴은 IEnumerator 반환형을 가지며, S

dev-jen.tistory.com

 

Unity - Invoke() vs Coroutine 비교 정리 & InvokeRepeating()

⏰ Unity Invoke() vs Coroutine 비교 정리Unity에서 일정 시간 이후에 어떤 작업을 수행하려면 보통 Invoke()나 Coroutine을 사용한다.둘 다 **시간 지연(delay)**을 다룰 수 있지만, 구조와 활용도에는 큰 차이가

dev-jen.tistory.com

 

Unity - Unity Instantiate() 오버로드 정리 & 자식으로 설정할 때의 차이

🧱 Unity Instantiate() 오버로드 정리 & 자식으로 설정할 때의 차이Unity에서 동적으로 오브젝트를 생성할 때 가장 많이 사용하는 함수는 Instantiate()다.하지만 부모를 지정하는 방식, 월드 좌표 유지

dev-jen.tistory.com

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 13:00 : GitHub 커밋 및 기능 구현
    • 보스 일반 공격 충돌 문제 해결
    • 스테이지 클리어 UI 기능 마무리
    • 보스 중력 및 히트 애니메이션, 붉은색 피격 효과 적용
    • 몬스터 사운드, 파티클, HP Bar 상호작용 기능 추가 및 수정
    • 튜토리얼 관련 버그 수정 및 기능 개선
    • StageChangeButton 관련 로직 개선 시도

🍽️ 점심시간

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

✅ 오후

  • 14:00 ~ 18:00 :
    • 몬스터 FSM과 SpawnManager 연결 로직 점검
    • 스테이지 전환 중 클리어 처리 예외 상황 확인
    • 보스 태그/프리팹 설정 및 애니메이션 처리 개선
    • GitHub 정리 및 커밋 다수 진행

🍽️ 저녁시간

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

✅ 저녁

  • 19:00 ~ 21:00 : 팀원들과 회의 및 개발 보고서 작성
    • 각자 진행 상황 공유
    • 기능 및 역할 정리
    • 향후 일정 조율 및 코드 통합 논의

✅ 오늘 학습 키워드

  • MonsterFSM 상태 관리 (Die 상태 처리 및 상태머신 전환 로직)
  • MonsterSpawnManager에서 몬스터 전체 사망 체크 및 UI 연동
  • StageChangeButton을 통한 스테이지 전환 조건 처리
  • GameManager의 SetStage 구조 및 클리어 처리 타이밍 확인
  • 스테이지별 매니저 활성화 순서와 OnEnable() 트리거 순서 이해
  • GitHub 커밋 내역을 기반으로 작업 흐름 관리 및 협업 상황 파악

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

오늘은 게임의 핵심 흐름 중 하나인 스테이지 전환과 클리어 처리 로직을 중점적으로 다뤘다.

먼저 StageChangeButton을 통해 스테이지를 변경할 때, 해당 스테이지가 이미 클리어된 경우 다음 미클리어 스테이지를 탐색해 자동으로 전환되도록 구현했다. 다만 이 과정에서 튜토리얼과 메인 스테이지는 클리어 조건이 적용되면 안 되는데, 튜토리얼에도 클리어 조건이 들어가 버려서 스킵되는 문제가 있었다. 이를 IsStageCleared() 내부에서 조건 분기로 해결했다.

또한 GoToMainStage() 함수에서 중간 스테이지에서도 메인으로 복귀할 수 있도록 처리했는데, 이때도 SetStage() 내부에서 클리어 처리가 함께 실행되어 버리는 구조 때문에, 스테이지를 클리어하지 않고 메인으로 이동했는데도 클리어가 되는 문제가 발생했다. 이를 해결하기 위해 SetStage() 호출 전에 클리어 처리 분기 제어가 필요함을 확인했고, 추후 구조 개선을 고려 중이다.

한편, MonsterSpawnManager에서 스폰된 몬스터들이 모두 사망하면 SkillUIManager를 호출해 스킬 선택 UI를 자동으로 띄우는 기능도 구현했다. FSM 구조와 상호작용하며 IsAlive()를 통해 몬스터 생존 여부를 체크하는 구조는 간단하지만 매우 실용적이었다.

마지막으로 팀원들과 회의하면서 개발보고서 작성을 진행했고, 전체 흐름을 점검하며 오늘까지 구현된 내용을 정리했다. 협업 리듬을 유지하면서도 각각의 시스템이 안정적으로 동작할 수 있도록 점검한 하루였다.


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

1. 문제정의

GoToMainStage() 함수 호출 시, 현재 스테이지가 클리어 처리되는 문제

  • 메인으로 단순 이동하고 싶을 뿐인데 GameManager.Instance.SetStage(...) 내부 로직에서 이전 스테이지를 클리어 처리함.

시도

public void GoToMainStage()
{
    GameManager.Instance.SetStage(StageType.MainStage);
}

이때, 내부적으로 SetStage()에서 이전 스테이지 클리어가 자동 처리됨:

switch (CurrentStage)
{
    case StageType.Stage1:
        StageManager.Instance.stage1Clear = true;
        break;
    ...
}

해결방법

임시로 다음과 같이 분기 조건을 넣었지만 구조적으로 아쉬움:

public void GoToMainStage()
{
    if (GameManager.Instance.CurrentStage != StageType.MainStage)
    {
        // 강제 클리어 방지용으로 별도 플래그나 조건 제어 필요
    }
    GameManager.Instance.SetStage(StageType.MainStage);
}

새롭게 알게 된 점

  • SetStage() 내부에서 무조건 현재 스테이지를 클리어 처리하고 있었음.
  • 이 로직은 “클리어한 후 다음 스테이지로 간다”는 전제를 깔고 있어서, 중간 이탈이나 테스트용 스테이지 이동에는 부적절함.

다시 만나게 된다면

  • SetStage() 호출 방식 리팩토링 필요. 이동 목적이 "클리어 + 다음 스테이지" 인지, "그냥 이동"인지 구분하는 인자를 도입하는 방식 고려 필요.
public void SetStage(StageType newStage, bool markClear = true)

2. 문제정의

스테이지 클리어 후 스킬 UI가 자동으로 안 뜸

시도

  • MonsterSpawnManager 내부에서 모든 몬스터가 죽었는지 체크해서 SkillUIManager.Instance.ShowSkillUI() 호출함.
if (spawnedMonsters.Count > 0 && AreAllMonstersDead())
{
    SkillUIManager.Instance.ShowSkillUI();
}

해결방법

  • 문제는 IsAlive()를 제대로 체크하지 못하거나, Die 상태로 바뀌었음에도 GameObject가 Destroy() 전까지는 살아있다고 판단하는 점 때문이었음.
  • FSM의 UpdateDie()에서 isDie = true;와 Destroy(gameObject, 3f);를 설정하고 있었음 → IsAlive()가 이 상태를 기준으로 false를 반환하도록 수정.

예시 코드

public bool IsAlive()
{
    return !isDie;
}

새롭게 알게 된 점

  • Unity에서 Destroy()는 실제로는 다음 프레임에 처리되기 때문에, 직접 상태 플래그로 죽음을 판단해야 한다.

다시 만나게 된다면

  • FSM은 상태 기반이므로, 사망 체크는 반드시 Die 상태와 isDie 같이 명시적으로 관리되어야 신뢰성이 있음.

📝 메모

오늘은 스테이지 이동 시스템과 몬스터 클리어 판정, FSM 상태 관리 등 게임 전반의 흐름을 결정짓는 핵심 시스템들을 다뤘다.

처음엔 단순히 "메인 화면으로 가고 싶다"는 동작이었지만, 그 안에 숨겨진 클리어 처리 로직사이드 이펙트들을 하나씩 파악하면서,

게임 설계에서 로직 분리와 명확한 의도 전달이 얼마나 중요한지 다시 한 번 느꼈다.

그리고 오늘 저녁엔 팀원들과 회의를 통해 개발보고서를 작성하며,

각자의 작업 내역을 공유하고 서로가 만든 시스템을 이해하려고 노력하는 시간이 정말 뜻깊었다.

하나의 기능을 만들고, 그것이 팀 전체의 흐름 속에서 어떻게 연결되는지를 고민하는 일이 정말 재미있고 보람찼다.

이제 정말 프로젝트의 완성도를 높이는 작업이 되고 있다는 게 느껴진다.

기능 구현에서 디테일 조정, 예외 처리, 그리고 클리어 후 보상 시스템까지…

하나하나 챙겨가며 정리하고 있다는 것이 자랑스럽기도 하다.

앞으로도 "작동하니까 됐어"가 아니라

"왜 이렇게 동작하지?"

"지금 이 로직은 진짜 이 목적에 맞는 걸까?"

하는 생각을 놓지 않고 더 단단하게 만들어가고 싶다.


반응형