새소식

🎮 Game Dev (게임개발)/PC (데스크탑, 노트북, 터치패널)

[3D 액션게임] 04.무기 획득과 변경

  • -

🔔 유튜브 크리에이터 골든메탈님의 유니티강의 3D 쿼터뷰 액션게임 [BE5] 를 보고 공부하여 작성한 게시글입니다! 🔔

 

 

플레이어 스크립트 코드 전체 보기

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    public float speed;
    public GameObject[] weapons;
    public bool[] hasWeapons;

    float hAxis;
    float vAxis;
    bool rDown;
    bool jDown;

    bool isJump;
    bool isDodge;
    bool isSwap;

    bool iDown;
    bool sDown1;
    bool sDown2;
    bool sDown3;

    Vector3 moveVec;
    Vector3 dodgeVec;
    Rigidbody rigid;

    Animator anim;

    GameObject nearObject;
    GameObject equipWeapon;
    int equipWeaponIndex = -1;

    // Start is called before the first frame update
    void Start()
    {
        
    }

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

    // Update is called once per frame
    void Update()
    {
        GetInput();
        Move();
        Turn();
        Jump();
        Dodge();
        Interation();
        Swap();
    }


    void GetInput()
    {
        // 키보드입력에 따라 0 ~ 1로 변환 left right up down
        hAxis = Input.GetAxisRaw("Horizontal");
        vAxis = Input.GetAxisRaw("Vertical");
        rDown = Input.GetButton("Run");
        jDown = Input.GetButtonDown("Jump");
        iDown = Input.GetButtonDown("Interation");
        sDown1 = Input.GetButtonDown("Swap1");
        sDown2 = Input.GetButtonDown("Swap2");
        sDown3 = Input.GetButtonDown("Swap3");
    }

    void Move()
    {
        // x y z
        moveVec = new Vector3(hAxis, 0, vAxis).normalized;

        // 회피 시 업데이트 안되게
        if (isDodge)
            moveVec = dodgeVec;
        
        // 스왑 시 못움직이게
        if (isSwap)
            moveVec = Vector3.zero;

        // transform
        transform.position += moveVec * (rDown ? 1.3f : 1f) * speed * Time.deltaTime;

        // animator
        anim.SetBool("isWalk", moveVec != Vector3.zero);
        anim.SetBool("isRun", rDown);
    }

    void Turn()
    {
        // Rotation
        transform.LookAt(transform.position + moveVec);
    }

    void Jump()
    {
        if(jDown && moveVec == Vector3.zero && !isJump && !isDodge) {
            // 물리엔진에 힘을 준다. 여기선 즉발적인 Impulse
            rigid.AddForce(Vector3.up * 15, ForceMode.Impulse);
            anim.SetBool("isJump", true);
            anim.SetTrigger("doJump");

            isJump = true;
        }
    }

    void Dodge()
    {
        // 이동하면서 점프할때, 
        if (jDown && moveVec != Vector3.zero && !isJump && !isDodge)
        {
            dodgeVec = moveVec;
            speed *= 2;
            anim.SetTrigger("doDodge");
            isDodge = true;

            Invoke("DodgeOut", 0.5f); // 시간지연 라이브러리 기능
        }
    }

    void DodgeOut()
    {
        speed *= 0.5f;
        isDodge = false;
    }
    
    void Swap()
    {
        if (sDown1 && (!hasWeapons[0] || equipWeaponIndex == 0))
            return;
        if (sDown2 && (!hasWeapons[1] || equipWeaponIndex == 1))
            return;
        if (sDown3 && (!hasWeapons[2] || equipWeaponIndex == 2))
            return;

        int weaponIndex = -1;
        if (sDown1) weaponIndex = 0;
        if (sDown2) weaponIndex = 1;
        if (sDown3) weaponIndex = 2;

        // 1, 2 ,3 버튼 누를때
        if((sDown1 || sDown2 || sDown3) && !isJump && !isDodge) {
            if(equipWeapon != null)
                equipWeapon.SetActive(false);

            equipWeaponIndex = weaponIndex;
            equipWeapon = weapons[weaponIndex];
            equipWeapon.SetActive(true);
            
            anim.SetTrigger("doSwap");
            

            // 스왑 중
            isSwap = true;
            Invoke("SwapOut", 0.4f);

        }
    }
    void SwapOut()
    {
        isSwap = false;
    }

    void Interation()
    {
        if(iDown && nearObject != null && !isJump && !isDodge) {
            if(nearObject.tag == "Weapon") {
                Item item = nearObject.GetComponent<Item>();
                int weaponIndex = item.value;
                hasWeapons[weaponIndex] = true;

                Destroy(nearObject);
            }
        }
    }

    // 충돌 시 이벤트 함수로 착지 구현
    void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.tag == "Floor"){
            isJump = false;
            anim.SetBool("isJump", false);
        }
    }

    private void OnTriggerStay(Collider other)
    {
        if (other.tag == "Weapon")
            nearObject = other.gameObject;
    }
    private void OnTriggerExit(Collider other)
    {
        if (other.tag == "Weapon")
            nearObject = null;
    }
}

 

🧷 1. 오브젝트 감지

-  무기 인식

/* Player Script , 기존 Script에서 해당하는 부분만을 표현했습니다. */

public class Player : MonoBehaviour
{	
    GameObject nearObject;


    private void OnTriggerStay(Collider other)
    {
        if (other.tag == "Weapon")
            nearObject = other.gameObject;
    }
    private void OnTriggerExit(Collider other)
    {
        if (other.tag == "Weapon")
            nearObject = null;
    }
    
}
  • 주위에 있는 Object를 인식하기 위한 GameObject 변수를 만듭니다.
  • OnTriggerStay 로, 근처 item collision 에 닿고 있을때 무기면, nearObject에 gameObject를 넣어줍니다.
  • OnTriggerExit 로 Item 근처에서 떨어질때는, null값으로 바꿔줍니다.

 

🧷 2. 무기 장착하기

- 무기 인벤토리에 넣기

  • 아이템이 근처에 있을시 획득 할 단축키를 Interation이름의 "e" key로 지정해주었습니다.

 

그 다음 플레이어의 스크립트로 돌아와

/* Player Script , 기존 Script에서 해당하는 부분만을 표현했습니다. */

public class Player : MonoBehaviour
{
    public bool[] hasWeapons;

	GameObject nearObject;

    
    bool iDown;
    
    void Update()
    {
    	Interation();
    }
    
    void GetInput()
    {
    	iDown = Input.GetButtonDown("Interation");
    }
    
    void Interation()
    {
        if(iDown && nearObject != null && !isJump && !isDodge) {
            if(nearObject.tag == "Weapon") {
                Item item = nearObject.GetComponent<Item>();
                int weaponIndex = item.value;
                hasWeapons[weaponIndex] = true;

                Destroy(nearObject);
            }
        }
    }   
}
  • iDown 변수를 통해 "e" 키와 연결시켜주었습니다.
  • 또한 Interation() 함수를 만들어 "e" 키를 누를시, nearObject가 Weapon일시, weaponIndex를 통해, bool 배열hasWeapons[]에 플레이어가 가지고 있는 무기로 넣어주었습니다.
  • 무기 습득시 그 무기는 필드에서 없어집니다.

 

 

- 캐릭터의 손에 무기 쥐어주기

  • 플레이어의 RightHand의 하위 오브젝트로 Cylinder을 만들어 Weapon Point로 지정하여 손의 위치에 쥐어줍니다.
  • 그 후, 각 무기들을 에셋에서 Weapon Point 자식 오브젝트에 위치시켜 , 무기들을 보면서 손에 잘 쥐어 질 수 있도록 위치를 변경시켜 주면 됩니다.

 

- Weapons 오브젝트 넣어주기

/* Player Script , 기존 Script에서 해당하는 부분만을 표현했습니다. */

public class Player : MonoBehaviour
{
	public GameObject[] weapons;

}

  • GameObject들을 담을 weapons 변수를 만든 후, 무기들을 끌어당겨 넣어주었습니다.

 

-  무기 장착 스트립트 작성

Input Manager에 무기를 장착할 키를 sDown1,sDown2,sDown3 이름으로 작동키는 숫자 1, 2 ,3 으로 지정해주었습니다.

 

/* Player Script , 기존 Script에서 해당하는 부분만을 표현했습니다. */

public class Player : MonoBehaviour
{
	GameObject equipWeapon;
    int equipWeaponIndex = -1;


    void GetInput()
    {
        sDown1 = Input.GetButtonDown("Swap1");
        sDown2 = Input.GetButtonDown("Swap2");
        sDown3 = Input.GetButtonDown("Swap3");
    }
    
    void Swap()
    {
    
        int weaponIndex = -1;
        if (sDown1) weaponIndex = 0;
        if (sDown2) weaponIndex = 1;
        if (sDown3) weaponIndex = 2;

        // 1, 2 ,3 버튼 누를때
        if((sDown1 || sDown2 || sDown3) && !isJump && !isDodge) {
            if(equipWeapon != null)
                equipWeapon.SetActive(false);

            equipWeaponIndex = weaponIndex;
            equipWeapon = weapons[weaponIndex];
            equipWeapon.SetActive(true);

        }
    }
    
}
  • 다음 조건을 지정하여, 1, 2, 3을 누를시 가지고 있는 장착하고있는 무기가 Active 되도록 해주었습니다.
  • 여기서 해머 = 1, 권총 = 1, 머신건 = 2 로 지정했습니다.

 

🧷 3. 무기 교체하기

-  무기 교체 애니메이션

  • 플레이어 에셋에서 Swap 애니메이션을 doSwap 트리거를 통해 연결해주었습니다.

 

-  무기 교체 스크립트 연결 및 제한사항

/* Player Script , 기존 Script에서 해당하는 부분만을 표현했습니다. */

public class Player : MonoBehaviour
{
	public GameObject[] weapons;
    
    bool isSwap;
    
    void Move()
    {
        // 스왑 시 못움직이게
        if (isSwap)
            moveVec = Vector3.zero;
    }
    
    void Swap()
    {
    	// 인벤토리에 무기가 없다면 실행 안되고, 똑같은 무기는 꺼낼 수 없습니다.
        if (sDown1 && (!hasWeapons[0] || equipWeaponIndex == 0))
            return;
        if (sDown2 && (!hasWeapons[1] || equipWeaponIndex == 1))
            return;
        if (sDown3 && (!hasWeapons[2] || equipWeaponIndex == 2))
            return;

        int weaponIndex = -1;
        if (sDown1) weaponIndex = 0;
        if (sDown2) weaponIndex = 1;
        if (sDown3) weaponIndex = 2;

        // 1, 2 ,3 버튼 누를때
        if((sDown1 || sDown2 || sDown3) && !isJump && !isDodge) {
            if(equipWeapon != null)
                equipWeapon.SetActive(false);

            equipWeaponIndex = weaponIndex;
            equipWeapon = weapons[weaponIndex];
            equipWeapon.SetActive(true);
            
            anim.SetTrigger("doSwap");
            

            // 스왑 중
            isSwap = true;
            Invoke("SwapOut", 0.4f);

        }
    }
    void SwapOut()
    {
        isSwap = false;
    }
}
anim.SetTrigger("doSwap")
  • 또한 스왑 중일때, 다른 움직이지 못하고 계속 스왑동작을 실행시키지 않게 Invoke를 이용해 쿨타임을 주었습니다.

 

if (sDown1 && (!hasWeapons[0] || equipWeaponIndex == 0)) return; if (sDown2 && (!hasWeapons[1] || equipWeaponIndex == 1)) return; if (sDown3 && (!hasWeapons[2] || equipWeaponIndex == 2)) return;​
  • 그리고, 똑같은 무기를 스왑하거나, 가지고있지도 않는 무기를 꺼낼 수 없게 조건을 달아 완성시켜 주었습니다.

 

 

 

출처: 골든메탈님 유튜브

https://www.youtube.com/watch?v=APS9OY_p6wo&list=PLO-mt5Iu5TeYkrBzWKuTCl6IUm_bA6BKy&index=4 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.