ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 슈팅게임 제작(3)
    실습/슈팅 2024. 3. 13. 02:19

    이번에는 플레이어가 발사하는 총알에 대해서 다뤄보겠다

    플레이어가 발사할 총알에 쓰일 이미지를 불러온뒤 Rigidbody 2D, Box Collider 컴포넌트를 넣어준다

    발사를 하면 일직선으로 쭉 날아갈 예정이기에 Rigidbody의 Gravity Scale은 0으로 설정해준다

     

    Prefabs라는 폴더를 만들어준뒤 두 총알을 모두 프리팹으로 만들어 넣어준다

     

    이렇게 프리팹까지 만들었다면 이번엔 총알을 무한으로 생성할 수 없기에

    특정 위치를 넘어가는 순간 총알을 자동으로 삭세해주는 시스템을 만들어보자

     

     

    닷지 게임 제작

    우선 가볍게 스테이지부터 만들어준다. 여기서 주의할건 중심이 되는 Plane은 가급적 위치를 (0,0,0)으로 잡아주자 Player가 될 Capsule 모양 오브젝트. 색을 입히고 싶다면 Material을 만들어준뒤 적용시

    sangeun00.tistory.com

    이 게임 같은 경우는 총알의 위치가 아닌, 생성되고 일정 시간이 흐른다면 자동으로 삭제해주는 방식을 사용했다

    하지만 이번에는 시간이 아닌 Box Collider에 Trigger 설정을 하여 충돌판정으로 삭제해보겠다

     

    우선 플레이어 이동반경보다 좀 더 넓은 BulletBorder라는 영역을 Box Collider로 만들어준다

    충돌판정을 위해 Is Trigger 선택후 Gravity Scale은 0으로 설정한다

    충돌판정을 위해 전용태그를 만들어준뒤 BulletBoder에도 전부 태그를 입혀주자

     

    마치 플레이어가 "Wall"태그가 입혀진 Trigger Box Collider와 부딫히면 더이상 움직이지 않듯이

    이번엔 총알이 "BulletBorder" 태그가 입혀진 콜라이더와 부딫히면 아예 삭제해보도록 하겠다

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class BulletControl : MonoBehaviour
    {
        private void OnTriggerEnter2D(Collider2D other)
        {
            if(other.gameObject.tag == "BulletBorder")
            {
                Destroy(gameObject);
            }
        }
    }

    총알을 사라지게 할 스크립트이기 때문에 BulletA,B 안에 들어갈 BulletControl 스크립트

    스크립트는 너무 간단하고 아까 했던 스크립트와 비슷하니 설명은 생략하겠다

     

    스크립트를 BulletA,B 프리팹에 넣어준뒤 게임을 실행해보면

     

    Box Collider와 닿는 순간 삭제되는것을 볼 수 있다

     

    이제 버튼을 누르면 총알이 발사되는것을 구현해보자. 당연히 발사는 PlayerControl에서 수정한다

    void Update()
        {
            Move();
        }
        void Move()
        {
            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);
    
            if (Input.GetButtonDown("Horizontal") ||
                Input.GetButtonUp("Horizontal"))
            {
                anim.SetInteger("Input", (int)x);
            }
        }

    슬슬 추가되는 코드들이 많아지므로 이동구현은 함수를 따로 만들어 빼주도록 하겠다. (캡슐화)

     

    public class PlayerControl : MonoBehaviour
    {
        public float speed;
        public bool TopTouch;
        public bool BottomTouch;
        public bool LeftTouch;
        public bool RightTouch;
    
        public GameObject bulletA;
        public GameObject bulletB;
    }
        ....
        
        
    void Update()
        {
            Move();
            Fire();
        }
        
        
        ....
    void Fire()
        {
            GameObject bullet = Instantiate(bulletA, transform.position, transform.rotation);
            Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
            rb.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
        }

    전역변수에 아까 만든 A,B타입 총알 게임오브젝트를 추가해준뒤

    Update 메서드안에 Fire이라는 함수도 하나 캡슐화 해준뒤 추가해주자

            GameObject bullet = Instantiate(bulletA, transform.position, transform.rotation);

     

            bullet이라는 이름의 변수는 bullatA를 플레이어의 위치, 회전과 똑같은 곳에서 생성하는 변수이다

     

            Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();

     

            총알이동을 위해 Addforce를 사용해야하니 Rigidbody2D의 컴포넌트를 가져오는데

            여기서 정말 중요한건 bullet.GetComponent라는 것이다

            평소대로 그냥 GetComponent를 써버리면 스크립트의 주인인 Player에게 적용이 되버리고 만다


            rb.AddForce(Vector2.up * 10, ForceMode2D.Impulse);

     

            bullet에 적용된 컴포넌트 rb를 이용하여 윗방향으로 10만큼 힘을준다

            그리고 약간 생소한 ForceMode2D로는 질량을 사용하여 rigidbody2D에 즉각적인 힘 충격을 추가한다

            폭발과 충돌로 인한 힘과 같이 즉시 발생하는 힘을 적용하는데 유용하다고 한다

    선택할 수 있는 옵션은 위처럼 2가지이다

     

    한번 ForceMode2D 옵션을 지우고 실행하면 총알이 굉장히 느린속도로 움직이는것을 볼 수 있다

    사실 이럴바엔 처음부터 속도를 크게 잡아주고 실행하면 될텐데 굳이 이럴필요가 있을까싶다

    그리고 총알과 총알끼리의 충돌허용을 꺼주자

    그럼 위 그림처럼 일직선으로 총알이 쭉 발사되는것을 확인할 수 있다

     

    이번엔 마우스 좌측버튼을 누를때마다 일정 시간마다 총알이 발사되게 만들어보자

    public class PlayerControl : MonoBehaviour
    {
        public float speed;
        public bool TopTouch;
        public bool BottomTouch;
        public bool LeftTouch;
        public bool RightTouch;
        
        public float reloadtime;
        public float maxtime;
        
        
        ....
    
    void Fire()
        {
            if (!Input.GetButton("Fire1"))
                return;
            if (reloadtime < maxtime)
                return;
    
            GameObject bullet = Instantiate(bulletA, transform.position, transform.rotation);
            Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
            rb.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
            reloadtime = 0;
        }
        void Reload()
        {
            reloadtime += Time.deltaTime;
        }

            if (!Input.GetButton("Fire1"))

    여기서 처음알게 된건데 GetButton안에 Fire1이라고 써도 좌클릭과 같은 효과가 난다

    물론 GetMouseButton(0)도 가능하다.

     

    그 이외는 어려운게 없다. Reload 함수로 reloadtime에 프레임마다 더해주고,

    그게 maxtime을 넘을때만 Fire 메서드가 움직이게 조건문을 걸어준다

     

    그리고 fire메서드가 한번 돌고나면 무조건 reloadtime은 0으로 초기화해준다

    그리고 Inspector창에서 위에 선언해주었던 변수 2개중 maxtime만 0.3으로 초기화해준다

    물론 처음 선언과 동시에 초기화를 해주어도 된다

     

     

    이제 발사에 관련된것은 거의 다 끝이 보인다. 마지막으로 현재 power에 따라 발사되는 총알의 타입만 바꿔주면 된다

     

    int power = 0;
    
    
    ....
    
    
    
    void Fire()
        {
            if (!Input.GetMouseButton(0))
                return;
            if (reloadtime < maxtime)
                return;
    
            switch (power)
            {
                case 1:
                    GameObject bullet = Instantiate(bulletA, transform.position, transform.rotation);
                    Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
                    rb.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                    break;
                case 2:
                    GameObject bulletL = Instantiate(bulletA, transform.position + Vector3.left*0.1f, transform.rotation);
                    GameObject bulletR = Instantiate(bulletA, transform.position + Vector3.right*0.1f, transform.rotation);
                    Rigidbody2D rbR = bulletR.GetComponent<Rigidbody2D>();
                    Rigidbody2D rbL = bulletL.GetComponent<Rigidbody2D>();
                    rbR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                    rbL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                    break;
                case 3:
                    GameObject bulletLL = Instantiate(bulletA, transform.position + Vector3.left * 0.1f, transform.rotation);
                    GameObject bulletCC = Instantiate(bulletB, transform.position, transform.rotation);
                    GameObject bulletRR = Instantiate(bulletA, transform.position + Vector3.right * 0.1f, transform.rotation);
    
                    Rigidbody2D rbRR = bulletRR.GetComponent<Rigidbody2D>();
                    Rigidbody2D rbCC = bulletCC.GetComponent<Rigidbody2D>();
                    Rigidbody2D rbLL = bulletLL.GetComponent<Rigidbody2D>();                
                    rbRR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                    rbCC.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                    rbLL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                    break;
            }

     

    int타입 변수 power를 선언해준뒤 fire메서드에서 스위치를 이용해 나갈 총알의 타입을 변경해줄 예정이다

     

    Case1. 즉 power가 1인 경우

    전에 짜둔것과 똑같이 A타입 총알을 한발 발사한다

     

    case가 2일경우

    이 과정을 동시에 2번 실행한다. 다만 총알이 겹칠순 없으니 transform.position에 Vector3.left/right를 더해준다

    AddForce로 힘을 더해주는것도 각각이니 컴포넌트 가져오는것도 각각 이름을 달리하여 작성해준다

     

    case가 3일경우

    이전과 똑같다. 다만 가운데 bulletB 타입이 하나 추가됐을뿐

    위 그림처럼 총알이 더 자연스럽고 이쁘게 생성되어 발사되는것을 원한다면 생성 순서를 변경해주면 된다

     

                    GameObject bulletLL = Instantiate(bulletA, transform.position + Vector3.left * 0.1f, transform.rotation);
                    GameObject bulletCC = Instantiate(bulletB, transform.position, transform.rotation);
                    GameObject bulletRR = Instantiate(bulletA, transform.position + Vector3.right * 0.1f, transform.rotation);

     

    =>           GameObject bulletLL = Instantiate(bulletA, transform.position + Vector3.left * 0.1f, transform.rotation);
                   GameObject bulletRR = Instantiate(bulletA, transform.position + Vector3.right * 0.1f, transform.rotation);

                   GameObject bulletCC = Instantiate(bulletB, transform.position, transform.rotation);

     

     

    Inspector창에서 power값을 변경할때마다 발사되는 총알타입이 달라지는것을 확인할 수 있다

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

    슈팅게임 제작(2)  (0) 2024.03.09
    슈팅게임 제작(1)  (0) 2024.03.08
Designed by Tistory.