부트캠프/본캠프

[내일배움캠프_2025AUG07] 유니티 숙련 챕터

Young_A 2025. 8. 7. 22:51

목차

    유니티 숙련 챕터

    오늘은 강의를 끝내고 싶다!


    TryGetComponent<T>(out T component)

    Unity에서 컴포넌트를 안전하게 가져오는 메서드이다.

    해당 컴포넌트가 존재하면 true, 없으면 false를 반환한다.

    컴포넌트가 없을 때 예외가 발생하지 않기 때문에 안전하게 사용할 수 있다.

     

    Rigidbody rb;
    if (TryGetComponent<Rigidbody>(out rb))
    {
        rb.AddForce(Vector3.up * 100f);
    }
    else
    {
        Debug.Log("Rigidbody component not found.");
    }

    T는 Component를 상속한 타입이어야 한다.

    out 매개변수로 컴포넌트를 반환받는다.

    조건문과 함께 사용해 방어적인 코드 작성에 적합하다.

     

    더보기

    참고

    유니티 숙련 주차 1-5 강의 PDF


    카메라 절두체 (View Frustum)

    렌더링에 사용되는 3D 공간의 시야 영역을 나타낸다.

    모양은 끝을 잘라낸 피라미드처럼 생겼으며, 카메라가 어떤 오브젝트를 렌더링할지 결정하는 데 사용된다.

    구성요소

    • FOV(Field of View): 시야각. 원근 중심에서 화면 상하단까지 잇는 선 사이의 각도
    • Near Clipping Plane / Far Clipping Plane
      • 각각 가까운 절단면 / 먼 절단면
      • 이 두 평면 사이에 있는 오브젝트만 카메라에 렌더링 됨.
    • 분기선: 카메라 화면 네 모서리에서 뻗어나가는 가상의 선.
      • 이 선을 기준으로 절두체 영역 밖의 오브젝트는 보이지 않음.

     

    따라서,

    뷰 절두체는 카메라의 위치와 방향, 시야각, 클리핑 플레이 설정 등에 따라 결정된다.

    절두체 안에 있어야 오브젝트가 보이고 렌더링 된다.

    Unity 카메라는 이 절두체를 기준으로 화면을 그린다.

     


    코루틴 (Coroutine)

    Unity에서 작업을 여러 프레임에 나눠서 실행할 수 있는 메서드 구조다.

    실행을 일시중단(yield)하고 Unity에게 제어를 넘긴 후, 다음 프레임부터 이어서 실행할 수 있다.

    형태는 IEnumerator를 반환하는 메서드로 작성한다.

    IEnumerator Move()
    {
        // 실행
        yield return new WaitForSeconds(1f); // 1초 대기
        // 재개
    }

    동기 vs 비동기

    코루틴은 비동기처럼 보일 수 있지만, 엄밀히 말하면 동기적 구조다.

    실제 실행은 모두 메인 스레드에서 이뤄진다. -> 따라서 스레드를 사용하는 비동기 작업과는 다르다.

    단지 yield를 통해 프레임 단위로 나눠 실행되는 것 뿐이다.

     

    코루틴의 특징을 정리하자면

    Unity의 코루틴은 비동기처럼 작동하는 동기 구조이다.

    무거운 연산에는 적합하지 않으며, 시간 지연, 애니메이션, 타이머 등 프레임 기반 작업에 적합하다.

    실제 비동기 작업이 필요할 땐 async/await나 스레드 사용을 고려해야한다.

     

    더보기

    참고

    유니티 숙련 주차 1-5 강의 PDF


    조명 (Unity Light)

    Light 소스는 게임 또는 3D 렌더링에서 광원을 추가하는 데 사용된다.

    특정 위치 또는 방향에서 발생하는 빛을 시뮬레이션 하는 역할을 한다.

    라이트의 종류

    • 점광원 (Point Light): 한 지점에서 모든 방향으로 빛을 발산
    • 방향성 라이트 (Directional Light): 무한히 멀리 떨어진 위치에서 한 방향으로 빛을 투사 (태양광 등)
    • 스포트라이트 (Spot Light): 한 점에서 시작해 원뿔 형태로 빛을 발산
    • 면광원 (Area Light): 사각형의 한쪽 면에서 빛을 균등하게 발산. 표면 영역 전체에 걸쳐 모든 방향으로 빛을 뿜음.

    속성: 위치, 방향, 강도(intensity), 색상(color), 범위(range), 각도(angle) 등이 있다.

    그림자: 라이트와 객체 사이의 관계에 따라 그림자가 생성되며, 라이트가 오브젝트에 부딪힌 뒤 뒤쪽에 그림자가 형성됨.

    성능: 라이트는 렌더링 성능에 큰 영향을 줄 수 있다. 특히 그림자가 활성화된 경우 성능 최적화에 유의해야 한다.

    추가로 Lighting Intensity Multiplier로 실제 환경 광의 강도를 조절하거나 Reflecting Intensity Multiplier로 실제 오브젝트에 반사되는 정로를 조절할 수도 있다.

     

    더보기

    참고

    유니티 숙련 주차 1-7 강의 PDF


    AnimationCurve

    시간에 따라 값이 변화하는 곡선을 정의하는 Unity 클래스이다.

    주로 애니메이션, 트윈 효과, 움직임 제어 등 시간 기반 로직에서 사용된다.

    구성 요소

    Keyframe: 시간(t)과 해당 시간에 대응하는 값(value)을 갖는 점. 여러 개의 키프레임으로 곡선을 구성한다.

    보간 방식 (Interpolation Mode): 키프레임 간의 값을 어떻게 계산할지 결정하는 방식. Unity에서는 기본적으로 곡선 형태 (Cubic Bezier 등)로 부드럽게 연결된다.

    주요 메서드 및 속성

    • AddKey(float time, float value): 곡선에 새로운 키프레임을 추가한다.
    • Evalutate(float time): 특정 시간에서의 값을 보간하여 반환한다.
    • keys: 현재 등록된 모든 키프레임 배열을 가져오거나 수정할 수 있다.
    private AnimationCurve curve;
    
    private void Start() {
        curve = new AnimationCurve();
        curve.AddKey(0f, 0f);
        curve.AddKey(1f, 1f);
    }
    
    private void Update() {
        float time = Time.time;
        float value = curve.Evaluate(time);
        Debug.Log("Time: " + time + ", Value: " + value);

    이외에도 오브젝트 이동 애니메이션, 점프 높이 조절, UI 효과 시간 조정, 게임 내 커스텀 트윈 동작 등에 쓰일 수 있다.

     

    더보기

    참고

    유니티 숙련 주차 1-7 강의 PDF


    C# 인터페이스 (Interface) 복습

    인터페이스는 클래스들이 공통적으로 따라야 할 규약을 정의하는 추상적인 구조이다.

    클래스는 이 인터페이스를 구현(implement)하여, 그 안의 메서드를 반드시 정의해야 한다.

     

    1. 추상화
      • 인터페이스는 구현 없이 메서드의 시그니처만을 갖는다. 인스턴스화가 불가능하며 반드시 구현 클래스가 필요하다.
    2. 메서드 시그니처 정의
      • 이름, 매개변수, 반환값만 명시하며, 실제 동작은 구현 클래스에 위임한다.
    3. 다중 상속 가능
      • C# 클래스는 다중 클래스 상속은 불가능하지만, 여러 개의 인터페이스는 동시에 구현할 수 있다.
    4. 강제 구현
      • 인터페이스를 구현한 클래스는 해당 인터페이스가 정의한 모든 메서드를 반드시 구현해야 한다.
    5. 인터페이스 간 상속 (확장)
      • 인터페이스는 다른 인터페이스를 확장할 수 있으며, 확장된 인터페이스는 더 많은 메서드를 정의할 수 있다.

    사용하는 이유

    • 결합도 낮춤 (Low Coupling): 구체 클래스에 의존하지 않고 인터페이스에 의존하면 유연한 구조 설계가 가능하다.
    • 작업 분리 및 병렬 개발 용이: 인터페이스만 정의해두면, 개발자들이 독립적으로 구현체를 작성할 수 있어 협업에 유리하다.
    • 표준화: 여러 명이 작업해도 일관된 형식을 유지할 수 있다.
    • 독집적인 프로그래밍: 선언은 인터페이스에, 구현은 클래스에. 각각 분리해서 유지보수 가능하다.

    챌린지반 특강: 프로젝트 구조

    오늘은 프로젝트 구조에 대한 강의가 있었다.

    진~~~짜 뭔가 많았다... 평소처럼 노트테이킹은 접은 글로.

    PPT 자료가 깔끔했고, 그걸 바탕으로 정리한거라 따로 정리는 하지않을 것 같다.

     

    인상 깊었던 것은, 그저 빈 씬인데 코드에서 오브젝트 생성 및 설정을 전부 해주어서, 게임 플레이 버튼을 눌렀을 때 완전히 다른 화면이 띄워지는 것이었다.

    이번 개인 프로젝트에 적용해볼 수 있으면 해볼 것 같다.

    더보기

    1. 로직에서 고정값 제거하기

    실제 로직에서 고정된 값으로 설정하는 것보다 변수를 이용하여 구현하는 것이 좋다.

    한 눈에 데이터 파악을 할 수 있고, 테스트에 용이해진다. (특히 스피트, 타이밍 등의 데이터)

    [SerializeField], 상수 테이블, ScriptableObject 등의 방법들이 있다.

    2. UI 코드에 로직 넣지 않기

    UI 스크립트에서 로직이나 데이터를 저장하게 되면

    UI 코드가 많아지고

    UI에 기능이 종속되고 (다른 UI에서 동일한 로직이 필요하다면...?)

    UI는 언제든 파괴돌 수 있다.

    실제 로직이 동작할 컨트롤러/매니저/시스템 등을 만들어서 사용하는 것이 좋다.

    3. 변수 타입

    변수를 선언할 때 전부 GameObject로 선언하지 말고, 가장 주로 사용될 타입으로 사용하는 것이 좋다.

    GameObject: 활성화/비활성화가 주 목적일때 사용. 그 외 특별한 기능을 활용하지 않을 때는 기본 값으로 좋음.

    Transform: 위치/회전/크기조정, 부모/자식 계층 관리

    4. 상수 사용 (작업 난이도 대비 가성비 최고)

    고정 문자열의 사용을 피하기 위해 상수를 이용하고, 상수들을 모아둔 클래스를 만들어두면 유용하다.

    PlayerPrefs 키, 씬 이름, 태그, 레이어, 경로 등

    글로벌 데이터 모음집을 만들면 좋다.

    5. 프리팹 구조

    프리팹 루프에 모델링/이미지 적용하지 않는 것이 좋다.

    빈 게임오브젝트를 루트로 삼고, 모델링 자식에 컴포넌트를 추가하여 NPC를 만들게 되면 이후 모델링을 변경할 때 세팅을 다시해야 한다.

    실제 개발 프로세스상 개발과 디자인 작업이 병행되는 경우가 많이 때문에 초반에는 임시 모델링을 사용하다가 이후에 실제 캐릭터로 바꿔주기에도 용이하다.

    인스펙터에 미리 연결해두는 데이터는 해당 프리팹 내부에 있는 오브젝트들로만 구성하는 것이 좋다.

    Q. 다른 프리팹을 넣는 것 까지는 괜찮나요? A. 괜찮다.

    6. 데이터 설정 (작업 효율에 비해 가성비는 떨어지므로 나중에 고려해도 된다.)

    데이터를 설정하는 것으로 초기화 할 수 있도록 설계

    국내 게임 업계의 절대 다수는 모바일 게임이고 API를 이용한 서버를 사용하여 멀티플레이가 개발된다.

    서버를 사용하는 외부에 있는 데이터를 불러와서 설정하는 경우가 많다.

    멀티플레이의 경우 다른 유저의 정보를 넘겨서 아바타를 생성할때도 유리함.

    DB의 데이터로 프리팹 세팅할때도 편하다.

     

    프로젝트 구조

     

    Contants, Define, Global Data

    UIManager

    SceneManager

    위 세개는 동적 생성을 위한 준비

    DataManager

    ResourceManager

    NetworkManager

     

    위 구조를 튜터님이 짧은 사이클 개발 때 신입들과 같이 개발하며 자주 쓰셨다고 함.

    여기에 더해서 MVC를 더하기도 함.

     

    7. 싱글톤

    베이스 싱글톤 클래스

    상속 받아 활용할 수 있는 싱글톤 베이스 클래스 구성.

    Generic에 대한 이해가 필요하지만 일단 그냥 써도 무방함.

    장점

    매번 싱글톤 구성요소를 만들지 않아도 된다.

    씬에 올려두지 않아도 호출 시 자동으로 생성 (프로퍼티, static에 대한 이해 필요)

    단점

    매니저 인스펙터에 오브젝트를 미리 연결해둘 수 있다.

    private static T _Instance;
    
    public static T Instance
    {
    	get
        {
        	if(_Instance == null)
            {
            	//인스턴스 존재 여부 확인
                _Instance = (T)FindObjectOfType(typeof(T));
                
                //아직 생성하지 않았다면 인스턴스 생성
                if(_Instance == null)
                {
                	//새로운 게임오브젝틀르 만들어서 싱글톤 Attach
                    var singletonObject.AddComponent<T>();
                    singletonObject.name = $"[{typeof(T)}]";
                    
                    //싱글톤 매니저에 추가
                    singletonObject.tag = "Singleton";
                }
            }
        }
        return _Instance;
    }
    더보기

    수동 Release

    씬 전환시에도 유지되는 인스턴스는 수동 릴리즈 기능을 만들어두면 활용도가 높다.

     

    8. 씬 관리

    씬 기능에 Enter/Exit 을 관리하는 지점이 있으면 전환 시 흐름 제어가 용이하다.

    특히 동적 로드 구조를 사용하는 경우 Enter 시점에서 데이터 세팅 및 프리팹 로드하기 좋다.

    PrevScene, CurScene

    지금 씬 정보와 이전 씬 정보를 알고 있다면 작업에 편리해진다.

    Village 씬에 입장할 때 이전에 Intro를 써서 진입했는지, 던전에 갔다가 오는지에 따라 초기화할 데이터가 다를 수 있다.

    Q. PrevScene관리하는 걸 Stack으로 하면 너무 무거워지려나요? A. 씬을 전환하다가 어떻게 튈지.. 안돌아오는 경우도 있으므로... 그런 경우가 없는게 확실하다면 나쁜 방법은 아닐 것 같다. UI같은거 띄울 때 Stack을 많이 쓴다. (뒤로가기 기능)

    9. MVC 구조

    초반 구조가 익숙해지기 전까지 평타는 치는 구조. 3가지로 담당 부분을 나누어서 목적에 맞게 코드 작성

    Model (데이터)

    View (UI)

    Controller (Manager/Controller/System/Handler)

    Q. View란느 것이 실제로 보여지는 모든 오브젝트에 대한 것인지 아니면 UI만 한정되는 것인지. A. 오브젝트에 대한 것도 포함이다.

    10. UIManager

    UIMAnager에 각 UI를 하나하나 변수로 들고 있는 것은 X

    List/Dictionary 등 컬렉션을 이용한 구조를 고려

    UI를 닫을 때 비활성화 하는 방법과 파괴하는 방법에 대해 고민해 볼 수 있다.

    UI 비활성화

    Instantiate/Destory에 취약한 Unity에서 최적화에 도움이 된다.

    비활성화가 임시로 된건지 UI를 닫기 위해 비활성화 시킨건지 모호.

    예를 들어 팝업이 뜰때 아래에 있는 메뉴창을 임시로 비활성화 시켜둬야 하는 경우.

    UI파괴

    Unity가 Instantiate/Destroy에 약하다고는 하지만 현대 기기 스펙이 그렇게 안좋지는 않다.

    모바일이라는 가정하에도 UI정도 만들고 파괴하는 건 큰 무리는 없어서 관리가 편하다면 진행해도 좋지만 규모는 고려하는 것이 좋다.

    Q. 그러면 UI 매니저는 UI를 총괄하는 걸 포함해서 활성화/비활성화/파괴만 담당하고, 각 UI에 들어갈 값은 MVC에서 컨트롤러가 담당해서 관리한 다음, 그 값을 UI의 각 로직이 받아서 처리한다는 뜻일까요? A. 맞다.

    Q. UI 프리팹을 게임 시작 전에 모두 동적으로 로드해서 필요할 때마다 활성화/비활성화 한다고 이해하면 될까요? A. 저런걸 적용하는 부분이 있지만 UI는 잘 적용하지 않는다. 보통 몬스터, 이펙트 등에 적용하는 방법이다. 왜냐면 몬스터는 사용된다는 보장이 있지만 UI는 해당 UI를 쓸거라는 보장이 없으므로. 

    11. 동적 로딩

    Scene에 오브젝트를 미리 올려두는 경우

    단점

    Scene을 로딩하는데 오래 걸립니다. (빈 씬 로딩 0.05초 -> 시작 씬 로딩 0.3초, 이 시점에서 우선 시작 -> 맵 전체 로딩 2초)

    필요 없는 데이터도 우선 로딩할 수 있습니다.

    준비된 오브젝트 간의 초기화 순서를 지정하는 게 힘듭니다.

    시작 여러 씬을 올릴 때 순간 메모리에 유리하다. (웹을 생각한다면 메모리 부족 시 취약)

    따라서 필요한 오브젝트에 접근할 방법을 마련해야합니다.

    Unity 입문 단계에서 코드 작업의 50% 이상은  A라는 오브젝트가 B에 접근할 수 있게 하는 것

    오브젝트를 코드에서 생성을 하면 인스펙터 연결 없이 변수에 저장해 둘 수 있다.

    이 작업을 매니저(싱글톤)에서 준비한다면, 전역에서 접근이 쉬워집니다.

    12. 오브젝트 접근

    서로 다른 클래스에서 접근이 필요한 경우 직접 접근은 권장 X

    매니저를 통해 할당하면 편하다.

    Find (이름으로 찾는거) 기능이 있긴 한데 절대 쓰지 않길 권한다. (튜터님 기준으로 포폴에서 보이면 바로 닫는다 하심)

     

    Q. 공통된 프로젝트 구조를 다른 팀원들도 잘 사용할 수 있게 공유되어야 할 것 같다. A. 쉽든 어렵든 공유가 필요하다. 신입이 오면 데려다가 코드리뷰 해주는 편. 제시한 구조도 완벽하진 않지만 직관적이다. (신입이 자주 끼어서 만든 구조라 하심)

    프로젝트 구조를 만들었다면 신입에게 설명한다고 생각하고 가이드 작성해보는 것도 좋을 것 같다.

    Q. UI매니저에 풀링을 적용해서 캔버스 안에 PopUI를 풀링시키는 것이 재생성보다 성능적 문제가 생길 수 있나요? A. 풀링 시스템을 적용하는 것에 문제는 없지만 조금 과하다고 생각한다. 작업 리소스 적으로 불편할듯. Q2. 로그라이크 보상UI 같은 것에 풀링 적용하는 것 생각했다. A2. 인벤토리 안에 들어가는 아이템은 풀링 쓴다.

    Q. 보통 프로젝트 구조를 템플릿처럼 재사용하시는 건가요? A. 프로젝트 양산할 필요가 있었을 때 구조를 템플릿처럼 사용했었다.

     

    Q. 여러 씬에서 쓰는 UI 같은 경우 DontDestroyOnLoad의 UIManager 아래 자식으로 canvas를 두고 쓰는 것이 관리면에서 더 괜찮나요? 아니면 Sacene마다 canvas를 새롭게 생성하는 게 괜찮나요? A. 파괴하고 새로운 씬에 가서 다시 생성하는 편이다. 그게 관리하기가 더 쉬운 것 같다.


    느낀점

    오늘 10시 38분까지 찾지 못해서 애를 쓴 이유^^

    GameObject를 꺼놨어야 했는데 Text를 꺼놔서.. 당연히 안보임^^

    로그는 찍히는데~ 어디서 잘못된것이냐 하면서 결국에는 ChatGPT한테까지 물어봤지만 찾아내지 못하고, 스스로 찾았다!

     

    물론 강의에서 각잡고 알려주시는 것들은 그때그때 정리하고 있지만 강의를 들을 수록 더 파보고 이해하고 싶은 부분들은 많아진다.

    그러나 현실적으로 다 체크하고 넘어가려면 시간이 부족하다!

    게다가 정리한다고 해도 반복해서 사용하지 않으면 계속 다시 정리하는 일이 반복할 수 있기 때문에,

    지난번에 튜터님들께 조언 받은대로 GTD 어플에다가 올려두기만 했다.

    이 리스트들은 일주일동안 모아두고, 과제를 끝내고 나면 복기하는 개념으로 훑어보려고 한다.


    내일 학습 할 것은 무엇인지

    오늘 강의를 인벤토리까지 진행하려고 했는데 하지 못했다!

    내일은 정말 강의를 끝내고 개인과제를 진행하려고 한다.