내일배움캠프 61일차 TIL - MonoBehaviour와 Unity 생명주기

권태하·2024년 7월 15일
0
post-thumbnail
post-custom-banner

확인 문제

  1. Time.timeScale을 0으로 하면 Update와 FixedUpdate는 모두 호출이 되지 않을까요? 그 이유는 무엇일까요?
    내 답:
    • Update 함수는 매 프레임마다 호출되므로 Time.timeScale의 값에 관계없이 계속 호출됩니다. Update는 주로 입력 처리, 애니메이션 업데이트, UI 업데이트 등에 사용됩니다.
    • FixedUpdate 함수는 물리 업데이트를 위해 일정한 시간 간격으로 호출됩니다. Time.timeScale을 0으로 설정하면 물리 시뮬레이션을 멈추기 때문에 FixedUpdate 호출이 중지됩니다. FixedUpdate는 Time.timeScale에 영향을 받으므로, 게임의 시간이 멈추면 호출되지 않습니다.

모범 답:

  1. Update의 호출주기에 영향을 주는 것은 무엇일까요?
    내 답:
    • Update 함수의 호출 주기는 프레임 레이트에 의해 결정됩니다. 즉, 게임의 프레임 레이트가 높으면 Update 호출이 더 자주 일어나고, 프레임 레이트가 낮으면 호출 빈도가 줄어듭니다. Update는 매 프레임마다 호출되므로 정확한 시간 간격으로 호출되지 않습니다.

모범 답:

  1. FixedUpdate의 호출주기에 영향을 주는 것은 무엇일까요?
    내 답:
    • FixedUpdate 함수의 호출 주기는 Time.fixedDeltaTime에 의해 결정됩니다. 이 값은 Unity 에디터의 Project Settings 메뉴에서 Time 섹션을 통해 설정할 수 있으며, 일반적으로 물리 업데이트를 위해 일정한 시간 간격으로 FixedUpdate가 호출됩니다. FixedUpdate는 물리 계산이나 다른 일정한 시간 간격으로 실행되어야 하는 로직에 사용됩니다.

모범 답:

  1. Awake와 Start, OnEnable의 호출 순서는 어떻게 될까요?
    내 답:
    • Awake: 스크립트 인스턴스가 로딩될 때 호출됩니다. 모든 Awake 함수가 호출된 후에 다른 함수들이 호출됩니다. 주로 초기화 작업에 사용됩니다.
    • OnEnable: Awake 다음으로 호출되며, 스크립트가 활성화될 때마다 호출됩니다. Awake가 호출된 후, 그리고 스크립트나 게임 오브젝트가 활성화될 때마다 호출됩니다.
    • Start: Awake와 OnEnable 이후에, 첫 번째 Update 호출 전에 정확히 한 번 호출됩니다. Start는 초기화 작업에 사용되며, 다른 오브젝트들이 이미 Awake를 통해 초기화된 상태에서 실행됩니다.

모범 답:

설명 문제

  1. Unity 생명주기(Unity Life Cycle)에 대해서 설명해주세요.
    내 답:
    Unity 생명주기는 Unity 엔진이 게임 오브젝트와 스크립트를 어떻게 초기화하고, 업데이트하며, 종료하는지에 대한 과정을 설명합니다. 이 생명주기는 여러 콜백 함수들로 구성되어 있으며, 각 함수는 특정 시점에 자동으로 호출됩니다. 주요 콜백 함수들은 Awake, OnEnable, Start, Update, FixedUpdate, LateUpdate, OnDisable, OnDestroy 등이 있습니다. 이 함수들은 스크립트의 초기화, 프레임별 업데이트, 오브젝트의 활성화 및 비활성화, 오브젝트의 파괴 등 다양한 상황에서 호출됩니다.

모범 답:

  1. MonoBehaviour 클래스의 주요 메서드와 그 기능에 대해 설명해주세요.
    - MonoBehaviour 클래스에서 StartAwake의 차이점은 무엇이며, 이를 적절히 사용하는 방법에 대해 설명해주세요.
    내 답:
    • Awake: 스크립트 인스턴스가 로딩될 때 호출됩니다. 게임 오브젝트가 생성될 때 한 번만 호출되며, 주로 변수나 게임 상태의 초기화에 사용됩니다.
    • OnEnable: 스크립트나 게임 오브젝트가 활성화될 때마다 호출됩니다.
    • Start: Awake와 OnEnable 이후, 첫 번째 Update 호출 전에 정확히 한 번 호출됩니다. Awake에서 초기화된 다른 오브젝트들과의 상호작용에 주로 사용됩니다.
    • Update: 매 프레임마다 호출됩니다. 주로 입력 검사, 애니메이션 업데이트, 게임 로직 처리 등에 사용됩니다.
    • FixedUpdate: 물리 업데이트 주기마다 호출됩니다. 물리 계산과 관련된 작업에 사용됩니다.
    • LateUpdate: 모든 Update 함수가 호출된 후에 매 프레임마다 호출됩니다. 주로 카메라의 이동과 같은 후처리 작업에 사용됩니다.
    • OnDisable: 스크립트나 게임 오브젝트가 비활성화될 때 호출됩니다.
    • OnDestroy: 스크립트가 파괴될 때 호출됩니다.

Start와 Awake의 차이점 및 사용 방법:
• Awake는 스크립트 인스턴스가 로딩될 때 호출되어, 변수 초기화와 같은 초기 설정에 사용됩니다. Awake는 게임 오브젝트가 활성화되지 않아도 호출됩니다.
• Start는 Awake 이후, 첫 번째 Update 호출 전에 한 번만 호출됩니다. 다른 오브젝트들과의 상호작용이 필요한 초기화 작업에 적합합니다.
• Awake를 사용하여 스크립트의 내부 상태를 설정하고, Start에서는 다른 오브젝트들이 이미 Awake를 통해 초기화된 상태에서 필요한 작업을 수행합니다.

모범 답:

  1. Update, FixedUpdate, LateUpdate의 차이점에 대해 설명해주세요.
    내 답:
    • Update: 매 프레임마다 호출되며, 게임 로직, 입력 처리 등 대부분의 일반적인 업데이트 작업에 사용됩니다.
    • FixedUpdate: 일정한 시간 간격으로 호출되며, 물리 업데이트(예: Rigidbody의 이동)와 관련된 작업에 사용됩니다. Time.fixedDeltaTime에 설정된 값에 따라 호출 주기가 결정됩니다.
    • LateUpdate: 모든 Update 함수가 호출된 후 매 프레임마다 호출됩니다. 주로 다른 오브젝트들의 업데이트에 의존하는 작업(예: 카메라의 추적)에 사용됩니다.

모범 답:

  1. Time.deltaTime이란 무엇이며, 사용하는 이유에 대해 설명해주세요.
    내 답:
    • Time.deltaTime은 이전 프레임이 완료되고 현재 프레임이 시작될 때까지 걸린 시간(초 단위)을 나타냅니다. 즉, 마지막 프레임의 지속 시간입니다.
    • Time.deltaTime을 사용하는 이유는 프레임 레이트에 독립적인 게임 로직을 구현하기 위해서입니다. 예를 들어, 오브젝트를 일정 속도로 이동시키고 싶을 때 Time.deltaTime을 사용하여 프레임 레이트 변화에 관계없이 일관된 속도로 오브젝트를 이동시킬 수 있습니다.

모범 답:

실습 문제

💡 **[JobQueue 만들기]**

Awake 호출 순서에 상관 없이 작동하는 JobQueue를 만들어봅시다.

여러분은 현재 스테이지의 모든 적이 죽었을 경우 다음 스테이지로 넘어가는 기능을 만들고 싶습니다.
먼저 싱글톤 패턴의 StageManager를 선언하여 적들의 정보를 한 군데에 모으려 합니다.

그런데 문제가 있습니다!
씬에 StageManagerEnemy 오브젝트가 있는데,

Scene 구조

StageManager의 초기화 전에 Enemy 오브젝트의 Awake가 먼저 호출되어버려
NullReferenceException 오류가 발생합니다!

그래서 StageManager에 JobQueue를 추가하여
Enemy의 Awake가 먼저 불려도 그 작업을 Queue에 저장해놓고 StageManager 초기화 시 차례대로 불러오려고 합니다.

JobQueue를 이용한 StageManager의 코드를 완성해주세요.

using System;
using System.Collections.Generic;
using UnityEngine;

public class StageManager : MonoBehaviour
{
    public static StageManager Instance { get; private set; }

    [SerializeField] private List<GameObject> enemies = new List<GameObject>();
    private static Queue<Action> jobQueue = new Queue<Action>();

    private void Awake()
    {
        Debug.Log("StageManager Awake");
        if (Instance == null)
        {
            Instance = this;
            ProcessJobQueue();
        }
        else
        {
            Destroy(gameObject);
        }
    }

    public static void AddEnemy(GameObject enemy)
    {
        //TODO: Awake가 호출되기 전에 함수가 호출된 경우 Job Queue에 추가하는 코드를 작성하세요.
        
    }

    private void AddEnemyInternal(GameObject enemy)
    {
        enemies.Add(enemy);
    }

    public void RemoveEnemy(GameObject enemy)
    {
        enemies.Remove(enemy);
    }

    private void ProcessJobQueue()
    {
        // TODO: Job Queue를 처리하는 코드를 작성하세요.
        // JobQueue가 빌 때까지 JobQueue에 있는 작업을 빼내서 실행
        
    }

    public bool IsStageClear()
    {
        return enemies.Count == 0;
    }
}
using UnityEngine;

public class Enemy : MonoBehaviour
{
    private void Awake()
    {
        Debug.Log("Enemy Awake");
        // 적을 StageManager에 등록
        StageManager.AddEnemy(gameObject);
    }

    // 적이 죽었을 때 호출되는 메서드
    public void OnEnemyDeath()
    {
        // 적이 죽었을 때 StageManager에서 적을 제거
        StageManager.Instance.RemoveEnemy(gameObject);
    }
}


profile
스터디 로그
post-custom-banner

0개의 댓글