유니티 프로젝트/2D 종스크롤 슈팅

[Unity/유니티] 기초-2D 종스크롤 슈팅: 플레이어 이동 구현하기[B27]

JongHoon 2022. 2. 26. 23:46

개요

유니티 입문과 독학을 위해서 아래 링크의 골드메탈님의 영상들을 보며 진행 상황 사진 또는 캡처를 올리고 배웠던 점을 요약해서 적는다.

현재는 영상들을 보고 따라하고 배우는 것에 집중할 것이며, 영상을 모두 보고 따라한 후에는 개인 프로젝트를 설계하고 직접 만드는 것이 목표다.

https://youtube.com/playlist?list=PLO-mt5Iu5TeYI4dbYwWP8JqZMC9iuUIW2 

 

유니티 강좌 기초 채널 Basic

유니티 개발을 처음 시작하시는 입문자 분들을 위한 기초 채널. [ 프로젝트 ] B00 ~ B12 (BE1) : 유니티 필수 기초 B13 ~ B19 (BE2) : 2D 플랫포머 B20 ~ B26 (BE3) : 2D 탑다운 대화형 RPG B27 ~ B37 (BE4) : 2D 종스크롤

www.youtube.com


2D 종스크롤 슈팅: 플레이어 이동 구현하기[B27]

1. 준비하기

새로운 프로젝트 Unity BE4 생성
사용할 에셋
내 에셋에 추가하기를 누르고 유니티 에디터에서 열기를 누르니 Package Manager에 추가되었다
다운로드 후 사용할 스프라이트와 이미지만 Import 한다
폴더를 만들어서 정리해뒀다

  • 영상 설명에 첨부된 에셋 스토어 링크를 통해서 에셋을 다운로드 받았다.
  • 참고로 이번 프로젝트부터는 최신 버전의 유니티를 활용할까 한다. 특별한 이유는 없고 앞으로 유니티 개인 프로젝트나 동아리를 통해서 팀 프로젝트를 진행할때는 아무래도 최신 버전의 유니티를 사용하면서 익숙해지는 것이 좋을 것같다는 생각이 들어서다.

사용할 Player 스프라이트
Sprite Editor를 통해서 잘라준다
잘 잘렸다. 옆의 Apply 버튼을 눌려서 적용시킨다.

  • Sprite Mode를 Multiple로, Pixels Per Unit을 24로, Filter Mode를 Point(no filter)로, Compression을 None으로 설정한다. 이후 Sprite Editor를 통해서 Grid By Cell Size Type으로 Pixel Size의 X, Y 값을 24로 하고 Padding을 각각 1씩 주며 Slice를 눌러 잘라준다.

Player 스프라이트 하나를 만들고 Scripts 폴더도 만든다
Scripts 폴더에 Player 스크립트를 만들어서 Player에 넣어준다


2. 플레이어 이동

//Player 스크립트 파일

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

public class Player : MonoBehaviour {
    public float speed;

    void Update() {
        float h = Input.GetAxisRaw("Horizontal");
        float v = Input.GetAxisRaw("Vertical");

        Vector3 curPos = transform.position;
        Vector3 nextPos = new Vector3(h, v, 0) * speed * Time.deltaTime;

        transform.position = curPos + nextPos;
    }
}

Speed 값 설정
해상도 추가 및 적용
실행하니 잘 움직인다. 다만 화면 밖으로 나갈수 있다

  • 물리적인 이동이 아닌 transform 이동에는 Time.DeltaTime을 곱해줘야한다. 이유는 지난 입문 프로젝트 글을 보면될 것 같다.

3. 경계 설정

 

Player에 Box Collider 2D 컴포넌트를 추가하고, Size를 적당히 설정해준다(정확한 피격 범위는 나중에 설정).
경계로 사용할 Empty 생성
아래에 Empty 4개 생성
각 Empty에 Box Collider 2D 컴포넌트 추가
적절히 위치를 설정해준다
모두 설정한 모습
Player에 Rigidbody 2D 추가
Border의 네가지 경계도 모두 Rigidbody 2D를 추가한다.
준비가 끝났으니 테스트를 위해 Rigidbody 변경
더이상 화면 밖으로 내려가지 않는다.

  • Player의 Rigidbody 2D의 Body Type은 Kinematic으로 설정한다. 기본 설정인 Dynamic을 하게되면 Dynamic끼리 부딪혔을때 밀리거나 떨리는 등의 물리 효과를 받게 된다. Kinematic을 설정하면 받지 않게 되어 작성한 코드 로직에 따라서만 작동하게된다. 그렇기에 이번 파트에서는 따로 경계선과 관련된 코드를 작성하지 않았으므로, 경계선이 잘 작동하는지 테스트하기위해서는 잠시 Dynamic으로 바꾸고 진행해야한다.
    • 참고로 위 캡처에서 계속 아래 화살표를 누르게되면 Player가 계속 내려가려고 시도하면서 튕기고 내려가고를 반복해 떨림현상이 발생한다. 즉, transform 이동과 물리 충돌 때문이다.
  • Border 4 경계의 Rigidbody 2D의 Body Type은 Static으로 설정한다. Static은 고정되어 움직이지 않는다.

4. 경계 충돌 로직

//Player 스크립트 파일

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

public class Player : MonoBehaviour {
    public float speed;
    public bool isTouchTop;
    public bool isTouchBottom;
    public bool isTouchLeft;
    public bool isTouchRight;

    void Update() {
        float h = Input.GetAxisRaw("Horizontal");
        if ((isTouchRight && h == 1) || (isTouchLeft && h == -1))
            h = 0;

        float v = Input.GetAxisRaw("Vertical");
        if ((isTouchTop && v == 1) || (isTouchBottom && v == -1))
            v = 0;

        Vector3 curPos = transform.position;
        Vector3 nextPos = new Vector3(h, v, 0) * speed * Time.deltaTime;

        transform.position = curPos + nextPos;
    }

    void OnTriggerEnter2D(Collider2D collision) {
        if (collision.gameObject.tag == "Border") {
            switch(collision.gameObject.name) {
                case "Top":
                    isTouchTop = true;
                    break;
                case "Bottom":
                    isTouchBottom = true;
                    break;
                case "Left":
                    isTouchLeft = true;
                    break;
                case "Right":
                    isTouchRight = true;
                    break;
            }
        }
    }

    void OnTriggerExit2D(Collider2D collision) {
        if (collision.gameObject.tag == "Border") {
            switch (collision.gameObject.name) {
                case "Top":
                    isTouchTop = false;
                    break;
                case "Bottom":
                    isTouchBottom = false;
                    break;
                case "Left":
                    isTouchLeft = false;
                    break;
                case "Right":
                    isTouchRight = false;
                    break;
            }
        }
    }
}

Border 4방향 경계 모두 Tag를 Border로 설정하고, Box Collider 2D에 Is Trigger를 체크해둔다
Player의 Rigidbody Kinematic으로 변경
떨림 현상도 없이 이동을 멈췄다


5. 플레이어 애니메이션

Center 애니메이션 추가
Right 애니메이션 추가
Left 애니메이션 추가
정리하고 Transition을 연결해준 Animator창. int형 매개변수 Input도 생성해준다.
Transition 설정

  • 매개변수 Input은 입력받은 키 값과 동일하게 1, 0, -1로 나온다. 즉, 왼쪽을 누르면 -1, 오른쪽을 누르면 1, 안누르면 0이 된다. 자세한 Transition 설정은 아래와 같다.
    • Center -> Right : Input Equals 1
    • Right -> Center : Input Equals 0
    • Center -> Left : Input Equals -1
    • Left -> Center : Input Equals 0
    • Right -> Left : Input Equals -1
    • Left -> Right : Input Equals 1
//Player 스크립트 파일

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

public class Player : MonoBehaviour {
    Animator anim;

    public float speed;
    public bool isTouchTop;
    public bool isTouchBottom;
    public bool isTouchLeft;
    public bool isTouchRight;

    void Awake() {
        anim = GetComponent<Animator>();
    }

    void Update() {
        float h = Input.GetAxisRaw("Horizontal");
        if ((isTouchRight && h == 1) || (isTouchLeft && h == -1))
            h = 0;

        float v = Input.GetAxisRaw("Vertical");
        if ((isTouchTop && v == 1) || (isTouchBottom && v == -1))
            v = 0;

        Vector3 curPos = transform.position;
        Vector3 nextPos = new Vector3(h, v, 0) * speed * Time.deltaTime;

        transform.position = curPos + nextPos;

        if (Input.GetButtonDown("Horizontal") || Input.GetButtonUp("Horizontal")) {
            anim.SetInteger("Input", (int)h);
        }
    }

    void OnTriggerEnter2D(Collider2D collision) {
        if (collision.gameObject.tag == "Border") {
            switch(collision.gameObject.name) {
                case "Top":
                    isTouchTop = true;
                    break;
                case "Bottom":
                    isTouchBottom = true;
                    break;
                case "Left":
                    isTouchLeft = true;
                    break;
                case "Right":
                    isTouchRight = true;
                    break;
            }
        }
    }

    void OnTriggerExit2D(Collider2D collision) {
        if (collision.gameObject.tag == "Border") {
            switch (collision.gameObject.name) {
                case "Top":
                    isTouchTop = false;
                    break;
                case "Bottom":
                    isTouchBottom = false;
                    break;
                case "Left":
                    isTouchLeft = false;
                    break;
                case "Right":
                    isTouchRight = false;
                    break;
            }
        }
    }
}

게임을 실행하니 Center 애니메이션이 작동한다
왼쪽 키를 누르니 Left 애니메이션이 작동하고
오른쪽 키를 누르니 Right 애니메이션이 작동한다

 

추가로 배경 스프라이트를 추가하였다