ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 슈팅게임 제작(1)
    실습/슈팅 2024. 3. 8. 01:42

    우선 게임을 만들기 전 화면 설정부터 해주자

    일반적으로 모바일 플랫폼에서 세로화면으로 가장 많이 쓰는건 1920x1080 Portrait 인것같다(내 생각)

    그게 아니라면 직접 만들어 화면의 비율을 임의로 조절한다음 사용할 수도 있다(Type은 꼭 Aspect Ratio)

    기본적인 플레이어로 사용할 Player 이미지를 선택하고 SpriteMode - Multiple로 선택한뒤 Sprite Editor로 잘라주자

    픽셀 사이즈는 적당하게, Padding은 무조건 축마다 1씩 남겨주자. 그렇지 않으면 밀려잘릴수 있다

    Apply 옆에 있는 tv모양 rgb를 누른다면 더 보기 쉽게 잘 잘렸는지 확인할 수 있다

    잘 잘린것을 확인

     

    Multiple sprite

    아직 잘리지 않고 한 이미지에 이어져있는 이미지를 프레임에 따라 하나씩 일정하게 잘라주자 1. 우선 이미지를 선택후 Sprite Mode에서 Multiple로 선택해준다 그리고 밑에 있는 Sprite Editor를 눌러 Spr

    sangeun00.tistory.com

    여기서 이미 한번 해본적이 있다

     

    이제 기본적으로 Player를 움직이는 스크립트를 PlayerControl이라는 이름으로 만들어보자

    using System.Collections;
    using System.Collections.Generic;
    using UnityEditor;
    using UnityEngine;
    
    public class PlayerControl : MonoBehaviour
    {
        float speed = 5f;
        void Update()
        {
            float x = Input.GetAxisRaw("Horizontal");
            float y = Input.GetAxisRaw("Vertical");
            Vector3 pos = transform.position;
            Vector3 nextpos = new Vector3(x, y, 0) * speed * Time.deltaTime;
            transform.position = pos + nextpos;
        }
    }

    이건 영상에서 제시해준 스크립트이다. 하지만 굳이 Vector3 타입 변수만 2개나 지정하고

    그걸 굳이 더해줘야할 필요가 있나 싶었다

            float x = Input.GetAxisRaw("Horizontal");
            float y = Input.GetAxisRaw("Vertical");
            transform.Translate(new Vector3(x, y, 0) * speed * Time.deltaTime);

    그냥 Translate로 이렇게 한줄에 해도 된다

            float x = Input.GetAxisRaw("Horizontal");
            float y = Input.GetAxisRaw("Vertical");
            Vector3 nextpos = new Vector3(x, y, 0) * speed * Time.deltaTime;
            transform.Translate(nextpos);

    아니면 nextpos라는 변수에 미리 값을 다 집어넣고 Translate에 넣어줘도 된다

     

    어느 방법이든 셋중 아무 스크립트나 Player에게 적용해주면 WASD 키나 방향키에 의해 이동하는것을 확인할 수 있다

     

    이제 화면밖으로 Player가 나가지 않게 모든면을 Box Collider로 막아주자

     

    하지만 Box Collider 하나 만들었다고 플레이어가 밖으로 나가지 않는것이 아니다

    우선 Player부터 Box Collider와 Rigidbody2D 컴포넌트를 입혀준다

     

    그리고 이제 Player와 충돌판정으로 쓸 Box Collider에 어떤 Body Type을 입히는지가 가장 중요하다

     

    Body Type은 총 3가지로, Dynamic, Kinematic, Static이 있다

     

    기본이 되는것들은 그냥 대충 두루뭉실하게 알고 있느니 이번 기회에 확실하게 짚고 넘어가자

     

    우선 계속해서 움직여야하고, Box Collider와 충돌시 막혀야하는 Player의 입장에서는 

    Kinematic은 중력과 힘의 영향을 받지 않으니 안되고,

    시뮬레이션 상태에서 전혀 움직이지 않도록 하는 정적인 Static에도 어울리지 않는다

    그러니 가장 적합한건 Dynamic에다 중력크기(Gravity Scale)을 0으로 잡는것이다

    충돌판정을 위한 사각 콜라이더들은 어떨까?

    사실 볼것도 없이 게임내내 절대 움직이지 않을 오브젝트이기에 Static이 더 볼것도 없이 적합하다

    (게다가 충돌은 오로지 Dynamic 바디 타입과 충돌한다)

     

    이제 확실하게 보이지 않는 박스 콜라이더에 막히는 모습을 볼수 있다

    하지만 한가지 아쉬운 점이라면 충돌판정이 일어났을때 비행기가 덜덜 떨리며 자연스럽지 않은 모습을 보인다는것

    이 부분을 스크립트 수정을 통해 충돌이 일어나는순간 뚝 멈추게 만들어보겠다

     

    우선 스크립트를 짜기전에 왜 이렇게 덜덜 떨리고, 어떻게하면 이걸 멈출수 있는지부터 알아보자

     

            Vector3 nextpos = new Vector3(x, y, 0) * speed * Time.deltaTime;

    이동 스크립트에 Time.deltaTime을 곱해주어 매 프레임마다 누른위치로 미세하게 이동하는 원리이다

    그렇기에 "충돌->막혔다가 한프레임 뒤 다시 이동->충돌->막혔다가 한프레임 뒤 다시 이동"

    이게 무한반복이 되는것이다. 그러니 우린 "충돌->해당 축의 속도를 0으로 설정"으로 변경해주면 된다

     

    우선 충돌판정을 스크립트에 적용하기 위해 "Wall"이라는 이름의 태그를 만들어주고

    4개의 충돌판정 벽에 "Wall" 태그를 달아준다

     

    그리고 이제 스크립트를 짜보자

    using System.Collections;
    using System.Collections.Generic;
    using UnityEditor;
    using UnityEngine;
    
    public class PlayerControl : MonoBehaviour
    {
        float speed = 5f;
        bool IsTouch = false;
        void Update()
        {
            float x = Input.GetAxisRaw("Horizontal");
            if ((IsTouch && x == 1) || (IsTouch && x == -1))
            {
                x = 0;
            }
            float y = Input.GetAxisRaw("Vertical");
            if ((IsTouch && y == 1) || (IsTouch || y == -1))
            {
                y = 0;
            }
            transform.Translate(new Vector3(x, y, 0) * speed * Time.deltaTime);
        }
    
        private void OnCollisionEnter2D(Collision2D collision)
        {
            if (collision.gameObject.tag == "Wall")
            {
                this.IsTouch = true;
            }
        }
        private void OnCollisionExit(Collision collision)
        {
            if (collision.gameObject.tag == "Wall")
            {
                this.IsTouch = false;
            }
        }
    }

     private void OnCollisionEnter2D(Collision2D collision)
        {
            if (collision.gameObject.tag == "Wall")
            {
                this.IsTouch = true;
            }
        }
        private void OnCollisionExit(Collision collision)
        {
            if (collision.gameObject.tag == "Wall")
            {
                this.IsTouch = false;
            }
        }

    Player가 콜라이더와 충돌판정이 일어났는데 그 콜라이더의 태그가 "Wall"이라면 IsTouch를 true로 만들어준다

    반대로 충돌판정이 끝나고 충돌판정이 끝난 콜라이더의 태그가 "Wall"이라면 isTouch를 false로 만들어준다

     

    void Update()
        {
            float x = Input.GetAxisRaw("Horizontal");
            if ((IsTouch && x == 1) || (IsTouch && x == -1))
            {
                x = 0;
            }
            float y = Input.GetAxisRaw("Vertical");
            if ((IsTouch && y == 1) || (IsTouch || y == -1))
            {
                y = 0;
            }
            transform.Translate(new Vector3(x, y, 0) * speed * Time.deltaTime);
        }

     

    다시 위로 넘어와 만약 x의 입력을 받았는데 IsTouch가 True인 상태에서 x의 값이 1이나 -1로 입력을 받고 있는 상태라면

    x를 0으로 만들어 x축으로는 움직일 수 없게 만든다. y축도 마찬가지

     

    하지만 이렇게하니 문제가 발생했다

     

     

    그냥 어느쪽이던간에 부딫히는 순간 Player가 어느쪽으로도 이동을 할수 없었던것

     

    그도 그럴게 코드를 다시보니 IsTouch가 true가 되는순간 x,y키 어느것을 누르던간에 전부 0이 되도록 짜두었다

    그럼 충돌상태에서 벗어나는순간 다시 값이 돌아와야하는데다,

    왼쪽에 부딫혔다면 오른쪽 x값을 눌러 벗어나야하고, 오른쪽에 부딫혔다면 왼쪽 x값을 눌러 벗어날수 있어야한다

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEditor;
    using UnityEngine;
    using static UnityEditor.PlayerSettings;
    
    public class PlayerControl : MonoBehaviour
    {
        float speed = 5f;
        public bool TopTouch;
        public bool BottomTouch;
        public bool LeftTouch;
        public bool RightTouch;
        void Update()
        {
            float x = Input.GetAxisRaw("Horizontal");
            if ((RightTouch && x == 1) || (LeftTouch && x == -1))
            {
                x = 0;
            }
            float y = Input.GetAxisRaw("Vertical");
            if ((TopTouch && y == 1) || (BottomTouch && y == -1))
            {
                y = 0;
            }
    
            transform.Translate(new Vector3(x, y, 0) * speed * Time.deltaTime);
        }
    
        void OnTriggerEnter2D(Collider2D collision)
        {
            if (collision.gameObject.tag == "Wall")
            {
                switch(collision.gameObject.name)
                {
                    case "Top":
                        TopTouch = true; 
                        break;
                    case "Bottom":
                        BottomTouch = true;
                        break;
                    case "Left":
                        LeftTouch = true;
                        break;
                    case "Right":
                        RightTouch = true;
                        break;
                }
            }
        }
        void OnTriggerExit2D(Collider2D collision)
        {
            if (collision.gameObject.tag == "Wall")
            {
                switch (collision.gameObject.name)
                {
                    case "Top":
                        TopTouch = false;
                        break;
                    case "Bottom":
                        BottomTouch = false;
                        break;
                    case "Left":
                        LeftTouch = false;
                        break;
                    case "Right":
                        RightTouch = false;
                        break;
                }
            }
        }
    }

    그래서 케이스를 아예 4개로 늘려버렸다

      public bool TopTouch;
        public bool BottomTouch;
        public bool LeftTouch;
        public bool RightTouch;

     

    void Update()
        {
            float x = Input.GetAxisRaw("Horizontal");

            x축 값을 입력받았는데
            if ((RightTouch && x == 1) || (LeftTouch && x == -1))

           만약 오른쪽끝에 닿았는데 더 오른쪽으로 가려하거나

           왼쪽끝에 닿았는데 더 왼쪽으로 가려한다면
                x = 0;

           x축의 값을 0으로 만든다

            float y = Input.GetAxisRaw("Vertical");
            if ((TopTouch && y == 1) || (BottomTouch && y == -1))
                y = 0;

     

            y축도 마찬가지

            transform.Translate(new Vector3(x, y, 0) * speed * Time.deltaTime);
        }

     

     void OnTriggerEnter2D(Collider2D collision)
        {

        만약 Player가 Trigger와 충돌했는데
            if (collision.gameObject.tag == "Wall")

           만약 충돌한 오브젝트의 태그가 "Wall"이라면
            {
                switch(collision.gameObject.name)

                오브젝트의 이름이
                {
                    case "Top":

                    Top이라면
                        TopTouch = true; 
                        break;

                    TopTouch 유무를 True로 한뒤 빠져나옴
                    case "Bottom":
                        BottomTouch = true;
                        break;
                    case "Left":
                        LeftTouch = true;
                        break;
                    case "Right":
                        RightTouch = true;
                        break;

                 나머지 3개의 경우의 수도 마찬가지
                }
            }
        }

    또 반대로 OnTriggerExit2D도 마찬가지이다. 떨어지는 순간 변수를 찾아 false로 만들어준다

    그럼 이제 우리가 원하는대로 결과가 나오는것을 확인할 수 있다

    '실습 > 슈팅' 카테고리의 다른 글

    슈팅게임 제작(3)  (2) 2024.03.13
    슈팅게임 제작(2)  (0) 2024.03.09
Designed by Tistory.