@ 슈터만들기
: 총을 완성했으니 총을 쏘는 슈터 역할을 하는 PlayerShooter 스크립트를 만들어야 함.
@ PlayerShooter 스크립트 기능
- 플레이어 입력에 따라 총을 쏘거나 재장전 함
- 플레이어 캐릭터의 손이 항상 총의 손잡이에 위치하도록 함
ㄴ 애니메이터의 IK를 사용해야 함
FK : 부모 조인트에서 자식 조인트 순서로 움직임을 적용함 // 큰 단위의 관절에서 세부적인 관절 순서로 움직임.
=> 손의 위치를 먼저 정하고 거기에 맞춰 애니메이션을 변형할 수 없음.
IK : 자식 조인트의 위치를 먼저 결정하고 부모 조인트가 거기에 맞춰 변형됨.
- IK Pass가 체크되어 있어야 사용 가능함.
- 애니메이터 컴포넌트가 IK 정보를 갱신할 때마다 OnAnimatiorIK 메시지가 발생.
@ PlayerShooter 스크립트
using UnityEngine;
// 주어진 Gun 오브젝트를 쏘거나 재장전
// 알맞은 애니메이션을 재생하고 IK를 사용해 캐릭터 양손이 총에 위치하도록 조정
public class PlayerShooter : MonoBehaviour {
public Gun gun; // 사용할 총
public Transform gunPivot; // 총 배치의 기준점
public Transform leftHandMount; // 총의 왼쪽 손잡이, 왼손이 위치할 지점
public Transform rightHandMount; // 총의 오른쪽 손잡이, 오른손이 위치할 지점
private PlayerInput playerInput; // 플레이어의 입력
private Animator playerAnimator; // 애니메이터 컴포넌트
private void Start() {
// 사용할 컴포넌트들을 가져오기
playerInput = GetComponent<PlayerInput>();
playerAnimator = GetComponent<Animator>();
}
private void OnEnable() {
// 슈터가 활성화될 때 총도 함께 활성화
gun.gameObject.SetActive(true);
}
private void OnDisable() {
// 슈터가 비활성화될 때 총도 함께 비활성화
gun.gameObject.SetActive(false);
}
private void Update() {
// 입력을 감지하고 총 발사하거나 재장전
if( playerInput.fire)
{
// 발사 감지시 총 발사
gun.Fire();
}
else if( playerInput.reload)
{
// 재장전 입력 감지시 재장전
if (gun.Reload())
{
// 재장전 성공 시에만 재장전 애니메이션 재생
playerAnimator.SetTrigger("Reload");
}
}
// 남은 탄알 UI 갱신
UpdateUI();
}
// 탄약 UI 갱신
private void UpdateUI() {
// gun에 사용할 총이 할당되어있으며 UIManager 싱글톤이 씬에 존재하는 경우에만 UIManager의 기능을 실행
if (gun != null && UIManager.instance != null)
{
// UI 매니저의 탄약 텍스트에 탄창의 탄약과 남은 전체 탄약을 표시
UIManager.instance.UpdateAmmoText(gun.magAmmo, gun.ammoRemain);
}
}
// 애니메이터의 IK 갱신
private void OnAnimatorIK(int layerIndex) {
// 총의 기준점 gunPivot을 3D 모델의 오른쪽 팔꿈치 위치로 이동
gunPivot.position = playerAnimator.GetIKHintPosition(AvatarIKHint.RightElbow);
// IK를 사용하여 왼손의 위치와 회전을 총의 왼쪽 손잡이에 맞춤
playerAnimator.SetIKPositionWeight(AvatarIKGoal.LeftHand, 1.0f);
playerAnimator.SetIKRotationWeight(AvatarIKGoal.LeftHand, 1.0f);
playerAnimator.SetIKPosition(AvatarIKGoal.LeftHand, leftHandMount.position);
playerAnimator.SetIKRotation(AvatarIKGoal.LeftHand, leftHandMount.rotation);
// IK를 사용하여 오른손의 위치와 회전을 총의 오른쪽 손잡이에 맞춤
playerAnimator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1.0f);
playerAnimator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1.0f);
playerAnimator.SetIKPosition(AvatarIKGoal.RightHand, rightHandMount.position);
playerAnimator.SetIKRotation(AvatarIKGoal.RightHand, rightHandMount.rotation);
}
}
- Gun 스크립트의 Fire()와 Reload()는 내부에서 if 문으로 총의 상태를 검사하여 발사하거나 재장전하기 때문에 PlayerShooter 스크립트에서 총의 상태를 직접 검사할 필요가 없음.
- gun에 사용할 총이 할당되어있으며 UIManager 싱글톤이 씬에 존재하는 경우에만 UIManager의 기능을 실행
@ OnAnimatorIK() 메서드
- 총을 상체와 함께 흔들기
- 캐릭터의 양손을 총의 양쪽 손잡이에 위치시키기.
- 총을 상체와 함께 흔들기 : Gun 오브젝트의 부모 오브젝트인 Gun Pivot 오브젝트를 항상 캐릭터의 오른쪽 팔꿈치에 배치하는 것으로 구현.
// 이걸 구현하지 않으면 상체가 숨쉬면서 위아래로 움직이는동안 총은 제자리에 가만히 떠있는 것처럼 보임.
@ GetIKHintPosition() : 애니메이터 컴포넌트인 이 메서드는 AvatarIKHint 타입으로 부위를 입력받아 해당 부위의 현재 위치를 가져옴.
- 캐릭터 왼손의 위치와 회전을 leftHandMount의 위치와 회전으로 변경.
- 그러기 위해 왼손 IK에 대한 위치와 회전가중치를 1.0(100%)으로 변경.
IK 가중치의 범위 0~1 사이. // 예를들어 0.5(50%)라면 원래 위치와 IK 목표위치가 절반씩 섞여 적용됨.
그다음 왼손 IK의 목표 위치와 목표 회전을 leftHandMount의 위치와 회전으로 지정.
애니메이터의 SetIKPosition()과 setIKRotation()은 IK 대상이 사용할 목표 위치와 목표 회전을 설정.
적용할 IK 대상 : 왼손 AvatarIKGoal.LeftHand
목표 위치 : 총의 왼손 손잡이의 위치 leftHandMount.position
목표 회전 : 왼손 손잡이의 회전 leftHandMount.rotation