using UnityEngine;
public class Crosshair : MonoBehaviour
{
[SerializeField]
private Animator animator;
//크로스헤어 상태에 따른 총의 정확도
private float gunAccuracy;
//크로스 헤어 비활성화를 위한 부모 객체
[SerializeField]
private GameObject go_crosshairHUD;
[SerializeField]
private GunController theGunController;
public void WalkingAnimation(bool _flag)
{
WeaponManager.currentWeaponAnim.SetBool("Walk", _flag);
animator.SetBool("Walking", _flag);
}
public void RunningAnimation(bool _flag)
{
WeaponManager.currentWeaponAnim.SetBool("Run", _flag);
animator.SetBool("Running", _flag);
}
public void JumpingAnimation(bool _flag)
{
animator.SetBool("Running", _flag);
}
public void CrouchingingAnimation(bool _flag)
{
animator.SetBool("Crouching", _flag);
}
public void FineingAnimation(bool _flag)
{
animator.SetBool("FineSight", _flag);
}
public void FireAnimation()
{
if (animator.GetBool("Walking"))
animator.SetTrigger("Walk_Fire");
else if (animator.GetBool("Crouching"))
animator.SetTrigger("Crouch_Fire");
else
animator.SetTrigger("Idle_Fire");
}
public float GetAccuracy()
{
if (animator.GetBool("Walking"))
gunAccuracy = 0.06f;
else if (animator.GetBool("Crouching"))
gunAccuracy = 0.015f;
else if (theGunController.GetFineSightMode())
gunAccuracy = 0.001f;
else
gunAccuracy = 0.035f;
return gunAccuracy;
}
}
using System.Collections;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
//스피드 조정 변수
[SerializeField]//시리얼라이즈 필드,인스펙터에 공개
private float walkSpeed;//이동 스피드
[SerializeField]
private float runSpeed;//달리기 스피드
[SerializeField]
private float crouchSpeed;
private float applySpeed;//현재 걷는,뛰는
[SerializeField]
private float jumpForce;
//상태변수
private bool isWalk = false;
private bool isRun = false;
private bool isCrouch = false;
private bool isGround = true;
//움직임 체크 변수
private Vector3 lastPos;
//앉았을때 얼마나 앉을지 결정하는 변수
[SerializeField]
private float crouchPosY;
private float originPosY;
private float applyCrouchPosY;
//땅 착지 여부
private CapsuleCollider capsuleCollider;
//카메라 민감도
[SerializeField]
private float lookSensitivity;
[SerializeField]
//카메라 한계
private float cameraRotationLimit;
private float currentCameraRotationX = 0;
//필요 컴포넌트
[SerializeField]
private Camera theCamera;//카메라
private Rigidbody myRigid;//리지드바디
[SerializeField]
private GunController theGunController;
private Crosshair theCrosshair;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
capsuleCollider = GetComponent<CapsuleCollider>();
myRigid = GetComponent<Rigidbody>();//Player에 있는 리지드바디 장착
theGunController = FindAnyObjectByType<GunController>();
theCrosshair = FindAnyObjectByType<Crosshair>();
//초기화
applySpeed = walkSpeed;
originPosY = theCamera.transform.localPosition.y;
applyCrouchPosY = originPosY;
}
// Update is called once per frame
void Update()
{
IsGround();
TryJump();
TryRun();
TryCrouch();
Move();
MoveCheck();
CameraRotation();
CharacterRotation();
}
private void TryCrouch()//앉기 시도
{
if (Input.GetKeyDown(KeyCode.LeftControl))
{
Crouch();
}
}
private void Crouch()//실제 앉기
{
isCrouch = !isCrouch;
theCrosshair.CrouchingingAnimation(isCrouch);
//if (isCrouch)
// isCrouch = false;
//else
// isCrouch = true;위 한줄짜리 코드 축약임
if (isCrouch)
{
applySpeed = crouchSpeed;
applyCrouchPosY = crouchPosY;
}
else
{
applySpeed = walkSpeed;
applyCrouchPosY = originPosY;
}
StartCoroutine(CrouchCoroutine());
}
IEnumerator CrouchCoroutine()//부드러운 앉기 동작 실행
{
float _posY = theCamera.transform.localPosition.y;
int count = 0;
while(_posY != applyCrouchPosY)
{
count++;
_posY = Mathf.Lerp(_posY, applyCrouchPosY, 0.5f);
theCamera.transform.localPosition = new Vector3(0, _posY, 0);
if (count > 15)
break;
yield return new WaitForSeconds(0.1f);
}
theCamera.transform.localPosition = new Vector3(0, applyCrouchPosY, 0f);
}
private void IsGround()//지면 체크
{
isGround = Physics.Raycast(transform.position, Vector3.down, capsuleCollider.bounds.extents.y + 0.1f);
theCrosshair.JumpingAnimation(!isGround);
}
private void TryJump()//점프시도
{
if (Input.GetKeyDown(KeyCode.Space) && isGround)
{
Jump();
}
}
private void Jump()//점프
{
if (isCrouch)
Crouch();
myRigid.linearVelocity = transform.up * jumpForce;
}
private void TryRun()//달리기 시도
{
if (Input.GetKey(KeyCode.LeftShift))
{
Running();
}
if (Input.GetKeyUp(KeyCode.LeftShift))
{
RunningCancel();
}
}
private void Running()//달리기 실행
{
if (isCrouch)
Crouch();
theGunController.CancelFineSight();
isRun = true;
theCrosshair.RunningAnimation(isRun);
applySpeed = runSpeed;
}
private void RunningCancel()//달리기 취소
{
isRun = false;
theCrosshair.RunningAnimation(isRun);
applySpeed = walkSpeed;
}
private void Move()//걷기 실행
{
float _moveDirX = Input.GetAxisRaw("Horizontal");//좌우 방향키를 입력시 +1 ~ -1이 반환된다
float _moveDirZ = Input.GetAxisRaw("Vertical");//상하 움직임 입력시 +1 ~ -1이 반환된다
Vector3 _moveHorizontal = transform.right * _moveDirX;
Vector3 _moveVertical = transform.forward * _moveDirZ;//실제 입력과 같이 이동을 처리함
Vector3 _velocity = (_moveHorizontal + _moveVertical).normalized * applySpeed;
myRigid.MovePosition(transform.position + _velocity * Time.deltaTime);
}
//움직임 체크
private void MoveCheck()
{
if (!isRun && !isCrouch && isGround)
{
if (Vector3.Distance(lastPos, transform.position) >= 0.01f)
isWalk = true;
else
isWalk = false;
theCrosshair.WalkingAnimation(isWalk);
lastPos = transform.position;
}
}
private void CharacterRotation()//좌우 캐릭터 회전
{
float _yRotation = Input.GetAxisRaw("Mouse X");
Vector3 _characterRotationY = new Vector3(0f, _yRotation, 0f) * lookSensitivity;
myRigid.MoveRotation(myRigid.rotation * Quaternion.Euler(_characterRotationY));
//Debug.Log(myRigid.rotation);
//Debug.Log(myRigid.rotation.eulerAngles);
}
private void CameraRotation()//시점 위아래 이동
{
float _xRotation = Input.GetAxisRaw("Mouse Y");
float _cameraRotationX = _xRotation * lookSensitivity;
currentCameraRotationX -= _cameraRotationX;
currentCameraRotationX = Mathf.Clamp(currentCameraRotationX, -cameraRotationLimit, cameraRotationLimit);
theCamera.transform.localEulerAngles = new Vector3(currentCameraRotationX, 0f, 0f);
}
}
using System.Collections;
using UnityEngine;
public class HandController : MonoBehaviour
{
//활성화 여부
public static bool isActivate = false;
//현재 장착된 Hand형 타입 무기
[SerializeField]
private Hand currentHand;
//공격중??
private bool isAttack = false;
private bool isSwing = false;
private RaycastHit hitInfo;
void Update()
{
if(isActivate)
TryAttack();
}
private void TryAttack()
{
if (Input.GetButton("Fire1"))
{
if (!isAttack)
{
StartCoroutine(AttackCoroutine());
}
}
}
IEnumerator AttackCoroutine()
{
isAttack = true;
currentHand.anim.SetTrigger("Attack");
yield return new WaitForSeconds(currentHand.attackDelayA);
isSwing = true;
StartCoroutine(HitCoroutine());
yield return new WaitForSeconds(currentHand.attackDelayB);
isSwing = false;
yield return new WaitForSeconds(currentHand.attackDelay - currentHand.attackDelayA - currentHand.attackDelayB);
isAttack = false;
}
IEnumerator HitCoroutine()
{
while (isSwing)
{
if (CheckObject())
{
isSwing = false;
Debug.Log(hitInfo.transform.name);
}
yield return null;
}
}
private bool CheckObject()
{
if (Physics.Raycast(transform.position, transform.forward /*transform.TransformDirection(Vector3.forward)은 같은 뜻*/, out hitInfo, currentHand.range))
{
return true;
}
return false;
}
public void HandChange(Hand _hand)
{
if (WeaponManager.currentWeapon != null)
WeaponManager.currentWeapon.gameObject.SetActive(false);
currentHand = _hand;
WeaponManager.currentWeapon = currentHand.GetComponent<Transform>();
WeaponManager.currentWeaponAnim = currentHand.anim;
currentHand.transform.localPosition = Vector3.zero;
currentHand.gameObject.SetActive(true);
isActivate = true;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunController : MonoBehaviour
{
//활성화 여부
public static bool isActivate = true;
//현재 장착된 총
[SerializeField]
private Gun currentGun;
//연사속도 계산
private float currentFireRate;//정조준 위치를 위한 값
//상태변수
private bool isReload = false;
[HideInInspector]//인스팩터에세 숨김
public bool isFineSightMode = false;//정조준 위치 bool 값
// 본래 포지션 값.
[SerializeField]
private Vector3 originPos;//원래 조준위치
//효과음
private AudioSource audioSource;
//레이져 충돌 정도 받아옴
private RaycastHit hitInfo;
//필요한 카메라 컴포넌트
[SerializeField]
private Camera theCam;
private Crosshair theCrosshair;
//피격 이팩트
[SerializeField]
private GameObject hit_effect_prefab;
void Start()
{
originPos = Vector3.zero;
audioSource = GetComponent<AudioSource>();
theCrosshair = FindAnyObjectByType<Crosshair>();
WeaponManager.currentWeapon = currentGun.GetComponent<Transform>();
WeaponManager.currentWeaponAnim = currentGun.anim;
}
// Update is called once per frame
void Update()
{
if (isActivate)
{
GunFireRateCalc();
TryFire();
TryReload();
TryFineSight();
}
}
//연사속도 재계산
private void GunFireRateCalc()
{
if (currentFireRate > 0)
currentFireRate -= Time.deltaTime;
}
//발사시도
private void TryFire()
{
if (Input.GetButton("Fire1") && currentFireRate <= 0 && !isReload)
{
Fire();
}
}
//발사전 계산
private void Fire()
{
if (!isReload)
{
if (currentGun.currentBulletCount > 0)
Shoot();
else
{
CancelFineSight();
StartCoroutine(ReloadCoroutine());
}
}
}
//발사 후 계산
private void Shoot()
{
theCrosshair.FireAnimation();
currentGun.currentBulletCount--;
currentFireRate = currentGun.fireRate; // 연사 속도 재계산.
PlaySE(currentGun.fire_Sound);
currentGun.muzzleFlash.Play();
Hit();
StopAllCoroutines();
StartCoroutine(RetroActionCoroutine());
}
private void Hit()
{
if (Physics.Raycast(theCam.transform.position, theCam.transform.forward +
new Vector3(Random.Range(-theCrosshair.GetAccuracy() - currentGun.accuracy, theCrosshair.GetAccuracy() + currentGun.accuracy),
Random.Range(-theCrosshair.GetAccuracy() - currentGun.accuracy, theCrosshair.GetAccuracy() + currentGun.accuracy),
0), out hitInfo, currentGun.range))
{
GameObject clone = Instantiate(hit_effect_prefab, hitInfo.point, Quaternion.LookRotation(hitInfo.normal));
Destroy(clone, 2f);
//Debug.Log(hitInfo.transform.name);
}
}
//재장전 시도
private void TryReload()
{
if (Input.GetKeyDown(KeyCode.R) && !isReload && currentGun.currentBulletCount < currentGun.reloadBulletCount)
{
CancelFineSight();
StartCoroutine(ReloadCoroutine());
}
}
public void CancelReload()
{
if (isReload)
{
StopAllCoroutines();
isReload = false;
}
}
//재장전
IEnumerator ReloadCoroutine()
{
if (currentGun.carryBulletCount > 0)
{
isReload = true;
currentGun.anim.SetTrigger("Reload");
currentGun.carryBulletCount += currentGun.currentBulletCount;
currentGun.currentBulletCount = 0;
yield return new WaitForSeconds(currentGun.reloadTiem);
if (currentGun.carryBulletCount >= currentGun.reloadBulletCount)
{
currentGun.currentBulletCount = currentGun.reloadBulletCount;
currentGun.carryBulletCount -= currentGun.reloadBulletCount;
}
else
{
currentGun.currentBulletCount = currentGun.carryBulletCount;
currentGun.carryBulletCount = 0;
}
isReload = false;
}
else
{
Debug.Log("소유한 총알이 없습니다.");
}
}
//정조준 시도
private void TryFineSight()
{
if (Input.GetButtonDown("Fire2") && !isReload)
{
FineSight();
}
}
//정조준 취소
public void CancelFineSight()
{
if (isFineSightMode)
FineSight();
}
//정조준 로직가동
private void FineSight()
{
isFineSightMode = !isFineSightMode;
currentGun.anim.SetBool("FineSightMode", isFineSightMode);
theCrosshair.FineingAnimation(isFineSightMode);
if (isFineSightMode)
{
StopAllCoroutines();
StartCoroutine(FineSightActivateCoroutine());
}
else
{
StopAllCoroutines();
StartCoroutine(FineSightDeactivateCoroutine());
}
}
//정조준 활성화
IEnumerator FineSightActivateCoroutine()
{
while (currentGun.transform.localPosition != currentGun.fineSightOriginPos)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, currentGun.fineSightOriginPos, 0.2f);
yield return null;
}
}
//정조준 비활성화
IEnumerator FineSightDeactivateCoroutine()
{
while (currentGun.transform.localPosition != originPos)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, originPos, 0.2f);
yield return null;
}
}
//총 반동
IEnumerator RetroActionCoroutine()
{
Vector3 recoilBack = new Vector3(currentGun.retroActionForce, originPos.y, originPos.z);
Vector3 retroActionRecoilBack = new Vector3(currentGun.retroActionFineSightForce, currentGun.fineSightOriginPos.y, currentGun.fineSightOriginPos.z);
if (!isFineSightMode)
{
currentGun.transform.localPosition = originPos;
// 반동 시작
while (currentGun.transform.localPosition.x <= currentGun.retroActionForce - 0.02f)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, recoilBack, 0.4f);
yield return null;
}
// 원위치
while (currentGun.transform.localPosition != originPos)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, originPos, 0.1f);
yield return null;
}
}
else
{
currentGun.transform.localPosition = currentGun.fineSightOriginPos;
// 반동 시작
while (currentGun.transform.localPosition.x <= currentGun.retroActionFineSightForce - 0.02f)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, retroActionRecoilBack, 0.4f);
yield return null;
}
// 원위치
while (currentGun.transform.localPosition != currentGun.fineSightOriginPos)
{
currentGun.transform.localPosition = Vector3.Lerp(currentGun.transform.localPosition, currentGun.fineSightOriginPos, 0.1f);
yield return null;
}
}
}
//사운드 재생
private void PlaySE(AudioClip _clip)
{
audioSource.clip = _clip;
audioSource.Play();
}
public Gun GetGun()
{
return currentGun;
}
public bool GetFineSightMode()
{
return isFineSightMode;
}
public void GunChange(Gun _gun)
{
if(WeaponManager.currentWeapon != null)
WeaponManager.currentWeapon.gameObject.SetActive(false);
currentGun = _gun;
WeaponManager.currentWeapon = currentGun.GetComponent<Transform>();
WeaponManager.currentWeaponAnim = currentGun.anim;
currentGun.transform.localPosition = Vector3.zero;
currentGun.gameObject.SetActive(true);
isActivate = true;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponManager : MonoBehaviour
{
//무기 중복 교체 실행방지
public static bool isChangeWeapon = false;//static 공유되는 자원
//현재 무기의 애니메이션
public static Transform currentWeapon;
public static Animator currentWeaponAnim;
//현재 무기 타입
[SerializeField]
private string currentWeaponType;
[SerializeField]
private float changeWeaponDelayTime;
[SerializeField]
private float changeWeaponEndDelayTime;
[SerializeField]
private Gun[] guns;
[SerializeField]
private Hand[] hands;
//관리 차원에서 쉽게 무기 접근이 가능하게 만듦
private Dictionary<string, Gun> gunDictionary = new Dictionary<string, Gun>();
private Dictionary<string, Hand> handDictionary = new Dictionary<string, Hand>();
//필요한 컴포넌트
[SerializeField]
private GunController theGunController;
[SerializeField]
private HandController theHandController;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
for (int i = 0; i < guns.Length; i++)
{
gunDictionary.Add(guns[i].gunName, guns[i]);
}
for (int i = 0; i < hands.Length; i++)
{
handDictionary.Add(hands[i].handName, hands[i]);
}
}
// Update is called once per frame
void Update()
{
if (!isChangeWeapon)
{
if (Input.GetKeyDown(KeyCode.Alpha1))
StartCoroutine(ChangeWeaponCoroutine("HAND", "맨손"));
else if (Input.GetKeyDown(KeyCode.Alpha2))
StartCoroutine(ChangeWeaponCoroutine("GUN", "SubMachineGun1"));
}
}
public IEnumerator ChangeWeaponCoroutine(string _type, string _name)
{
isChangeWeapon = true;
currentWeaponAnim.SetTrigger("Weapon_Out");
yield return new WaitForSeconds(changeWeaponDelayTime);
CancelPreWeaponAction();
WeaponChange(_type, _name);
yield return new WaitForSeconds(changeWeaponEndDelayTime);
currentWeaponType = _type;
isChangeWeapon = false;
}
//무기 취소 함수
private void CancelPreWeaponAction()
{
switch (currentWeaponType)
{
case "GUN":
theGunController.CancelFineSight();
theGunController.CancelReload();
GunController.isActivate = false;
break;
case "HAND":
HandController.isActivate = false;
break;
}
}
private void WeaponChange(string _type, string _name)
{
if(_type == "GUN")
theGunController.GunChange(gunDictionary[_name]);
else if(_type == "HAND")
theHandController.HandChange(handDictionary[_name]);
}
}
오늘은 웨펀메니져를 공부할 것이다
무기의 0번을 누르면 맨손이 나오고 1번을 누르면 우리가 그동안 만들은 머신건을 나오게 할 것 이다
우선 C# 스크립트로 WeaponManager 이라는 파일을 만든다
선언해준 변수 목록이다
8번줄의 static 로 선언된 변수는 모든 스크립트를 통틀어서 하나의 변수만 선언되게 하는 변수이다
기존의 변수들은 파일만 다르면 이름이 같아도 그 스크립트 내의 변수로 관리가 되었지만 static로 선언을 하게 되면
다른 스크립트로 넘어가도 하나의 변수로 관리하게 된다 이걸 bool값으로 선언해서 on/off를 관리한다
11번 줄은 Transform으로 선언이 되었는데 유니티에서 Transform은 가장 기초적인 컴포넌트이고 여러가지 값을 가지고 있는 컴포넌트이다 이번에는 이걸 이용한다
12번 줄은 애니메이터를 선언해준 것이다
16번 줄은 string로 선언해서 무기의 이름을 문자열로 받아온 것이다
19번줄과 21번 줄은 무기를 바꾸고 나는 딜레이를 flaot로 선언해준 것이다
24번은 총을 []으로 배열화했고
26번은 손의 []으로 배열로 했다
29번줄과 30번 줄은 Dictionary(딕셔너리)라고 하는 변수타입을 선언해주었다
Dictionary는 C#의 자료구조 중 하나로 데이터를 key와 value의 싸응로 저장하고 관리할 수 있는 컬랙션이다
이 변수는 실제 사전처럼 특정키를 통해 원하는 값을 빨리 받아올 수 있게 설계되어있다
주요 특징은
키와 값의 쌍으로 이루어져 있어 고유한 키와 그에 대응하는 값으로 구성되어 있다
키를 사용하여 값을 효율적으로 검색할 수 있다
데이터의 순서에 관계 없이 값이 저장된다
동일한 키를 두번 사용할 수 없다
이 Dictionary를 선언과 동시에 값을 넣어주었다
33~36번 줄은 건컨트롤러와 핸드컨트롤러를 선언해준 것이다
void Start()함수이다
for문으로 i =0이고 i는 guns.Length보다 적으며 i++으로 반복해주어
지금금 가진 gunDictionary와 handDictionary에서 무기를 검색해 불러와준다
void Update()함수이다
if문으로 !isChangeWeapon으로 웨폰체인지가 아닐때
if문으로 1번키를 누르면 ChangeWeaponCoroutine 코루틴이 스타트되며 string값으로 "HAND", "맨손" 을 불러온다
else if문은 2번키를 누르면
ChangeWeaponCoroutine 코루틴이 스타트되며 string값으로 "GUN", "SubMachineGun1"을 코루틴으로 불러온다
대망의 코루틴 ChangeWeaponCoroutine(string _type, string _name)이다
일단 static로 선언된 isChangeWeapon을 true로 만들어주고
currentWeaponAnim.SetTrigger("Weapon_Out")를 실행하여 무기를 집어놓는 손 동작을 실행한다
그뒤 changeWeaponDelayTime를 실행하여 인스펙터에 선언된 변수만큼 쉬어주고
CancelPreWeaponAction()함수를 실행해준다
그위 WeaponChange(_type, _name)를 실행해주고
이번에는 changeWeaponEndDelayTime 변수만큼 쉬어주고
currentWeaponType = _type와 값을 같게해주고
static로 선언된 isChangeWeapon을 false로 해준다
이제 void CancelPreWeaponAction()함수를 보자
switch문으로 currentWeaponType로 string 조건문을 선언해주고
case로 GUN 이 조건이라면
GunController에서 cancelFineSight()함수를 실행해주고 정조준 취소를 호출해준다
GunController에서 CancelReload() 함수를 실행해준다
그리고 GunController에서 isActivate = false로 바꾸어서 조준점을 관리해준다
Gun 스크립트를 비활성화해준다
그리고 break;로 끊어준다
case로 HAND가 조건이면
HandController.isActivate = false로 이건 HAND를 비활성화해주는 함수이다
그리고 break;로 끊어준ㄷ다
WeaponChange(string _type, string _name)함수이다
if문으로 조건 인수로 받아온 _type가 GUN과 같다면
theGunController에서 GunChange(gunDictionary[_name])를 호출해주어 장비한다
97번줄은 else if로 인수로 받아온 _type가 HAND와 같다면
theHandController에서 HandChange(handDictionary[_name])를 호출해주어 장비한다
이제 GunController C# 스크립트를 열어보자
void Start()함수에
보라색으로 표시한 변수를 추가해주자
WeaponManager 스크립트에서 받아온 값을 초기화해주는 것이다
여기에 CancelReload() 함수를 추가해주자
조건문으로 isReload가 true일때
모든 코루틴을 스돕하고 isReload를 false로 바꿔준다
다음은 GunChange(Gun _gun)함수를 보자
조건문으로 우리가 작성해온 WeaonManager에서 currentWeapon이 null이 아니라면
WeaopnManager.currentWeapon.gameObject.SetActive(false)라고 작성하여 무기 활성화를 해제해준다
298번에 _gun 인수를 currentGun에 넣어준다
그뒤 299번에 WeaopnManager.currentWeaopn변수에 currentGun.GetComponent<Transform>()을 넣어준다
그리고 300번에 WeaopnManager.currentWeaponAnim = currentGun.anim을 해준다
그뒤 302번에 currentGun.transform.localPosition = Vector3.zero 로 초기화해준다
그뒤 303번에 currentGun.gameObject에 SetActive(true)로 스크립트를 활성화해준다
그리고 스크립트의 isActivate를 true로 이건 조준점 관련으로 작성된 것이다
이제 C# 스크립트 HandController 를 열어주자
바로 위의 GunChange(Gun _gun)
함수에서 Gun대신 Hand로 전부 수정해준 것에 불과하다
이건 총에서 손으로 무기를 바꿀때 해주는 함수이다
이제 인스펙터에 값을 넣자
우리가 지금까지 만들어준 값이다 슬롯에 쉽게 넣어주자
그리고 스크립트를 작성하면서 테스트를 하면 총을 바꿀때 out하는 애니메이션이 실행이 안될 것이다
원인은 애니메이션에서 케이디님을 따라하다가 Gun0Weapon_out함수를 연결하지 않았기 때문이다
위처럼 박스에 AnyState를 연결해주고 인스펙터를 아래처럼 수정해주자
그리고 다음은 손을 든 상태에서 조준점의 정조준 상태를 막는 것을 할 것이다
GunController 스크립트를 열어서 아래 8번 줄을 작성해주자
그리고 void Update함수에서 파란줄친 부분을 작성해주자
HandController 스크립트도 파란줄에 밑줄 친 부분을 작성해주자
이렇게 해주면 기존에 작성된 함수와 같이 움직여서 조준점이 관리될 것이다
정확히는 조준점이 핸드일때 정조준이 되는 문제가 해결 될 것이다
그리고 애니메이션도 살짝 수정줄 것이다
에니메이터를 걷고 뛰는것에 맞춰 애니메이션을 실행해줄 것이다
Crosshair 스크립트를 열어서 애니메이션을 보자
1번은 기존의 함수를 수정한 것이고 2번은 우리가 Jumping 애니메이션을 추가한 것이다
bool값으로 _flag를 인수로 받아왔기 때문에 살짝만 수정해줘도 된다
그리고 Jumping를 추가했으면 PlayerController 스크립트를 수정하자
파란색으로 밑줄친 부분을 수정해주자
JumpingAnimation함수를 대응하게 한 것이다
이렇게 해주면...
1번과 2번의 키로 번갈아서 무기를 잡는 것이 구현되었고
걷기와 뛰기도 구분되었으며
맨손 모드일때는 정조준이 되지 않으나 총을 잡았을때는 정조준이 구현되었다
'FPS서바이벌 디펜스' 카테고리의 다른 글
9.Weapon Sway(마우스 민감도) (0) | 2025.04.28 |
---|---|
7.크로스헤어(조준점) (0) | 2025.04.23 |
6.HUD (0) | 2025.04.22 |
5-3.명중, 피격 이팩트 (0) | 2025.04.21 |
5-2.재장전, 정조준, 반동 (0) | 2025.04.17 |