전체 페이지뷰

2017년 9월 27일 수요일

Unity Tutorial: 2D Roguelike, part 7


Writing the Player Script




이번 시간에는 플레이어의 스크립트를 작성하도록 하겠습니다. 그 전에 GameManager에 몇가지 추가할 사항이 있습니다. GameManager 스크립트를 에디터로 열어 보도록 합시다.

두개의 퍼블릭 변수와, 한개의 퍼블릭 메소드를 추가하고자 합니다. 처음 부분 변수들 선언 부에
public int playerFoodPoints = 100;
[HideInInspector] public bool playersTurn = true;
cs
를 추가합니다. 보시다시피 플레이어가 음식을 얻었을때 늘어나는 포인트와, 플레이어의 차례인지를 나타내는 bool형의 변수입니다.

한 가지 더,
public void GameOver()
{
    enabled = false;
}
cs
게임이 끝났을 때 게임매니저를 끌수 있는 메소드입니다. 스크립트를 저장하고 유니티로 돌아가서 Scripts 폴더에 Player라는 이름의 스크립트를 하나 생성하고 에디터로 엽시다.

이 클래스는 MonoBehaviour가 아니라 앞에서 작성한 MovingObject를 상속받게 될 것입니다. 따라서 MonoBehaviour를 지우고 MovingObject를 넣습니다.

public class Player : MovingObject
{
    ...
}
cs

먼저 사용할 변수들을 선언합니다.
public int wallDamage = 1// 플레이어가 벽을 쳤을 떄 한번에 받는 데미지
public int pointsPerFood = 10// 음식 하나당 포인트
public int pointsPerSoda = 20// 음료 하나당 포인트
public float restartLevelDelay = 1f; // 레벨 재시작 시 시간딜레이 1초
private Animator animator; // 애니메이터 레퍼런스
private int food;  // 음식 포인트 저장용
cs

Start() 메소드는 상속 받았으므로 override 되어야 합니다. 그 안에서 레퍼런스를 연결합니다.
protected override void Start ()
{
    animator = GetComponent<Animator>();
    // 게임매니저에 저장된 푸드 포인트를 얻어 옴
    food = GameManager.instance.playerFoodPoints;
    base.Start();
}
cs

다음은 유니티 API의 메소드로서 게임 오브젝트가 disable될 때 호출되는 OnDisable입니다.
private void OnDisable()
{
    GameManager.instance.playerFoodPoints = food;
}
cs
여기서 음식 포인트를 현재까지의 포인트로 교체합니다.

그리고 게임이 끝났는가를 판단하는 메소드인 CheckIfGameOver를 작성합니다.
private void CheckIfGameOver()
{
    // 푸드 포인트가 0 이하면 GameOver호출
    if (food <= 0)
        GameManager.instance.GameOver();
}
cs

AttemptMove를 오버라이드 합니다.
protected override void AttemptMove<T>(int xDir, int yDir)
{        
    food--// 한턴 움직일 때마다 푸드 포인트 1 감소
    // 부모 클래스의 AttemptMove 호출
    base.AttemptMove<T>(xDir, yDir); 
    // Move에서 사용할 hit 레퍼런스
    RaycastHit2D hit;
    // 게임이 끝났는지 체크
    CheckIfGameOver();
    // 플레이어의 턴을 false로 설정
    GameManager.instance.playersTurn = false;
}
cs
좀 더 작성해야 하지만 일단 여기서 멈추고,

Update()로 넘어갑니다.
void Update ()
{
    if (!GameManager.instance.playersTurn)
        return;   // 플레이어 차례가 아니면 넘어감
    // 1또는 -1로 가로, 세로 방향 저장용
    int horizontal = 0;
    int vertical = 0;
    // Input 매니저로부터 입력받아 저장
    // 현재는 standalone의 입력만 취급했고 추후 모바일용 추가 예정
    horizontal = (int)Input.GetAxisRaw("Horizontal");
    vertical = (int)Input.GetAxisRaw("Vertical");
    // 가로로 움직였다면 세로는 0
    if (horizontal != 0)
        vertical = 0;
    // 어느 쪽으로든 움직이라는 명령이 있었다면
    if (horizontal != 0 || vertical != 0)
        //플레이어는 벽과도 상호작용할 수 있으므로 제너릭에 Wall을 넘겨줌
        AttemptMove<Wall>(horizontal, vertical);
}
cs

다음은 추상으로 선언했던 OnCantMove 차례입니다.
protected override void OnCantMove<T>(T component)
{
    // 인수로 받은 component를 Wall로 캐스팅
    Wall hitWall = component as Wall;
    // DamageWall 메소드로 데미지를 줌
    hitWall.DamageWall(wallDamage);
    // animator의 상태를 변경
    animator.SetTrigger("playerChop");
}
cs

다음은 레벨을 재로딩하는 Restart() 메소드입니다. 이것을 사용하기 위해서 먼저 네임 스페이스 선언을 추가해야 합니다.
using UnityEngine.SceneManagement;
...
private void Restart()
{
    SceneManager.LoadScene(0);
}
cs


이제 플레이어가 공격받았을때 food point를 잃어버리는 LoseFood()차례입니다.
public void LoseFood(int loss)
{
    // 애니메이터 상태 변경
    animator.SetTrigger("playerHit");
    food -= loss; // 음식 포인트 차감
    CheckIfGameOver();
}
cs

다음은 Soda, Food, Exit에 도달했을 때 벌어지는 일을 구현하기 위해 유니티 내부 API인 OnTriggerEnter2D를 작성합니다.

private void OnTriggerEnter2D(Collider2D other)
{
    // 감지한 것이 Exit이면 다음판 시작
    if (other.tag == "Exit")
    {
        Invoke("Restart", restartLevelDelay);
        enabled = false;
    }
    // Food이면 포인트 추가하고 사라지게 함
    else if (other.tag == "Food")
    {
        food += pointsPerFood;
        other.gameObject.SetActive(false);
    }
    // Soda도 포인트 추가, 사라지게 함
    else if (other.tag == "Soda")
    {
        food += pointsPerSoda;
        other.gameObject.SetActive(false);
    }
}
cs

나중에 추가할 내용이 있겠지만 일단은 여기서 멈춥니다. 스크립트를 저장하고 유니티로 돌아갑니다.

Prefabs 폴더에서 Player를 선택하고 Player스크립트를 컴포넌트로 추가합니다.


그리고 스크립트가 추가되면 Blocking Layer 프로퍼티를 BlockingLayer로 지정합니다.


댓글 없음:

댓글 쓰기