GameDev/Cubidom

Cubidom - 디테일 추가 및 버그 수정 1

SMNNMN 2026. 4. 29. 22:45

생각나는 여러 디테일을 추가할 것이다. 

현재 생각나는 것들은

 

생성 블럭 사용 자원량

적 코어 체력

기본 자원량

기본 화면 꾸미기

카메라 제어

음향 설정

기본화면의 나가기, 옵션 버튼

 

 

생성 블럭 자원량 UI

블럭을 생성할 때의 비용을 적어 표시한다. 

 

적 코어 체력

스테이지 별로 적의 코어 체력을 설정할 수 있게 한다. 

EnemyAIData

using UnityEngine;

[CreateAssetMenu(menuName = "Scriptable/EnemyAIData",fileName = "Enemy AI")]
public class EnemyAIData : ScriptableObject
{
    public int id; // 각 데이터마다의 고유 식별번호

    public float behaviourRandomness; // 행동 판단 랜덤계수
    public float positionRandomness; // 생성 위치 판단 랜덤계수
    public float thinkDelay; // 생각하는 시간
    public float totalResource; // 초기 자원량
    public float attackWeight; // 공격행동 가중치
    public float defenceWeight; // 블럭행동 가중치
    public float resourceWeight; // 생산행동 가중치
    public float coreHp; // 코어의 기본 체력
}

coreHp라는 변수를 추가해 적 AI 데이터에 코어 초기 Hp값을 설정한다. 

EnemyAI

    void DataSetUp() // 데이터를 확인해서 적용하는 함수
    {
        int level = GameManager.Instance.enemyLevel;
        int stage = GameManager.Instance.enemyStage;
        int findId = (level * 100) + stage;
        if (aiData.ContainsKey(findId))
        {
            enemyData = aiData[findId];
            Debug.Log(enemyData + " " + findId);
        }

        totalResource = enemyData.totalResource;
        thinkDelay = enemyData.thinkDelay;
        behaviourRandomness = enemyData.behaviourRandomness;
        positionRandomness = enemyData.positionRandomness;
        core.hp = enemyData.coreHp;

        EnemyAttack attack = GetComponent<EnemyAttack>();
        EnemyDefence defence = GetComponent<EnemyDefence>();
        EnemyResource resource = GetComponent<EnemyResource>();

        attack.weight = enemyData.attackWeight;
        defence.weight = enemyData.defenceWeight;
        resource.weight = enemyData.resourceWeight;
        
    }

데이터 셋팅에서 core의 hp값을 데이터의 coreHp값으로 수정해준다. 

 

기본 자원량 수정

플레이어의 기본 자원량을 수정해 줄 것이다.

InputController

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

    protected override void Init()
    {
        totalResource = 150;
    }

Start와 Init에서 플레이어의 초기자원량을 설정해주었다. 

 

기본화면 꾸미기

제목을 추가하고 여러 아이콘들을 넣을 것이다. 기본화면에 있는 보통의 요소들을 추가할 것이다. 

제목넣기

새로 글꼴을 다운받아서 넣어보았다. 

해당 글꼴로 게임의 모든 텍스트를 맞춰줄 것이다. (텍스트를 프리팹으로 만드는 습관을 들이자)

사용한 글꼴: https://noonnu.cc/font_page/1816

 

UIManager

    [SerializeField] GameObject mainSceneUI;
    void enemyLevel() // 적 난이도 UI
    {
        startButton.SetActive(false);
        mainSceneUI.SetActive(false);

        enemyLevels.SetActive(true);
        playButton.SetActive(true);
    }
        void playStart() // 게임시작 시 UI
    {
        if(GameManager.Instance.myState == GameManager.GameState.TUTORIAL) // 튜토리얼 상태일때
        {
            startButton.SetActive(false);
            mainSceneUI.SetActive(false);
        }
        enemyLevels.SetActive(false);
        playButton.SetActive(false);

        resourceValue_T.gameObject.SetActive(true);
        levelStage_T.text = "Level : " + GameManager.Instance.enemyLevel_E.ToString() + "\nStage : " + GameManager.Instance.enemyStage.ToString();

        if(GameManager.Instance.myState != GameManager.GameState.TUTORIAL)
        {
            levelStage_T.gameObject.SetActive(true);
        }
    }   
        void MainUI()
    {
        ReStartUI();
        startButton.SetActive(true);
        mainSceneUI.SetActive(true);
        resourceValue_T.gameObject.SetActive(false);
        levelStage_T.gameObject.SetActive(false);
    }

Start 버튼과 동일하게 활성화 되어야 하니 변수 선언이후 동일한 위치에 활성화 유무 코드를 작성한다.

 

링크 불러오기

이번엔 유튜브랑 블로그 버튼을 클릭하면 해당 사이트로 들어가지는 기능을 만들 것이다. 

UIManager

    public void LinkOpen(string url) // 링크를 타고 들어가는 함수
    {
        Application.OpenURL(url);
    }

Application의 OpenURL을 사용하여 사이트를 불러온다. 

파라미터는 버튼 클릭 이벤트에서 가져온다. 

 

 

카메라 제어 기능

현재 게임 종료시 다음 스테이지를 시작할 경우나, 다시 게임을 재개할 경우, 카메라가 플레이어 코어쪽을 비추지 않고, 마지막에 있었던 위치로 카메라가 이동하기 때문에 이 부분을 수정해 줄 것이다. 

CameraMovement

    private static CameraMovement instance;
    public static CameraMovement Instance
    {
        get { return instance; }
    }

    private void Awake()
    {
        if(instance == null )
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
            brain = GetComponent<CinemachineBrain>();
        tempRotation = playingCam.transform.rotation.eulerAngles;
    }

private Vector3 tempRotation;

void gameStartCam()
    {
        SetPlayingCamera();
        ChangeCamera(playingCam);

        // pitch = transform.rotation.eulerAngles.x;
        // yaw = transform.rotation.eulerAngles.y;

        Vector3 currentRotation = controllCam.transform.rotation.eulerAngles;
        pitch = currentRotation.x;
        yaw = currentRotation.y;
        
        Quaternion rotation = Quaternion.Euler(pitch, yaw, 0);
        offset = rotation * new Vector3(0, 0, -distance);

    }
    void SetPlayingCamera() // 게임 카메라 초기값 세팅
    {
        pitch = tempRotation.x;
        yaw = tempRotation.y;

        Quaternion rotation = Quaternion.Euler(pitch, yaw, 0);
        offset = rotation * new Vector3(0, 0, -distance);

        playingCam.transform.position = target.position + offset;
        playingCam.transform.rotation = rotation;

        zoom = 0;
    }

먼저 접근을 위해 싱글톤으로 작성한다. 

tempRotation을 통해 초기 playingCamera가 가지는 값을 넣고, 게임이 시작될 때, playingCam에 초기 정보값을 넣어준다.

추가로 camera의 orthographicSize를 통일하기 위해 zoom을 0으로 초기화 시킨다. 

CubeCreator

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

                           CameraMovement.Instance.target = prefab.transform;
                       }
                       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);
           }
       }
   }

게임이 초기화 될때, CaramaMovement의 target에 생성된 플레이어 코어를 넣어준다. 

 

음향 설정

설정창에서 배경음과 효과음 볼륨을 설정할 수 있도록 할 것이다. 

BGM 볼륨 설정

AudioManager

    private float optionBGMWeigth = 0.2f; // 옵션창의 배경음 가중치
    public void SetBGMVolume(float value)
    {
        backGroundAudio.volume = value * optionBGMWeight;
    }
        IEnumerator BGMFade(bool type) // type = 1 : FadeIn / type = 0 : FadeOut
    {
        float t = 0;
        float duration,end;
        float start = backGroundAudio.volume;
        switch(type)
        {
            case true: duration = 5; end = backGroundAudio.volume / optionBGMWeight; break;
            case false: duration = 0.5f; end = backGroundAudio.volume * optionBGMWeight; break;
        }
        while(t < duration)
        {
            // t += Time.deltaTime;
            t += Time.unscaledDeltaTime;
            backGroundAudio.volume = Mathf.Lerp(start, end, t / duration);
            yield return null;
        }
    }

BGM의 경우 FadeIn/Out을 사용하기 때문에, 코드를 수정해 주었다. 

optionBGMWeight로 옵션 창일 때의 줄어드는 볼륨 가중치를 만들어주고, 사용한다.

SetBGMVolume 함수의 경우, 슬라이더로 value 값을 받는 함수이다. 옵션창에서 볼륨을 조절하는데, 이 때는 볼륨이 감소되어있는 상태이기 때문에, 볼륨에 가중치를 곱해서 오디오 볼륨에 넣는다. 

BGMFade에서 FadeOut이 된다면 가중치 만큼 곱해주고, FadeIn이 된다면 감쇠된 정도만큼 다시 곱해서 볼륨을 조절한다.

Max Value와 Min Value를 설정해주고, 값 변경 이벤트에 SetBGMVolume을 넣어주면 된다. 

 

SFX 볼륨 설정

AudioManager

    public void SetSFXVolume(float value) => effectAudio.volume = value;
    public void EffectPlay(GameObject clipObject,Vector3 pos) // 효과음 실행 함수
    {
        GameObject audioClip = Instantiate(clipObject, pos,Quaternion.identity);
        
        clipObject.GetComponent<AudioSource>().volume = effectAudio.volume;
        audioClip.GetComponent<AudioSource>().pitch = Random.Range(0.8f, 1.2f);
        StartCoroutine(EffectFinishCheck(audioClip.GetComponent<AudioSource>()));
        Debug.Log("dd");
    }

SetSFXVVolume으로 effectAudio의 볼륨값을 바꾼다.

게임중 나타나는 효과음은 GameObejct로써 소리를 발생시키기 때문에, 생성된 Effect의 AudioSource에 접근해 현재 EffectAudio와 같은 Volume으로 바꿔준다. 

 

기본화면 옵션, 나가기 버튼

기본화면에서 옵션버튼과 나가기 버튼을 만들 것이다.

먼저 Start와 동일한 버튼 두개를 더 추가한뒤 각 버튼에 맞는 클릭 이벤트들을 수정할 것이다.

Option 버튼

    public void OptionClick() // 메인화면의 옵션 버튼을 클릭 했을 때,
    {
        optionPanel.SetActive(true);
    }
        public void OptionUI(bool myBool)
    {
        if(GameManager.Instance.myState != GameManager.GameState.STANDBY)
        {
            InterruptObject.SetActive(!myBool);
        }
        optionPanel.SetActive(myBool);
        Debug.Log("옵션");
    }

OptionClick 함수는 Option 버튼을 눌렀을 때, 실행되는 함수로, 옵션창이 활성화 된다.

OptionUI 함수에서 현재 메인 화면일 때의 조건문을 걸어주었다. (Back Button을 눌렀을 때 실행되는 함수)

Title Canvas Group에 버튼 세개(Main Buttons)를 넣어두어, 따로 관리하지 않고, 메인화면에 있는 여러 UI와 함께 비/활성화 되게 한다.

Exit 버튼

    public void ExitClick() // 메인화면의 나가기 버튼을 클릭 했을 때,
    {
#if UNITY_EDITOR
        UnityEditor.EditorApplication.isPlaying = false;
#else
        Application.Quit();
#endif
    }

Application.Quit로 앱을 종료할 수 있다.

테스트를 위해서 전처리기 지시어를 사용하여 유니티 에디터에서는 현재 플레이를 중단하게끔 한다.

완성본

Option 클릭시 설정창이 생성되며, Exit버튼시 게임이 종료된다.

 

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

Cubidom - AI 시스템 보완 (Utility AI)  (0) 2026.05.03
Cubidom - 디테일 추가 및 버그 수정 2  (0) 2026.04.30
Cubidom - FTUE 3  (0) 2026.04.28
Cubidom - FTUE 만들기 2  (0) 2026.04.27
Cubidom - FTUE 만들기 1  (0) 2026.04.26