기록 보관소

[Unity/유니티] 기초-3D 쿼터뷰 액션 게임: 드랍 무기 입수와 교체[B41] 본문

유니티 프로젝트/3D 쿼터뷰 액션게임

[Unity/유니티] 기초-3D 쿼터뷰 액션 게임: 드랍 무기 입수와 교체[B41]

JongHoon 2022. 3. 21. 00:07

개요

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

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

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


3D 쿼터뷰 액션 게임: 드랍 무기 입수와 교체[B41]

1. 오브젝트 감지

//Player 스크립트 파일

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

public class Player : MonoBehaviour {
    public float speed;

    float hAxis;
    float vAxis;
    bool wDown;
    bool jDown;

    bool isJump;
	bool isDodge;

    Vector3 moveVec;
	Vector3 dodgeVec;

    Animator anim;
    Rigidbody rigid;

	GameObject nearObject;

    void Awake() {
        rigid = GetComponent<Rigidbody>();
        anim = GetComponentInChildren<Animator>();  //Player 자식 오브젝트에 있으므로
    }

    void Update() {
        GetInput();
        Move();
        Turn();
        Jump();
		Dodge();
    }

    void GetInput() {
        hAxis = Input.GetAxisRaw("Horizontal"); //좌우 방향키
        vAxis = Input.GetAxisRaw("Vertical");   //상하 방향키
        wDown = Input.GetButton("Walk");    //shift 키
		jDown = Input.GetButtonDown("Jump"); //스페이스바
    }

    void Move() {
        moveVec = new Vector3(hAxis, 0, vAxis).normalized;  //normalized : 방향 값이 1로 보정된 벡터

		if (isDodge)	//회피 중일때는
			moveVec = dodgeVec;	//회피하는 중인 방향으로 유지

        transform.position += moveVec * speed * (wDown ? 0.3f : 1f) * Time.deltaTime;
		
        anim.SetBool("isRun", (moveVec != Vector3.zero));   //이동을 멈추면
        anim.SetBool("isWalk", wDown);
    }

    void Turn() {
        transform.LookAt(transform.position + moveVec); //나아갈 방향 보기
    }

    void Jump() {
        if (jDown && (moveVec == Vector3.zero) && !isJump && !isDodge) {	//움직이지 않고 점프
            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.4f);
		}
	}

	void DodgeOut() {
		speed *= 0.5f;
		isDodge = false;
	}

	void OnCollisionEnter(Collision collision) {
		if (collision.gameObject.tag == "Floor") {
			anim.SetBool("isJump", false);
			isJump = false;
		}
	}

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

		Debug.Log(nearObject.name);
	}

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

테스트를 위해 Weapon들을 배치해두고
실행해서 다가가니 무기 이름이 뜬다


2. 무기 입수

Interation Input 추가

//Player 스크립트 파일

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 wDown;
    bool jDown;
	bool iDown;

    bool isJump;
	bool isDodge;

    Vector3 moveVec;
	Vector3 dodgeVec;

    Animator anim;
    Rigidbody rigid;

	GameObject nearObject;

    void Awake() {
        rigid = GetComponent<Rigidbody>();
        anim = GetComponentInChildren<Animator>();  //Player 자식 오브젝트에 있으므로
    }

    void Update() {
        GetInput();
        Move();
        Turn();
        Jump();
		Dodge();
		Interation();
    }

    void GetInput() {
        hAxis = Input.GetAxisRaw("Horizontal"); //좌우 방향키
        vAxis = Input.GetAxisRaw("Vertical");   //상하 방향키
        wDown = Input.GetButton("Walk");    //shift 키
		jDown = Input.GetButtonDown("Jump"); //스페이스바
		iDown = Input.GetButtonDown("Interation");	//E키
    }

    void Move() {
        moveVec = new Vector3(hAxis, 0, vAxis).normalized;  //normalized : 방향 값이 1로 보정된 벡터

		if (isDodge)	//회피 중일때는
			moveVec = dodgeVec;	//회피하는 중인 방향으로 유지

        transform.position += moveVec * speed * (wDown ? 0.3f : 1f) * Time.deltaTime;
		
        anim.SetBool("isRun", (moveVec != Vector3.zero));   //이동을 멈추면
        anim.SetBool("isWalk", wDown);
    }

    void Turn() {
        transform.LookAt(transform.position + moveVec); //나아갈 방향 보기
    }

    void Jump() {
        if (jDown && (moveVec == Vector3.zero) && !isJump && !isDodge) {	//움직이지 않고 점프
            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.4f);
		}
	}

	void DodgeOut() {
		speed *= 0.5f;
		isDodge = 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") {
			anim.SetBool("isJump", false);
			isJump = false;
		}
	}

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

		Debug.Log(nearObject.name);
	}

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

Has Weapons에 값을 넣어주자
실행 후 아이템에 다가가서
E키를 누르니 망치가 사라졌다
다른 무기들도 마찬가지로 E키를 누르니 사라졌다


3. 무기 장착

무기 장착 위치를 정해줄 Cylinder 생성
위치를 정하고, Collider는 삭제하고, Mesh Renderer를 체크 해제한다.
Weapon Point 아래에 무기 프리펩들(에셋에서 받은 프리펩)을 넣어서 위치 조정을 해준다.
추가한 무기들은 모두 비활성화 한 후, Player의 Weapon 배열에 게임 오브젝트로 넣어준다


4. 무기 교체

번호 1, 2, 3으로 무기 교체를 하기 위해 Input Manager에 추가
Swap 애니메이션 추가 및 설정

  • Trigger형 매개변수 doSwap을 추가하고, Transition을 설정해준다. Swap -> Exit으로 갈때는 Transition Duration만 0.1로 맞춰주면 끝.
//Player 스크립트 파일

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 wDown;
    bool jDown;
	bool iDown;
	bool sDown1;	//망치
	bool sDown2;	//권총
	bool sDown3;	//기관총

    bool isJump;
	bool isDodge;
	bool isSwap;

    Vector3 moveVec;
	Vector3 dodgeVec;

    Animator anim;
    Rigidbody rigid;

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

    void Awake() {
        rigid = GetComponent<Rigidbody>();
        anim = GetComponentInChildren<Animator>();  //Player 자식 오브젝트에 있으므로
    }

    void Update() {
        GetInput();
        Move();
        Turn();
        Jump();
		Dodge();
		Swap();
		Interation();
    }

    void GetInput() {
        hAxis = Input.GetAxisRaw("Horizontal"); //좌우 방향키
        vAxis = Input.GetAxisRaw("Vertical");   //상하 방향키
        wDown = Input.GetButton("Walk");    //shift 키
		jDown = Input.GetButtonDown("Jump"); //스페이스바
		iDown = Input.GetButtonDown("Interation");  //E키
		sDown1 = Input.GetButton("Swap1");	//번호 1번 키
		sDown2 = Input.GetButton("Swap2");	//번호 2번 키
		sDown3 = Input.GetButton("Swap3");	//번호 3번 키
	}

    void Move() {
        moveVec = new Vector3(hAxis, 0, vAxis).normalized;  //normalized : 방향 값이 1로 보정된 벡터

		if (isDodge)	//회피 중일때는
			moveVec = dodgeVec; //회피하는 중인 방향으로 유지

		if (isSwap)	//무기 교체 중일때는
			moveVec = Vector3.zero;	//멈추기

        transform.position += moveVec * speed * (wDown ? 0.3f : 1f) * Time.deltaTime;
		
        anim.SetBool("isRun", (moveVec != Vector3.zero));   //이동을 멈추면
        anim.SetBool("isWalk", wDown);
    }

    void Turn() {
        transform.LookAt(transform.position + moveVec); //나아갈 방향 보기
    }

    void Jump() {
        if (jDown && (moveVec == Vector3.zero) && !isJump && !isDodge && !isSwap) {	//움직이지 않고 점프
            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 && !isSwap) {    //이동하면서 점프
			dodgeVec = moveVec;
			speed *= 2;
			anim.SetTrigger("doDodge");
			isDodge = true;

			Invoke("DodgeOut", 0.4f);
		}
	}

	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;

		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") {
			anim.SetBool("isJump", false);
			isJump = false;
		}
	}

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

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

아이템이 없을때는 무기를 꺼낼 수 없다
무기 교체 애니메이션도 잘 나온다
문제없이 자유롭게 무기를 변경 할 수 있다