Unity/Unity Study

[Unity] 세번째 게임, '고양이 밥주기 게임' 완성

JEE_YA 2025. 1. 28. 22:01

1, 2주차에서 사용했던 내용이 많아 해당 내용들은 패스, 새로운 부분들에 대해서만 몇가지 기록하고자 한다.

대략 게임은 배고픈 고양이로부터 생선가게 주인인 강아지가 고양이에게 밥을 주어(거의 던지고있지만) 배부른 고양이로 만들어 가게에 오지 않게 지키는 게임이다.

 


 

게임 시작 화면

 

플레이 버튼을 누르면 게임이 시작된다.

 

저번 게임까지는 MainScene 하나로 진행했으나 이번 게임은 MainScene(게임이 진행되는 메인 씬)외에 StartScene을 추가하여 처음 시작화면을 따로 만들어주었다.

 

스타트 버튼을 누르면 게임 화면(MainScene)으로 이동해주어야 하기 때문에 Button 오브젝트를 생성,

MainScene으로 이동할 수 있게 스타트 버튼에 대한 스크립트를 만들고 using문을 이용하여 Scene을 관리해주는 SceneManagement를 추가해준 후 코드를 작성해주었다.

Using UnityEngine.SceneManagement;

public void Start()
	{
	SceneManager.LoadScene("SceneName");
    }

SceneName 부분에 이동하고자 하는 씬의 오브젝트 이름을 넣어주면 된다.

 

 

Food

 

  • Food 스크립트에는 간단하게 오브젝트가 생성되면 무조건 위로 직진하게 설정
    void Update()
    {
        transform.position += Vector3.up * 0.5f;
    }
  • Vector3.up을 이용, 이후 if문을 사용하여 일정 좌표값보다 넘으면 Destroy 함수를 이용하여 일정 범위 밖으로 벗어난 경우에 파괴하는 로직 생성
  • 고양이와 충돌할때 CompareTag를 사용하기 위해 Collider를 추가
  • Rigidbody 컴포넌트를 추가하여 중력 발생하게 하기
  • Food 태그 생성하여 적용하였음 (추후 Cat 부분에서 충돌(Collision) 로직을 추가하기 위해)

 

 

Dog

 

  • 강아지의 움직임은 2번째 게임에서 사용했던 mousePos를 이용하여 x값만 가져왔으며 강아지가 위아래로 움직이지 않기에 y값은 현재와 그대로 설정.
  • Food를 강아지 위치에서 사용할 수 있게 쏘는 로직 생성, Food는 한번이 아닌 여러번 반복되어 생성하기 때문에 InvokeRepeating 사용
    void Start()
    {
        InvokeRepeating("MakeFood", 0f, 0.1f);
    }
  • - InvokeReapeating("메서드 이름", float time/지연시간(즉시 호출할때는 0), float repeatRate/반복호출할 간격
    나의 경우 만들어두었던 MakeFood 메서드, 즉시 호출, 0.1초마다 반복호출 로 설정해주었으며 
    반복호출의 경우 0.5가 초기값이나 나는 원활한 테스트와 빠른 진행을 위해 ㅎㅎ...

 

 

Cat

 

  • 고양이 오브젝트를 생성, 하위에 배고픈 고양이 / 배부른 고양이 생성 
    (다른 고양이를 추가할 경우 동일하게 고양이 오브젝트 생성, 상위 오브젝트는 일반 고양이와 구분할 수 있게 이름 변경하기!)
  • 애니메이션을 설정하여 배고픈 고양이 / 배부른 고양이 전환
  • 고양이가 너무 빨리 내려올 경우 Frame 고정 andom.Range를 통해 임의의 위치에서 내려오게 하기.
  • Food와 마찬가지로 Collider 컴포넌트 적용
  • 고양이의 크기, 속도 등 속성에 대해서 스크립트에 작성 (고양이별로 내려오는 속도가 다르게 설정)
  • 스크립트에 고양이 에너지에 대한 코드를 추가, 일정 에너지보다 커질 경우 배고픈 고양이가 될수있게 함
    (에너지가 초과하지 않도록 사전에 bool값(bool isFull = false;)을 추가해주었음)
    에너지바(체력바, 게이지)에 대한 내용(RectTransFrom) 등은 밑에 따로 추가하였으며 이부분은 이해하는 데에 오랜 시간이 걸렸다.. 
    private void OnTriggerEnter2D(Collider2D collision)
    {
    	// food 태그가 걸린 것과 충돌할 경우
        if (collision.gameObject.CompareTag("Food"))
        {
            if (energy < full)
            {
                energy += 1.0f;
                // 애너지바(체력바)에 대한 내용
                front.localScale = new Vector3(energy / full, 1.0f, 1.0f);
                Destroy(collision.gameObject);

                if (energy == 5.0f)
                {
                    //isFull이 false가 될때에만 이프문이 적용되게
                    //isFull == false도 가능하나 !를 붙여서 동일하게 됨 (!=반대)
                    if (!isFull)
                    {
                        isFull = true;
                        // 배고픈 고양이를 꺼주고, 배부른 고양이를 켜준다(유니티 내 오브젝트)
                        hungryCat.SetActive(false);
                        fullCat.SetActive(true);
                        Destroy(gameObject, 3.0f);
                        GameManager.Instance.AddScore();
                    }
                }
            }
        }
    }

 

 

레벨 설정

 

게임매니저엔 int로 하여 레벨값, 스코어 값을 넣어주었으며

	int level = 0;
	int score = 0;

	public void AddScore()
	{
    	score ++;
    	level = score / 5;
	}

배부른 고양이가 된 마리수에 따라 레벨 및 스코어가 올라갈 수 있게 로직을 만들어주었다.

 

그리고 레벨에 따라 고양이가 생성되는 퍼센트와 다른 고양이가 나올 수 있게 if문을 통하여 생성해주었다.

    void MakeCat()
    {
        Instantiate(nomalCat);
        int p = Random.Range(0, 10);

        // Lv.1 20%확률로 고양이를 더 생성해준다.
        if(level == 1)
        {
            if(p < 2) Instantiate(nomalCat);
        }
        // Lv.2 50%확률로 고양이를 더 생성해준다.
        else if(level == 2)
        {
            if (p < 5) Instantiate(nomalCat);
        }
        // Lv.3 뚱뚱한 고양이를 생성해준다.
        else if(level >= 3)
        {
            Instantiate(fatCat);
        }
        // Lv.4 해적 고양이를 생성해준다.
        else if(level >= 4)
        {
			if (p < 5) Instantiate(nomalCat);
        	
            Instantiate(fatCat);
            Instantiate(pirateCat);
        }
    }

레벨 4의 경우 과제로 진행되었는데, == 숫자로만 표시하면 해당 레벨에서만 나오는것을 뚱뚱한 고양이를 추가하다 알게되었다..

이때문에 >=를 사용해야 한다는걸 알게되었고 위와같이 작성하여 최종적으로는 레벨 4부터 모든 고양이가 나오게 된다!

다만 과제 전 3레벨에 >=를 넣은 후 과제를 진행하다 3, 4레벨 전부 >=를 넣어주었더니 이상하게 나와 3레벨은 == 만 넣고 4레벨에만 >= 를 넣어주게 되었다.

if와 else if에 대해서는 정말 많이 쓰일것 같아 이부분에 대해 공부하고 그 내용이 맞는지 튜터님께 여쭤보았는데 드린 질문은 아래와 같다.

 

  1. if와 else if는 하나만 적용되는걸로 알고있어 레벨 4에 위에 써두었던 if (p < 5) Instantiate(nomalCat);과 Instantiate(fatCat)을 다시한번 사용해준것이 맞는지
  2. nomalCat은 if 전에 이미 instantiate 로 처리되어 있어 계속 나오는 것인지

 

일단 결론적으로 2번의 경우 if 전에 계속 nomalCat이 나오게 설정해두었기 때문에 레벨과 관계없이 생성되며

if부터 시작해서 순서대로 맞는 조건에 맞게 실행되기 때문에 3, 4레벨 전부 >=를 해두면 레벨3의 로직에서 멈춰있기때문에 이후 레벨에서 piratCat이 나올수 없는 것이었다.

 

 

점수 추가 및 레벨 표시

 

unsing문에 UnityEngine.UI를 추가, 레벨에 대한 게임오브젝트의 태그를 UI로 변경

유니티 내에 레벨 오브젝트를 만들어 위치, 이미지 등을 설정해주고 이미지 안에 UI > Text를 생성,

게임매니저 스크립트에서 public으로 하여 RectTransForm, Text를 추가하여 level에 관련된 내용을 사용할 수 있게 해준다.

레벨에 대한 오브젝트

    public void AddScore()
    {
        //score += 1;로도 가능, 스코어가 1씩 올라갈수있게 하는것 
        score++;
        level = score / 5;
        levelTxt.text = level.ToString();
        // 이 부분은 밑에 추가할 RectTransFrom에 대한 코드
        levelFront.localScale = new Vector3((score - level * 5) / 5.0f, 1f, 1f);
    }

 

 

고양이 배부름 표시 및 레벨 게이지 등

 

게이지

 

난 이게 제일 신기했다, 움직이는 거나 다른거야 오.. 였는데 얘는 오오.. 였다.

고양이와 밥이 충돌하면 고양이 쪽에도 게이지가 차고, 배부른 고양이가 많아지면 많아질수록 상단에 있는 레벨 밑의 게이지가 차면서 레벨이 오르는 형식인데, 둘다 RectTransForm 클래스를 이용한다.

(RectTransForm : UI 위치, 크기, 정렬 등을 관리하는 클래스, 레벨의 게이지바를 위해 사용)

 

해당 스크립트(여기선 Cat과 게임매니저)에서 public으로 선언하여 RectTransForm클래스를 이용해 변수를 추가한 다음

두개의 오브젝트 중 한개의 scale값을 이용하기 때문에 localScale을 사용, 아래와 같이 코드를 작성하여 진행하였다.

변수명.localScale = new Vector3(내용 / x, y, z);

- localScale : 크기

- 내용 : 계산식의 내용

- 2D에선 z축은 미사용하기 때문에 1f로 고정

(예시로 바로 위 점수 추가 및 레벨 표시 부분의 코드에 주석으로 표시해두었음)

게이지바의 경우 보통 배경(위에 오브젝트는 Back)과 게이지를 나타내는 부분(위에 오브젝트는 Front) 두개의 오브젝트의 scale을 조정하는 방식으로 진행

 

 

대략적으로 위 내용대로 유니티/스크립트를 적용하여 진행하였으며 최종 완성된 게임은 다음과 같다.

고양이 밥주기 게임

위에 설명했던 것처럼... 원래 이렇게 밥이 많이 나오는건 아닌데... 레벨에 따라 테스트 하다 그 레벨에 도달하기도 전에 게임오버가 된 경우도 있었고 ㅎㅎ... 내 성격이 급해서 와다다다 나오게 설정해버렸다ㅋㅋㅜㅜ

이렇게 세번째 게임까지 마무리! 

 

 

 

사실 세번째 게임은 미니 프로젝트 들어가기 훨씬전에 완성했는데...... 그동안 다른거 한다고 너무 늦게 정리했다......

덕분에 글 쓰면서 이게 뭐였더라 하는 상황도 있었다ㅎㅎ.....

그래도 다시한번 복습하면서 예전에는 그냥 모른상태로 지나갓던 부분에 대해서 튜터님께 여쭤보고 확실하게 이해도 하면서 게임 끝냈을 당시엔 몰랏던것도 좀 더 많이 알게되었따^_^ 앞으로도 파이팅!