Unity 개발일지

[Unity] MonoBehaviour와 Unity 생명주기 실습하기 본문

Unity 개발

[Unity] MonoBehaviour와 Unity 생명주기 실습하기

아머르 2024. 7. 16. 13:11

[확인문제]

 

1. Time.timeScale을 0으로 하면 Update와 FixedUpdate는 모두 호출이 되지 않을까요? 그 이유는 무엇일까요?

더보기

Update와 FixedUpdate 모두 호출되지 않는다.

Time.timeScale은 게임의 시간 흐름을 제어하며, 0으로 설정하면 일반적인 프레임 업데이트가 멈춘다.

따라서, Time.timeScale을 0으로 사용하면 게임을 일시정지하거나 특정 이펙트를 구현하는 데 유용할 수 있으나 게임 오브젝트의 로직을 제어하는데 사용해서는 안된다. 로직 제어에는 Start, Awake, OnEnable, OnDisable과 같은 MonoBehaviour 생명주기 메서드를 사용해야한다.

2. Update의 호출주기에 영향을 주는 것은 무엇일까요?

더보기

프레임 레이트

Update는 매 프레임마다 호출되며, 프레임 레이트에 따라 호출 주기가 달라진다.

고프레임일수록 더 자주 호출된다. 예를 들면, 60fps로 게임을 실행하면 Update는 초당 60번 호출된다.

 

3. FixedUpdate의 호출주기에 영향을 주는 것은 무엇일까요?

더보기

Time.fixedDeltaTime

FixedUpdate는 고정된 시간 간격마다 호출되며, 이 간격은 Time.fixedDeltaTime으로 설정된다.

이는 물리 연산의 일관성을 유지하기 위해 고정된 주기로 호출된다.

 

4. Awake와 Start, OnEnable의 호출순서는 어떻게 될까요?

더보기

 

Awake : 오브젝트가 활성화될 때 처음으로 호출

OnEnable : 오브젝트가 활성화될 때 Awake 이후에 호출. 이미 활성화된 상태라면 Awake 전에 호출될 수 있다.

Start : 오브젝트가 활성화된 후, 첫 Update 호출 전에 한 번만 호출. Awake와 OnEnable이 모두 호출된 후에 호출

 

 

 

[설명문제]

 

1. Unity 생명주기 (Unity Life Cycle)에 대해서 설명해주세요.

더보기

 

게임 오브젝트가 생성되고, 활성화되고, 업데이트되고, 삭제되는 과정을 정의하는 일련의 단계이다.

 

 

2. MonoBehaviour 클래스의 주요 메서드와 그 기능에 대해 설명해주세요.

 * MonoBehaviour 클래스에서 Start와 Awake의 차이점은 무엇이며, 이를 적절히 사용하는 방법에 대해 설명해주세요.

더보기

 

Awake : 스크립트 인스턴스가 로드될 때 호출, 초기화 작업 수행 가능

Start : 오브젝트가 활성화된 후 첫 번째 Update 전에 한 번 호출, 초기화 작업 수행 가능

OnEnable : 오브젝트가 활성화될 때 호출

OnDisabl e: 오브젝트가 비활성화될 때 호출

Update : 매 프레임마다 호출, 주로 게임 로직을 처리

FixedUpdate : 고정된 시간 간격마다 호출, 주로 물리 연산을 처리

LateUpdate : 모든 Update가 호출된 후 매 프레임마다 호출, 주로 카메라 움직임 등 후처리 작업을 수행

OnDestroy : 오브젝트가 파괴될 때 호출

 

StartAwake의 차이점

<Awake>

스크립트 인스턴스가 로드될 때 즉시 호출되며, 종속성 초기화를 포함한 초기화 작업에 적합

<Start>

오브젝트가 활성화된 후 첫 번째 Update 전에 호출되며, 다른 오브젝트와의 상호작용이 필요한 초기화 작업에 적합

 

 

3. Update, FixedUpdate, LateUpdate의 차이점에 대해 설명해주세요.

더보기

 

Update

매 프레임마다 호출되며, 주로 게임 로직을 처리. 프레임 레이트에 따라 호출 주기가 달라진다.

 

FixedUpdate

고정된 시간 간격마다 호출되며, 주로 물리 연산을 처리. Time.fixedDeltaTime에 따라 호출 주기가 고정

 

LateUpdate

모든 Update가 호출된 후 매 프레임마다 호출되며, 주로 카메라 움직임 등 후처리 작업을 수행

 

 

4. Time.deltaTime이란 무엇이며, 사용하는 이유에 대해 설명해주세요.

더보기

이전 프레임과 현재 프레임 사이의 시간 간격을 나타낸다. 이를 사용하여 프레임 레이트에 독립적인 움직임과 애니메이션을 구현할 수 있다. 예를 들어, 오브젝트의 이동을 Time.deltaTime을 곱하여 프레임 레이트에 상관없이 일정한 속도로 이동하도록 할 수 있다.

 

 

[실습문제]

 

💡 [JobQueue 만들기]

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

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

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

StageManager의 초기화 전에 Enemy 오브젝트의 Awake가 먼저 호출되어버려

NullReferenceException 오류가 발생합니다!

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

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

 

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;
    }
}

 

Enemy 클래스

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);
    }
}

 

 

더보기
 public static void AddEnemy(GameObject enemy)
    {
        if (Instance == null)
        {
            // Instance가 아직 초기화되지 않은 경우 Job Queue에 추가
            jobQueue.Enqueue(() => Instance.AddEnemyInternal(enemy));
        }
        else
        {
            Instance.AddEnemyInternal(enemy);
        }
    }
private void ProcessJobQueue()
    {
        // JobQueue가 빌 때까지 JobQueue에 있는 작업을 빼내서 실행
        while (jobQueue.Count > 0)
        {
            var job = jobQueue.Dequeue();
            job();
        }
    }
반응형