Unity/유니티 기본

[4.6] 화살 피하기 게임

ljw4104 2021. 4. 6. 12:37

1. 기본 화면 셋팅

* 고양이가 화면에서 보이지 않으면?

고양이의 Component 중에서 Sprite Renderer의 Order in Layer를 1로 해준다. 그러면 백그라운드 앞에 고양이게 위치하게 된다.

 

2. 기본적인 Player의 움직임 작성 (PlayerController.cs)

PlayerController.cs

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        //해당 키가 눌린 순간
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            transform.Translate(-3, 0, 0);
        }

        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            transform.Translate(3, 0, 0);
        }
    }
}

현재 위치 +3 or -3이기 때문에 연속적인 움직임으로 아직 보이지 않는다.

메서드 동작
GetKeyDown(Keycode key) key가 눌렸을 때
GetKey(Keycode key) key가 눌리는 동안
GetKeyUp(Keycode key) key가 눌렸다가 뗐을 때

 

3. 화살 떨어트리기 ( Physics 사용 X )

using UnityEngine;

public class ArrowController : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, -0.1f, 0);       //프레임마다 등속운동으로 내려온다.

        if(transform.position.y < -4.33f)
        {
            Destroy(gameObject);                //화면 밖으로 나간 오브젝트를 파괴함.
        }
    }
}
  • void UnityEngine.Object.Destroy : 게임오브젝트, 컴포넌트나 에셋을 삭제한다.

하나를 했을 때, 여러개를 했을 때

 

 

4. 화살이 고양이에 닿이면 삭제

using UnityEngine;

public class ArrowController : MonoBehaviour
{
    private GameObject player;

    // Start is called before the first frame update
    void Start()
    {
        this.player = GameObject.Find("player");
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, -0.1f, 0);       //프레임마다 등속운동으로 내려온다.

        if (transform.position.y < -4.33f)
        {
            Destroy(gameObject);                //화면 밖으로 나간 오브젝트를 파괴함.
        }

        //충돌판정
        Vector2 p1 = transform.position;                //화살의 중심좌표
        Vector2 p2 = this.player.transform.position;    //유저의 중심좌표
        Vector2 dir = p1 - p2;                          //화살~유저 사이의 방향벡터
        float d = dir.magnitude;                        //방향벡터의 스칼라(크기)

        float r1 = 0.5f;                                //화살의 반경
        float r2 = 1.0f;                                //플레이어의 반경

        if (d < r1 + r2)
        {
            //벡터의 크기가 화살의 반경과 플레이어의 반경의 합과 겹친다면 충돌했다고 판정함.
            Destroy(gameObject);
        }
    }
}

 

 

4. 화살 프리팹 만들기

4-1. 프리팹 ( Prefab )

  • Hierarchy = 게임오브젝트 / Project = 파일
  • 게임오브젝트의 파일화 ( Hierarchy의 게임오브젝트를 Project 쪽으로 끌고 오면 만들어짐 )
  • 화살같이 같은 오브젝트를 무한히 만들려고 할 때 사용함.
  • 하나 수정하면 다른 것도 수정이 된다. 즉, 각각의 것은 링크되어있다. 하지만 Hierarchy에 나와있는 것을 수정하면 그것만 수정이된다.

Open Prefab을 하면 프리팹을 수정할 수 있다.

 

4-2. Prefab 생성

public GameObject 프리팹이름;

GameObject 이름 = Instantiate<GameObject>(프리팹이름);
//or = Instantiate(프리팹이름) as GameObject;

이름.transform.position = new Vector3(px, 7, 0);

 

 

5. HP바 넣기

1. Image 삽입

  • 메뉴 GameObject -> UI -> Image 로 삽입
  • Source Image에 hp_gauge Sprite Image 삽입

 

1-1. Canvas 설정

Reference Resolution을 항상 설정해야됨.

 

1-2. Anchor 설정

  • 좌표로 UI의 position을 설정하면 기기마다 값이 다를 수 있다. 그러므로 Anchor로 어느 기기든 똑같은 위치에 나타나도록 해야한다.

 

2. HP 게이지 줄여나가기

  • Image 컴포넌트의 Image Type 속성을 simple에서 Filled로 바꿈.
  • Fill Method : Radial 360, Fill Origin : Top
  • Fill Amount를 코드로 줄여나갈 수 있다. ( 손으로 할 수 있는건 코드로 치환이 가능하다. )

using UnityEngine;
using UnityEngine.UI;

public class GameDirector : MonoBehaviour
{
    private GameObject hpGauge;

    // Start is called before the first frame update
    void Start()
    {
        hpGauge = GameObject.Find("hpGauge");
    }

    public void DecreaseHp()
    {
        this.hpGauge.GetComponent<Image>().fillAmount -= 0.1f;
    }
}

 

3. 충돌 했을 때 DecreaseHp() 호출하도록 하기

using UnityEngine;

public class ArrowController : MonoBehaviour
{
    public float arrowSpeed = -0.07f;
    private GameObject player;

    // Start is called before the first frame update
    void Start()
    {
        this.player = GameObject.Find("player");
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, this.arrowSpeed, 0);       //프레임마다 등속운동으로 내려온다.

        if (transform.position.y < -4.33f)
        {
            Destroy(gameObject);                //화면 밖으로 나간 오브젝트를 파괴함.
        }

        //충돌판정
        Vector2 p1 = transform.position;                //화살의 중심좌표
        Vector2 p2 = this.player.transform.position;    //유저의 중심좌표
        Vector2 dir = p1 - p2;                          //화살~유저 사이의 방향벡터
        float d = dir.magnitude;                        //방향벡터의 스칼라(크기)

        float r1 = 0.5f;                                //화살의 반경
        float r2 = 1.0f;                                //플레이어의 반경

        if (d < r1 + r2)
        {
            //감독 스크립트에 플레이어와 화살이 충돌했다고 전달함.
            GameObject directorGo = GameObject.Find("GameDirector");
            directorGo.GetComponent<GameDirector>().DecreaseHp();

            //벡터의 크기가 화살의 반경과 플레이어의 반경의 합과 겹친다면 충돌했다고 판정함.
            Destroy(gameObject);
        }
    }
}

화살을 맞으면 고양이의 체력이 깎이는 것이 아닌, 그냥 이미지만 바뀌고 있다. 지금은

 

 

5. 버튼으로 캐릭터 조작하기

  • Canvas를 UIGame으로 이름을 변경하고, UIGame 스크립트를 새로 만들어 부착
  • UI -> Button 2개를 생성 후 Anchor 설정.

Button에 Event 다는 방법

  1. 위에서 만든 UIGame 스크립트를 연다.
  2. 스크립트에서 처리할 UI를 변수로 선언 후 불러온다.
  3. AddListener 이벤트에 델리게이트로 달아주면 된다.

 

  • 버튼이 조작되었을때, 캐릭터가 움직이게 하는 것은 이 Scene의 모든 것을 담당하는 InGame이라는 스크립트를 새로 만들어 거기서 관리한다.
  • 캐릭터 컨트롤러에는 캐릭터에 관련된 것만, UI에 관련된 것은 UI만 관리하도록 하기 위해서이다.

 

InGame.cs

using UnityEngine;
using UnityEngine.UI;

public class InGame : MonoBehaviour
{
    public PlayerController controller;
    public UIGame uiGame;
    // Start is called before the first frame update
    void Start()
    {
        this.uiGame.lBtn.onClick.AddListener(() =>
        {
            controller.Move(Vector2.left);
        });

        this.uiGame.rBtn.onClick.AddListener(() =>
        {
            controller.Move(Vector2.right);
        });
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
public void Move(Vector2 dir)
{
    transform.Translate(dir.x * 3, 0, 0);
}