본문 바로가기
VR 팀프로젝트/[GroundZero] 제작 일지

GroundZero 제작일지 - 왼손 방패 잡기 구현(LeftHandShield)

by 잰쟁 2023. 11. 8.
728x90

 

▷LeftHand - 방패(Shield)잡기 구현

 

구현할 부분(왼손 방패)

R&D할 부분

 

 

구현할 것

- 왼 손을 쥐고 있으면 (LeftIndexTrigger를 누르는 동안) 방패 생성

- LeftIndexTrigger를 누르는 동안 방패 게이지(UI)가 줄어듦
  (MaxGauge : 100%)

- 왼 손을 펴면 방패 사라짐 & 방패 게이지 충전

 

 

 

구현 과정

 

(방식)

- 컨트롤러의 트리거 (LeftIndexTrigger)를 누르면 손 프리팹 변경

 

(목표)

==> 기본 왼손을 쥐면(LeftIndexTrigger를 누르면) 방패를 쥔 왼손으로 프리팹 바꾸기

==> 다시 손을 피면(LeftIndexTrigger를 떼면) 기본 왼손 프리팹으로 돌아오기


 

▶기본 왼손

- MainCamera 삭제 후 OVRCameraRig 붙이기

- OVRCameraRig ->TrackingSpace -> LeftHandAnchor에 빈오브젝트 'HandLeftParent' 추가

- 'HandLeftParent'에 다운 받은 손 에셋 중 맘에 드는 손을 골라 자식으로 붙이고 'HandLeft'(기본 왼손)로 이름 바꾸기 

 

왼손 전체적인 모습
다운받은 손 에셋에서 맘에드는 손을 HandLeftParent의 자식으로 가져오기
가져온 손에셋의 모습

 

 


▶방패든 왼손

 

- 기본 왼손을 복사 붙여넣기 하고 이름을 'HandLeft(Shield)'로 변경

- 다운받은 이펙트 에셋 중에 맘에드는 것을 골라 'HandLeft(Shield)의 자식으로 붙여주기(이름도 'Shield'로 변경)

 

 

 

- 자꾸 손이 펴지는 것을 방지

   --> 기존에 부착되어 있던 Animator 체크 해제

 

 

- 원작과 비슷하게 방패의 위치 및 회전율 조정하기

원작 방패 및 손 모양

 


▶방패 게이지 UI

 

- Canvas -> Text_TMPPro 생성하기

- 손(GameObject)옆에 붙어있을 것이므로 ==> Canvas -> Render Mode를 'World Space'로 변경!!

 

- Text_TMPPro 부분도 폰트, 글자 크기 등 알맞게 조정

 


 

1차 완성본

: 방패 및 방패게이지UI 보이기

: 손을 쥐면 초당 1%씩 게이지 감소, 다시 펴면 초당 1%씩 게이지 회복

 

 


 

▶ ▶ 수정 및 보완

 

(수정)

- 손을 쥘때만 방패게이지UI 보이기 -->  방패게이지 UI 상시 보이기

- 방패게이지 닳고 회복하는 속도 조정하기

 

(보완)

방패 역할 구현

- 총알이 방패에 닿으면 총알 없애기

- 닿은 총알 개수 당 방패게이지UI의 게이지 수치 -10%씩 닳기

 

 


 

▶ 방패게이지UI 상시 보이기

- 'LeftHandShield' 스크립트의 트리거를 누르고 뗄 때 넣었던 Action 제거하기

    (UI 활성, 비활성화 제어했던 것을 제거)

 

▶ 게이지 수치 속도 조정

- 기존에 'LeftHandShield' 부분의 게이지 시간을 조절하는 Time.deltaTime 부분에 speed 변수 곱해주기

 

 

▶ 총알 없애고 방패게이지 감소시키기

 

- 팀원이 만든 Enemy 프리팹 가져와서 배치

 

 

- 기존에 만든 Shield 프리팹에 총알과 Trigger체크를 할 'Shield' 스크립트 및 Collider 부착하기

 

-  총알에 닿으면 게이지 10%씩 닳게 하도록 기존에 작성했던 'LeftHandShield' 스크립트 수정하기

		private float timeSpeed = 4f;
        private float recoverSpeed = 7f;

        void Start()
        {
            this.shieldValue = this.shieldMaxValue;
            this.onChangeValue(this.shieldValue);

		//방패와 총알이 닿으면 방패게이지 -10 감소
            this.shield.onTriggerBullet = () =>
            {
                this.shieldValue -= 10;
                Debug.LogFormat("<color=red>{0}</color>",shieldValue);
            };

        }

스크립트

- LeftIndexTrigger를 입력을 받아 왼손 프리팹을 교체해줄 스크립트

- 방패게이지(UI)를 관리할 스크립트 : 방패 게이지 100%에서 초마다 따라 게이지가 1%씩 줄어듦

 

.

.

.

 

LeftHandShield

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

namespace LJE 
{
    public class LeftHandShield : MonoBehaviour
    {
        [SerializeField] private GameObject leftHand;
        [SerializeField] private GameObject leftHandShield;
        [SerializeField] private Shield shield;

        public System.Action<int> onChangeValue;
        private int shieldMaxValue = 100;
        private int shieldValue = 0;
        private float elapsedTime;
        private float timeSpeed = 4f;
        private float recoverSpeed = 7f;

        void Start()
        {
            this.shieldValue = this.shieldMaxValue;
            this.onChangeValue(this.shieldValue);
            
		//방패와 총알이 닿으면 방패게이지 -10 감소
            this.shield.onTriggerBullet = () =>
            {
                this.shieldValue -= 10;
                Debug.LogFormat("<color=red>{0}</color>",shieldValue);
            };

        }

        void Update()
        {
        	//왼손을 쥐면 방패쥔 손으로 변경
            if (OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger))
            {
                this.leftHand.SetActive(false);
                this.leftHandShield.SetActive(true);
                
                //방패가 나타나는 동안 방패게이지 감소
                this.elapsedTime += (Time.deltaTime * this.timeSpeed);
                if (this.elapsedTime >= 1)
                {
                    this.shieldValue--;
                    this.onChangeValue(this.shieldValue);
                    this.elapsedTime = 0f;
                }
            }
            //손을 다시 펴면 원래 왼손으로 변경
            else if (OVRInput.GetUp(OVRInput.Button.PrimaryIndexTrigger))
            {
                this.leftHand.SetActive(true);
                this.leftHandShield.SetActive(false);
                this.elapsedTime = 0;
                //this.shieldValue = shieldMaxValue;
                this.onChangeValue(this.shieldValue);
            }
            else
            {
            	//손을 피면 감소했던 게이지 다시 회복
                this.elapsedTime += (Time.deltaTime * this.recoverSpeed);
                if (this.elapsedTime >= 1)
                {
                    this.shieldValue++;
                    this.onChangeValue(this.shieldValue);
                    this.elapsedTime = 0f;
                  //방패게이지가 최대게이지를 넘어가지 않도록
                    if (this.shieldValue > this.shieldMaxValue)
                    {
                        this.shieldValue = this.shieldMaxValue;
                        this.onChangeValue(this.shieldValue);
                    }
                }
            }
        }
    }
}

 

Shield

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

public class Shield : MonoBehaviour
{
    [SerializeField] private LeftHandShield leftHandShield;
    public System.Action onTriggerBullet;

    //총알과 트리거 체크
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Bullet"))
        {
        	//총알 제거
            Destroy(other.gameObject);
           	//총알이 제거되었으니 게이지 닳게하도록 LeftHandShield에게 알리기
            this.onTriggerBullet();          
        }
    }
}

 

ShieldGaugeUI

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System.Runtime.CompilerServices;

namespace LJE 
{
    public class ShieldGaugeUI : MonoBehaviour
    {
        [SerializeField] private TMP_Text shieldGauge;
        [SerializeField] private LeftHandShield leftShield;


        void Start()
        {   
        	//value값이 변할때마다 출력
            this.leftShield.onChangeValue = (value) =>
            {
                this.shieldGauge.text = string.Format("{0}%", value);
            };
        }

        // Update is called once per frame
        void Update()
        {
        	//게이지txt 위치 조정
            this.transform.position = this.leftShield.transform.position + Vector3.right * 0.

        }
    }
}

 

- 알맞은 곳에 스크립트 부착


 

▼완성본