EasyCastleUNITY

고양이 화살 피하기 게임 본문

유니티 기초

고양이 화살 피하기 게임

EasyCastleT 2023. 8. 2. 13:21

전체 화면

게임의 전체적인 화면 설명 이미지

---게임의 간단한 개요---

이동버튼을 누르면 그 방향으로 플레이어가 이동합니다. (PC에서는 화면 클릭과 키보드를 통해 움직일 수 있습니다.)

플레이어 캐릭터의 체력은 총 10으로, 화살에 부딫칠때마다, 체력이 1씩 감소합니다. 

점수는 화살이 바닥에 닿으면 올라가며, 이때마다 100씩 증가합니다. 

 

플레이어 캐릭터의 체력이 0이 되면, Game Over라는 문구가 나오며 게임이 종료됩니다.

점수는 더 이상 올라가지 않으며, 플레이어 또한 움직이지 않습니다.  

게임 오버

---제작 과정에서의 주의한 점---

1.플레이어가 버튼을 계속 누르면, 캐릭터가 렌더링 영역 밖으로 나가는 문제가 있었다.

   이러한 문제를 Mathf.Clamp라는 메서드를 통해 해결했다.  

https://the-pond.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84-%EB%A7%8C%EB%93%A4%EA%B8%B0-%ED%94%8C%EB%A0%88%EC%9D%B4%EC%96%B4%EC%9D%98-%EC%9D%B4%EB%8F%99%EB%B2%94%EC%9C%84%EB%A5%BC-%EC%A0%9C%ED%95%9C%ED%95%98%EA%B8%B0

 

[유니티 게임 만들기] 플레이어의 이동범위를 제한하기

Step 2. 플레이어의 이동범위를 제한하기 플레이어가 알아서 메인 카메라의 범위 내에서 움직이면 참 좋겠지만 ㅡㅡ 벗어나서 화면밖으로 없어져 버려요. 이럴땐 플레이어의 이동범위를 제한해

the-pond.tistory.com

이 블로그를 참고 했다.

이런 식으로 메서드를 만들어 캐릭터가 움직일 수 있는 영역을 제한시켰다. 

 

2. 게임 오버가 되었지만 캐릭터가 움직이는 문제 

각각의 이동버튼은 CatController의 MoveLeft(), MoveRight() 라는 메서드와 연결되어 있다. 

그렇기에 이 2개의 메서드 자체의 제한 조건을 걸어, 게임이 종료되면 이 함수가 동작할 수 없도록 만들었다. 

게임이 종료되면 이동 불가

3. 게임이 종료되었지만, 점수를 계속 얻는 문제점 

앞에 2번 처럼 똑같이 제한을 걸어, 게임이 종료되면 동작하지 않도록 하였다. 

ArrowController의 점수 계산 부분

ArrowController에서의 cat은 CatController의 instance를 의미한다. 

 

4. 게임 오버 시, 이미 생성된 화살이 그대로 존재하는 문제

3번과 같이 엮여 있는 문제였는데, 화살이 그대로 존재하기에 바닥에 내려와서 점수를 계산하면서

3번 문제가 생긴 것이었다. 그래서 게임이 종료되면 모든 화살들을 삭제하는 방식으로 해결 하였다. 

ArrowController의 Update안에 있음

---전체적인 코드---

CatController: 캐릭터의 이동을 담당하는 클래스 

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

public class CatController : MonoBehaviour
{
    public float radius = 1;
    public int hp = 10;
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        this.transform.position = ClampPosition(this.transform.position);
        //키 입력받기 
       
            if (Input.GetKeyDown(KeyCode.LeftArrow))
            {
                //왼쪽 화살표 누르면 -3이동
                this.MoveLeft();
            }
            else if (Input.GetKeyDown(KeyCode.RightArrow))
            {
                //오른쪽 화살표 누르면 +3이동
                this.MoveRight();
            }
        
    }
    public void MoveLeft()
    {
        if (this.hp > 0)
        {
            this.transform.Translate(-3.0f, 0, 0); //-3씩 이동 좌표 -9~9로 제한
        }
    }

    public void MoveRight()
    {
        if (this.hp > 0)
        {
            this.transform.Translate(3.0f, 0, 0); //3씩 이동 좌표 -9~9로 제한
        }
    }

    public Vector3 ClampPosition(Vector3 position)
    {
        return new Vector3(Mathf.Clamp(position.x, -9.0f, 9.0f), -3.4f, 0);
    }
    //이벤트 함수 
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(this.transform.position, this.radius);
    }
}

ArrowController: 화살의 움직임과, 캐릭터와의 충돌, 화살의 삭제등을 담당하는 클래스

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

public class ArrowController : MonoBehaviour
{
    [SerializeField]  //이 애트리뷰트를 사용하면 private 멤버도 인스펙터에 노출 
    private float speed;
    private GameObject catGo;
    private GameObject gameDirectorGo;
    GameDirector gameDirector;
    private CatController cat;

    public int score=0;
    // Start is called before the first frame update
    void Start()
    {
        this.catGo = GameObject.Find("cat");
        cat = this.catGo.GetComponent<CatController>();
        this.gameDirectorGo = GameObject.Find("GameDirector");
        this.gameDirector = this.gameDirectorGo.GetComponent<GameDirector>();
        Debug.Log("catGo:{0}", this.catGo);
       
    }
    private bool isCollide()
    {
        //두 원사이의 거리, 정확히는 화살의 중점과 고양이의 중점 사이의 거리 
        float distance = Vector3.Distance(this.transform.position, this.catGo.transform.position);

        //반지름의 합
        CatController catController = this.catGo.GetComponent<CatController>();
        float sumRadius = this.radius + catController.radius;
       // Debug.LogFormat("sumRadius:{0}", sumRadius);

        //두 원사이의 거리가 반지름의 합보다 크면 부딪히지 않음 (false)
        //두 원의 반지름의 합이 두 원사이의 거리보다 크다면 부딪혔다. 
        return distance < sumRadius;
    }
    // Update is called once per frame
    void Update()
    {

        //프레임 기반
        //this.gameObject.transform.Translate(0, -1, 0);

        //시간 기반 이동
        //속도 * 방향 * 시간
        //if * new Vector3(0,-1,0) * Time.deltaTime
        this.gameObject.transform.Translate(this.speed * Vector3.down * Time.deltaTime);

        if(this.transform.position.y <= -3.9f) //화살이 바닥에 있을 때 
        {
            if(cat.hp > 0) //게임 진행중 
            {
                gameDirector.score += 100;
            }
            Destroy(this.gameObject);
        }
        if(this.isCollide()) //충돌판단 
        {
            // Debug.LogFormat("충돌했다");
            GameObject gameDirectorGo=GameObject.Find("GameDirector");
            GameDirector gameDirector =gameDirectorGo.GetComponent<GameDirector>();
            gameDirector.DecreseHp();
            //ArrowController 컴포넌트가 붙어있는 게임오브젝트를 씬에서 제거한다
            Destroy(this.gameObject); 
        }
        else
        {
          //  Debug.LogFormat("충돌하지 않았다");
        }
        //게임이 종료되면 이미 생성되어 있던 화살도 전부 삭제 
        if(cat.hp <= 0)
        {
            Destroy(this.gameObject);   
        }
    }
    public float radius = 1;
    //이벤트 함수 
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(this.transform.position, this.radius);
    }
}

ArrowGenerator: 프리팹화된 화살을 생성(랜덤한 위치에 생성) 하는 역할을 하는 클래스

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

public class ArrowGenerator : MonoBehaviour
{
    public GameObject arrowPrefab; //프리팹 원본 파일 
    private float elapsedTime; //경과시간  //Time.deltaTime을 어딘가에다가 누적: 흘러간 시간 
    private GameObject catGo;
    private CatController cat;
    // Start is called before the first frame update
    void Start()
    {
        this.catGo = GameObject.Find("cat");
        cat = this.catGo.GetComponent<CatController>();
    }

    // Update is called once per frame
    void Update()
    {
        //매프레임 마다 Time.deltaTime을 경과시간에 더해준다. 
        this.elapsedTime += Time.deltaTime;
        //경과시간이 1초를 지나갔다면
        if (this.elapsedTime > 1f && cat.hp > 0)
        {
            //화살을 만든다
            this.CreateArrow();
            this.elapsedTime = 0f; //다시 처음부터 누적하도록 초기화
        }
    }
    private void CreateArrow()
    {
        //arrowGo: 프리팹 복제본(인스턴스)
        GameObject arrowGo = Instantiate(this.arrowPrefab);

        arrowGo.transform.position = new Vector3(Random.Range(-9, 10), 6f, 0);
    }
}

GameDirector: UI등 게임의 기능을 전체적으로 통괄하는 클래스

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

public class GameDirector : MonoBehaviour
{
    private GameObject catGo;
    private GameObject hpGaugeGo;
    private GameObject scoreGo; //UI Text 
    private GameObject gameStateGo; //UI Text 
    private CatController cat;

    public int score;
    private int hp;
    // Start is called before the first frame update
    void Start()
    {
        this.catGo=GameObject.Find("cat");
        this.hpGaugeGo=GameObject.Find("hpGauge");
        this.scoreGo = GameObject.Find("ScoreText");
        this.gameStateGo = GameObject.Find("GameState");

        cat = this.catGo.GetComponent<CatController>();

        Debug.LogFormat("this.catGo:{0} this.hpGauge:{1}",this.catGo,this.hpGaugeGo);
        
    }

    void Update()
    {
        this.hp = cat.hp; 
        Text scoreText = this.scoreGo.GetComponent<Text>();
        scoreText.text = string.Format("{0}", score);
        if (this.hp == 0)
        {
            Text gameStateText = this.gameStateGo.GetComponent<Text>();
            gameStateText.text = "Game over";
        }
       

    }
    //체력 감소 
    public void DecreseHp()
    {
        Image hpGauge = this.hpGaugeGo.GetComponent<Image>();
        hpGauge.fillAmount -= 0.1f;  //10%씩 감소
        
        cat.hp--;
    }
}

결과

게임 실행

'유니티 기초' 카테고리의 다른 글

유니티 밤송이 던지기  (0) 2023.08.04
구름 오르기  (0) 2023.08.02
2023/08/01 복습  (0) 2023.08.01
Swipe car 음향 및 UI 추가  (0) 2023.08.01
간단 룰렛  (0) 2023.08.01