카테고리 없음

2025_02_18 TIL

chajungto0211 2025. 2. 18. 20:31

유니티 기초 주차 3일째에 접어들었다. 솔직히 뭐 했다고 벌써 3일이 지나갔고, 캠프 1달차를 바라보고 있는지 모르겠다. 그래도 이게 다 열심히 공불한 보람인지 시간이 빠르게 지나간 거라고 생각하면, 또 내가 해냈구나 라는 생각이 들게 되어 좋은것 같다. 아무튼 오늘의 내가 한 행동을 돌아보자.

 

1. 게임 구상

사실상 내가 만들어야 할 게임을 정해져있었다. 필수 과제에서 " 미니 게임은 플래피버드 스타일(장애물 회피) 또는 스택 스타일(블록 쌓기) 중 선택" 이라고 쓰여져 있었기 때문에 만약에 내가 추가로 무언가를 만들다가 시간이 초과되었을 경우를 대비하여 필수를 먼저 구현하는 것이 맞았기 때문이다. 하지만, 일단 나는 지레 겁을 먹었다. 왜냐하면, 내가 듣기로는 스택 스타일은 3D로 하는 게임인데 현재 구현하는 건 2D라서 힘들것 같았고, 장애물 회피형은 듣기로는 탑 다운 형식의 총 쏘는 게임인데 이걸 구현할까 하기에는 자신이 없었다. 그럼 무얼 선택했냐? 지금 보면 미친 생각인데, 그냥 내가 새로운걸 하나 만들고 내일 둘 중 하나를 만들자라는 계획을 세웠다. (제가 왜 그랬을까요 이해가 안가네요)  그래서 어떤 게임을 만들까 고민하다가, 어짜피 지금 내 공간 컨셉이 내일배움캠프이고, 모두 다 개발을 공부하러 왔으니 개발과 연관지어 보면 어떨까? 해서 만들게 된 게임이 "오류 찾기 게임"이다.

 

2. 오류 찾기 게임

내 나름대로의 규칙을 세웠다. 좌우로밖에 움직이지 못하는 마우스 커서 게임오브젝트 하나와 상하로밖에 움직이지 못하는 중단점 하나를 이용해 움직여서 맵 내에서 뜨는 오류들을 잡으면 되는 게임이다. 오류를 잡는 방법은 두 말을 움직여서 선이 겹치도록 한 뒤 그 위에 오류가 오도록 만들어 스페이스바를 두르면 점수가 올라가는 형식이다.

파란색이 마우스 커서, 빨간색이 중단점이다.

일단 이 게임을 구현하기 위해 타일맵을 모니터에서 화면 보는 느낌이 있도록 만들었고(그런 느낌이 없다면 유감), 두 말들이 범위를 벗어나지 않도록 해당 부분에 콜라이더를 설정하였다.

 

완성된 타일 맵

그 후, 움직여야하는 두 말에 각각 Input System을 넣어서 상하/ 좌우로만 움직이도록 설정하였다.그리고 혹시나 콜라이더에 부딪혀 말이 돌아가는 일이 없도록 z축을 고정시켰다. 그리고 각 선들을 해당하는 말의 하위 자식으로 두어 따라다니도록 설정했다.

 

3. 트러블 슈팅의 연속

 

이렇게 어느정도 잘 풀리는 듯 싶었지만, 난 언제든 행복할 수 없었다. 이제 두 선에 콜라이더를 붙히고, 오류코드와 둘다 겹쳤을 때 스페이스 바를 누르면 없어지게 해야하는데, 왜 이러지 싶을 정도로 제대로 되지 않았다. 분명 Input System도 오타가 없었고, 리지드바디는 오류코드에 붙어있었으며, 다른 오류도 드지 않았기 때문이다. 그래서 너무 답답한 마음에 튜터님에게 다가가 여쭤보니... 놀랍게도...! 그냥 내가 적은 함수의 이름에서 g를 하나 더 눌러적은 것이었다.... 이름이 다르니 그냥 다른 함수로 판단하여 작동 자체를 멈추었던 것이었다...  밑은 내가 바보같은 실수를 한 코드이다.

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class ErrorCode : MonoBehaviour
{
    public List<Collider2D> lines = new List<Collider2D>();            //검출될 라인들의 충돌

    void OnTriggerEnter2D(Collider2D collider)
    {
        lines.Add(collider);
        Debug.Log("추가");
    }

    void OnTriggerExit2D(Collider2D collider)
    {
        lines.Remove(collider);
        Debug.Log("제거");
    }

    private void OnRemove()
    {
        if (lines.Count == 2)
        {
            Destroy(this.gameObject);
            Debug.Log("눌림");
            FindErrorGameManager.Instance.score++;
        }
    }
}

다행히 스펠링을 고치고 나니 정상작동하였다. 뻘쭘했다..

 

하지만 이게 끝이 아니었다. 분명 내가 오류 코드를 랜덤 생성하는 코드를 짜고 테스트해볼 시기였다.

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

public class FindErrorGameManager : MonoBehaviour
{
    private static FindErrorGameManager instance;        //싱글톤

    public static FindErrorGameManager Instance          //싱글톤 프로퍼티
    {
        get
        {
            if (null == instance)
            {
                return null;
            }
            return instance;
        }
    }

    [SerializeField]
    List<GameObject> errorCodes = new List<GameObject>();       //오류코드들

    public float currentTime = 0f;              //시간

    public float routine = 1.5f;                  //생성주기

    public float routineTime = 0f;              //생성주기 측정

    public float limitTime = 60f;               //제한시간

    public Text TimeTxt;                        //시간 표시

    public Text ScoreTxt;                       //점수 표시

    public Text FinalScoreTxt;                  //최종점수 표시

    public Text BestScoreTxt;                  //최고점수 표시

    public int score = 0;                           //점수

    public GameObject StartPanel;               //시작 패널

    public GameObject EndPanel;                 //종료 패널

    public GameObject DescriptionPanel;         //설명 패널

    private void Awake()
    {
        if (null == instance)
        {
            instance = this;
        }
        else
        {
            Destroy(this.gameObject);
        }
    }

    private void Start()
    {
        StartPanel.SetActive(true);
        EndPanel.SetActive(false);
        BestScoreTxt.text = PlayerPrefs.GetInt("BestScore").ToString();
        Time.timeScale = 0f;
    }

    private void Update()
    {
        if (Time.timeScale == 1f)
        {
            currentTime += Time.deltaTime;
            routineTime += Time.deltaTime;
        }
        TimeTxt.text = string.Format("{0:N2}", currentTime);
        ScoreTxt.text = score.ToString();
        FinalScoreTxt.text = score.ToString();

        if (currentTime >= 60)
        {
            EndPanel.SetActive(true);
            Time.timeScale = 0f;
            if (score > PlayerPrefs.GetInt("BestScore"))
            {
                PlayerPrefs.SetInt("BestScore", score);
                BestScoreTxt.text = PlayerPrefs.GetInt("BestScore").ToString();
            }

        }

        if (currentTime >= 30f)
        {
            routine = 1f;
        }

        int randomIndex = Random.Range(0, errorCodes.Count);
        float xPos = Random.Range(-9.65f, 9.65f);
        float yPos = Random.Range(-3.8f, 3.8f);

        int randomNumber = Random.Range(0, errorCodes.Count);
        if (routineTime >= routine)
        {
            GameObject errorCode = Instantiate(errorCodes[randomIndex], new Vector2(xPos, yPos), Quaternion.identity);
            Destroy(errorCode, 3f);
            routineTime = 0f;
        }
    }
}

코드상으로는 문제가 없었는데, 테스트할 당시에 특정 "오류 코드 게임 오브젝트"가 선 위로 표시가 되었던 것이었다. 분명히 다른 오류 코드들은 밑으로 표시가 되었었다. 이게 왜이러지 하고 해당 오브젝트와 다른 오브젝트의 차이점을 분석할려고 해당 오브젝트의 프리펩, 스프라이트 크기, 오더 인 레이어 등등 다 살펴보았지만 다른점을 찾을수가 없었다. 그래서 어쩔수 없이 튜터님에게 가서 질문했는데, 또 내가 바보같은 짓을 했음을 깨달았다. 해당 오브젝트들 끼리 비교하는 것이 아닌, 겹치는 선과 비교를 했어야 했다. 해당 선들의 오더 인 레이어는 10이었고, 내가 비교한 것들의 오브젝트들도 10이었다. 그렇다면 여기서 의문이 들수도 있다. 모두 다 10 인데 그럼 다른 오브젝트들도 다 같은 현상을 겪어야 하는 것이 아닌가?

여기서 설명하자면, 나는 해당 오브젝트를 샘플로 하나 만든 후 선들을 만들었고, 그 후 다른 오류 코드의 종류들을 만들었다. 이때 다 오더 인 레이어가 10으로 설정되어 있어, 시스템 내부에서 자체적으로 순서를 판단하여 샘플로 만들었었던 오브젝트만 해당 현상을 띄게 된 것이었다. 해당 문제점을 안 후에, 나는 선들의 오더 인 레이어를 고쳐주었다. 그리고 나머지 UI작업을 무사히 완성했다.

선의 오더 인 레이어
오류 코드 오브젝트의 오더 인 레이어

게임 하나 만드는게 굉장히 힘들고 어려웠지만, 그래도 정확하게 돌아가는 모습을 보니 뿌뜻하는 생각도 든다. 내일도 이런 기분으로 게임을 하나 더 만들었으면 한다.

 

////해당 TIL은 저의 학습을 돌아보는 내용이라 틀린게 있을수도 있습니다!////