GameDev/Cubidom

Cubidom 게임 재시작하기

SMNNMN 2026. 3. 23. 03:14

게임 재시작하기

게임 종료 후 Retry 버튼을 클릭했을 때, 실행할 함수를 GameManager에 작성하고 실행하는 방식으로 구현할 것이다.

 

GameManager

    public event Action reGame;
    public event Action gameInit;
    
public void ReGame()
    {
        reGame?.Invoke();
        gameInit?.Invoke();

        myState = GameState.START;
        winner = Winner.NONE;
        Time.timeScale = 1f;
    }

가장 먼저 만든 것은 GameManager에서 Retry 버튼을 눌렀을 때, 실행될 함수를 만들었다.

reGame 델리게이트의 경우, 게임에 남아있는 큐브들을 모두 제거하는 과정이며, 

gameInit 델리게이트는 다시 게임을 초기상태로 만드는 이벤트로 모두 제거후 생성되게끔 각각 나눠서 작성했다.

 

CubeCreator

    [SerializeField] Caster[] casters;

void Start()
    {
        GameManager.Instance.reGame += ReStart;
        GameManager.Instance.gameInit += gameInit;
        
    }
    private void OnDisable()
    {
        GameManager.Instance.reGame -= ReStart;
        GameManager.Instance.gameInit -= gameInit;
    }

void ReStart() // 게임이 재시작 되었을 때, 코어를 제외한 모든 큐브르 삭제한다. 
    {
        Debug.Log("Cube 모두 삭제");
        foreach (var caster in casters)
        {
            foreach(var block in caster.haveBlock)
            {
                Destroy(block.gameObject);
            }
            caster.haveBlock.Clear();
            caster.haveCube.Clear();
        }
        posList.Clear();
        blockList.Clear();
        Debug.Log("5");
    }

reGame 이벤트를 먼저 만들고, 그 다음 만든 기능은 CubeCreator에서 배치되어있는 모든 큐브를 제거하는 기능이다.

casters 라는 시전자 배열을 통해, 현재 시전자들이 가지고 있는 블럭들을 참조하여, haveBlock이나 haveCube들을 Clear시킨다.

이후 CubeCreator에 있는 posList나 blockList를 클리어하여, 남아있는 큐브가 없도록 한다.

이때 원래는 haveBlock과 haveCube에는 Core가 없었는데, 코드를 수정하면서 처음부터 Core가 리스트에 있게끔 해주었다.

 

UIManager

      void Start()
    {
        GameManager.Instance.enemySelete += enemyLevel;
        GameManager.Instance.gameStart += playStart;
        GameManager.Instance.gameFinish += FinishUI;
        GameManager.Instance.reGame += ReStartUI;
    }

    private void OnDisable()
    {
        GameManager.Instance.enemySelete -= enemyLevel;
        GameManager.Instance.gameStart -= playStart;
        GameManager.Instance.gameFinish -= FinishUI;
        GameManager.Instance.reGame -= ReStartUI;
    }
  
  void ReStartUI()
    {
        finishPanel.SetActive(false);
        retryButton.SetActive(false);
        enemyWin_t.SetActive(false);
        playerWin_t.SetActive(false);
    }

이후 UIManager에서 다시 게임이 진행될때, 현재 UI창에 gameFinish UI들을 지워준다.

 

CubeCreator

    [SerializeField] GameObject[] corePre;

void Start()
    {
        GameManager.Instance.reGame += ReStart;
        GameManager.Instance.gameInit += gameInit;
        
    }
    private void OnDisable()
    {
        GameManager.Instance.reGame -= ReStart;
        GameManager.Instance.gameInit -= gameInit;
    }    
    
    void gameInit() // 게임이 재시작 되고, 모든 큐브의 삭제이후, 게임 상태를 초기화한다.
    {
        foreach(var core in corePre)
        {
            GameObject prefab = Instantiate(core); // 코어 생성
            foreach(var caster in casters) // 코어의 시전자 부착
            {
                switch (prefab.GetComponent<Core>().caster_E)
                {
                    case Core.Caster_E.PLAYER: if(caster is InputController) 
                        { 
                            caster.core = prefab.GetComponent<Core>();
                            prefab.GetComponent<Core>().myCaster = caster.GetComponent<InputController>();
                            caster.GetComponent<InputController>().haveBlock.Add(prefab.GetComponent<Block>());
                            caster.GetComponent<InputController>().haveCube.Add(prefab.GetComponent<Core>());
                        }
                        break;
                    case Core.Caster_E.ENEMY: if(caster is EnemyAI) 
                        { 
                            caster.core = prefab.GetComponent<Core>();
                            prefab.GetComponent<Core>().myCaster = caster.GetComponent<EnemyAI>();
                            caster.GetComponent<EnemyAI>().haveBlock.Add(prefab.GetComponent<Block>());
                            caster.GetComponent<EnemyAI>().haveCube.Add(prefab.GetComponent<Core>());
                        }
                        break;
                }
                Debug.Log(prefab, caster);
            }
        }
    }

그 이후에 게임의 상태를 다시 초기화 하는 기능을 만들었다.

먼저 코어들을 생성시키기 위해 GameObject 배열로 프리팹을 생성시킨다.

casters를 통해 코어의 Enum 값에 따라 시전자를 분리시키고, Caster의 core와 myCaster에 값을 넣어준다. (후에 설명)

그리고 나서 시전자의 haveBlock과 haveCube에 코어를 추가해준다.

 

Core

using UnityEngine;
using System;

public class Core : Cube
{
    public enum Caster_E
    {
        PLAYER,
        ENEMY,
    }
    public Caster_E caster_E;

    // [SerializeField] CubeCreator cube_C;
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        // cube_C.posList.Add(worldPosition);
        CubeCreator.Instance.posList.Add(worldPosition);
        // cube_C.blockList.Add(this);
        CubeCreator.Instance.blockList.Add(this);

    }
    private void OnDestroy() // 코어가 파괴되었을 때
    {
        if(GameManager.Instance.winner == GameManager.Winner.NONE && isdead)
        {
            GameManager.Instance.CoreDestroyed(myCaster);
        }
    }
}

코어에 기능을 추가해서 재시작 기능을 만들었는데, Caster_E를 통해서 현재 자신의 코어가 Enemy용인지 Player용인지를 판단시킨다.

OnDestroy 함수에서는 isdead라는 변수를 하나 만들어서 조건에 추가해 주었다. 게임이 재시작 될때, 코어또한 사라지기 때문에 OnDestroy 함수가 출력될 수 있는데, 이 경우를 막기 위해서 사용되었다. (후에 설명)

 

Cube

using System;
using UnityEngine;

public class Cube : Block, IDamageable
{
    [SerializeField] float hp;
    public event Action CubeDissapear;
    protected bool isdead = false;
    public void OnDamage(float damage) // 데미지를 받는 함수
    {
        hp -= damage;
        if(hp <= 0)
        {
            hp = 0;
            OnDelete();
        }
         
    }
    void OnDelete() // hp가 0이하 되었을 때 사라지는 하무
    {
        Debug.Log(gameObject.name + "사라짐");
        CubeDissapear?.Invoke();
        isdead = true;
        CubeCreator.Instance.DeleteBlock(this, myCaster);
        // Destroy(gameObject);
    }
}

isdead의 경우 체력이 0이하일때 OnDelate가 실행되고 이 함수에서 isDead가 실행된다. 때문에 Destroy로 강제 삭제시키는 경우 isdead가 false인 채로 삭제되기 때문에 Core의 OnDestroy 함수가 실행되지 않는다. 

 

Caster

using NUnit.Framework;
using UnityEngine;
using System.Collections.Generic;

public class Caster : MonoBehaviour
{
    public float totalResource; // 자원량
    public List<Block> haveBlock = new List<Block>(); // 자신이 가지고 있는 블럭 (자신의 블럭)
    public List<Cube> haveCube = new List<Cube>(); // 자신이 가지고 있는 큐브 
    public Core core; // 기준 코어
    protected virtual void Awake()
    {
        haveBlock.Add(core);
        haveCube.Add(core);
        Debug.Log(gameObject.name);
    }
    protected virtual void Start()
    {
        GameManager.Instance.gameInit += Init;
    }
    protected virtual void Init()
    {
        
    }
    // Update is called once per frame
    void Update()
    {
        
    }
    protected virtual void OnDisable()
    {
        GameManager.Instance.gameInit -= Init;
    }
}

재시작 기능을 위해서 Caster 스크립트를 변경해줄 필요가 있었다. 

먼저 core를 직접 사용해서 haveBlock과 haveCube에 코어를 직접 넣어준다. Awake에서 실행한 이 코드는 처음 게임이 실행되었을 때, 유효한 코드이다. 만약  이 코드가 없다면 코어가 사라질때, 코어에 붙어있는 Structure가 사라지지 않는 경우가 발생한다.

이후 protected virtual 가상함수를 통해서 Start와 OnDisable에 GameManager의 gameInit에 Init 함수를 구독하게 한다. 

Init 함수의 경우, 게임이 재시작될 때, 상태를 초기화 하는 코드를 구현하는 함수자리이다. 

 

InputController

    protected override void Awake()
    {
        if(instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }

        core.myCaster = this;
        base.Awake();

    }
	protected override void Start()
    {
        base.Start();
        totalResource = 50;
    }

    protected override void Init()
    {
        totalResource = 50;
    }
    protected override void OnDisable()
    {
        base.OnDisable();
    }

Awake와 Start, Init, OnDisable 가상함수를 받기 때문에 모두 protected override를 작성하고 base.~를 작성하여 구독을 완료한다.

Init 함수에는 현재 필요로 한 자원량 초기화 코드를 작성한다. 

 

EnemyAI

    protected override void Awake()
    {
        base.Awake();
        currentState = EnemyState.Alive;
        // haveBlock.Add(core);
        // haveCube.Add(core);
        core.myCaster = this;
    }
    protected override void Start()
    {
        base.Start();
        GameManager.Instance.gameStart += LevelSetUp;
        GameManager.Instance.gameStart += StartMyCoroutine;
    }
    protected override void Init()
    {
        totalResource = 50;
        enemyData = aiData[GameManager.Instance.enemyLevel - 1];
        Debug.Log(enemyData);
    }
    void LevelSetUp()
    {
        enemyData = aiData[GameManager.Instance.enemyLevel - 1];
        Debug.Log(enemyData);

        thinkDelay = enemyData.thinkDelay;
        behaviourRandomness = enemyData.behaviourRandomness;
        positionRandomness = enemyData.positionRandomness;
    }
    protected override void OnDisable()
    {
        base.OnDisable();
        GameManager.Instance.gameStart -= LevelSetUp;
        GameManager.Instance.gameStart -= StartMyCoroutine;
    }

EnemyAI에서는 InputController와 마찬가지로 Awake, Start, Init, OnDsiable을 base로 사용한다.

Init함수의 경우 레벨을 앞전에 선택했는 레벨 그대로를 따라야 하기 때문에 자원량 초기화와 더불어, enemyData에 레벨을 새로 넣어준다. (사실 안넣어도 되는데, 혹시모르니..)

 

플로우차트

 

 

EnemyVisual

using UnityEngine;

public class EnemyVisual : MonoBehaviour
{
    private MeshRenderer render;

    private void Awake()
    {
        render = GetComponent<MeshRenderer>();
    }
    private void Start()
    {
        GameManager.Instance.changeMaterial += ChangeMaterial;
        ChangeMaterial();
    }
    void ChangeMaterial()
    {
        render.material = Resources.Load<Material>("Materials/Enemy_Level/EnemyCore_M " + GameManager.Instance.enemyLevel);
        Debug.Log(render.material.name);
    }
    private void OnDisable()
    {
        GameManager.Instance.changeMaterial -= ChangeMaterial;
    }
}

게임이 재시작 될때, 코어의 색이 선택한 레벨에 따라 초기화 될수 있게끔 Start에 ChangeMaterial 함수를 실행해준다. 

Core에 붙어있는 스크립트이기 때문에 코어가 실행될때, Start에서 레벨에 따라 material 색을 바꾸는 기능을 구현했다. 

 

 

완성본

'GameDev > Cubidom' 카테고리의 다른 글

Cubidom Enemy, 카메라,UI 버그 수정  (0) 2026.03.25
Cubidom 메인화면으로 이동  (0) 2026.03.24
Cubidom 게임 종료 UI  (0) 2026.03.20
Cubidom 적 난이도 세팅  (0) 2026.03.20
Cubidom 적 난이도 선택  (0) 2026.03.19