- 화면이 캐릭터를 따라가도록 개발.
- 캐릭터 이동(걷기, Shift 달리기), 총과 머리가 마우스 따라 움직임
- 총을 키보드 1~5번을 눌러서 바꿀때 총 타입에 맞춰 Side에서 꺼내거나 Back에서 꺼냄.
- IK 적용해서 손이 총에 자연스럽게 달라붙게 만듦.
- 사격할때 애니메이션과 IK가 충돌하지 않게 IK의 weight값을 낮췄다가 높임.
- PlayerAim.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAim : MonoBehaviour
{
private Player player;
private PlayerControlls controls;
[Header("Aim info")]
[SerializeField] Transform aim;
[SerializeField] LayerMask aimLayerMask;
Vector2 aimInput;
void Start()
{
player = GetComponent<Player>();
AssignInputEvents();
}
private void Update()
{
aim.position = new Vector3(GetMousePosition().x, transform.position.y + 1, GetMousePosition().z);
}
public Vector3 GetMousePosition()
{
Ray ray = Camera.main.ScreenPointToRay(aimInput);
if(Physics.Raycast(ray, out var hitInfo, Mathf.Infinity, aimLayerMask))
{
return hitInfo.point;
}
return Vector3.zero;
}
private void AssignInputEvents()
{
controls = player.controls;
controls.Character.Aim.performed += context => aimInput = context.ReadValue<Vector2>();
controls.Character.Aim.canceled += context => aimInput = Vector2.zero;
}
}
- LeftHand_Target_Transform.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LeftHand_Target_Transform : MonoBehaviour
{
}
- Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public PlayerControlls controls;
public PlayerAim aim { get; private set; } // read-only
public void Awake()
{
controls = new PlayerControlls();
aim = GetComponent<PlayerAim>();
}
private void OnEnable()
{
controls.Enable();
}
private void OnDisable()
{
controls.Disable();
}
}
- PlayerAnimationEvents.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAnimationEvents : MonoBehaviour
{
PlayerWeaponVisuals visualController;
void Start()
{
visualController = GetComponentInParent<PlayerWeaponVisuals>();
}
public void ReloadIsOver()
{
visualController.MaximizeRigWeight();
// refill - bullets.
}
public void ReturnRig()
{
visualController.MaximizeRigWeight();
visualController.MaximizeLeftHandIkWeight();
}
public void WeaponGrabIsOver()
{
visualController.SetBusyGrabbingWeaponTo(false);
}
}
- PlayerMovement.cs
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
Player player;
CharacterController characterController;
PlayerControlls controls;
Animator animator;
[Header("Movement info")]
[SerializeField] float walkSpeed = 3f;
[SerializeField] float runSpeed;
[SerializeField] float turnSpeed;
float speed;
float verticalVelocity;
Vector3 movementDirection;
Vector2 moveInput;
bool isRunning = false;
private void Start()
{
characterController = GetComponent<CharacterController>();
animator = GetComponentInChildren<Animator>();
player = GetComponent<Player>();
isRunning = false;
speed = walkSpeed;
AssignInputEvents();
}
private void Update()
{
ApplyMovement();
ApplyRotation();
AnimatorControllers();
}
private void AnimatorControllers()
{
float xVelocty = Vector3.Dot(movementDirection.normalized, transform.right);
float zVelocty = Vector3.Dot(movementDirection.normalized, transform.forward);
animator.SetFloat("xVelocity", xVelocty, 0.1f, Time.deltaTime);
animator.SetFloat("zVelocity", zVelocty, 0.1f, Time.deltaTime);
bool playRunAnimation = isRunning && movementDirection.magnitude > 0;
animator.SetBool("isRunning", playRunAnimation);
}
private void ApplyRotation()
{
Vector3 lookingDirection = player.aim.GetMousePosition() - transform.position;
lookingDirection.y = 0;
lookingDirection.Normalize();
Quaternion desireRotation = Quaternion.LookRotation(lookingDirection);
transform.rotation = Quaternion.Slerp(transform.rotation, desireRotation, turnSpeed * Time.deltaTime);
}
private void ApplyMovement()
{
movementDirection = new Vector3(moveInput.x, 0, moveInput.y);
ApplyGravity();
if (movementDirection.magnitude > 0)
{
characterController.Move(movementDirection * speed * Time.deltaTime);
}
}
private void ApplyGravity()
{
if (characterController.isGrounded == false)
{
verticalVelocity -= 9.81f * Time.deltaTime;
movementDirection.y = verticalVelocity;
}
else
{
verticalVelocity = -0.5f;
}
}
private void AssignInputEvents()
{
controls = player.controls;
controls.Character.Movement.performed += context => moveInput = context.ReadValue<Vector2>();
controls.Character.Movement.canceled += context => moveInput = Vector2.zero;
controls.Character.Run.performed += context =>
{
speed = runSpeed;
isRunning = true;
};
controls.Character.Run.canceled += context =>
{
speed = walkSpeed;
isRunning = false;
};
}
}
- PlayerWeaponControllers.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerWeaponControllers : MonoBehaviour
{
Player player;
void Start()
{
player = GetComponent<Player>();
player.controls.Character.Fire.performed += context => Shoot();
}
void Update()
{
}
private void Shoot()
{
print("fire");
GetComponentInChildren<Animator>().SetTrigger("Fire");
}
}
- PlayerWeaponVisuals.cs
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Animations.Rigging;
public class PlayerWeaponVisuals : MonoBehaviour
{
bool isGrabbingWeapon;
[SerializeField] Transform[] gunTransforms;
Transform currentGun;
[SerializeField] Transform pistol;
[SerializeField] Transform revolver;
[SerializeField] Transform autoRifle;
[SerializeField] Transform shotgun;
[SerializeField] Transform rifle;
[Header("Rig")]
[SerializeField] float rigWeightIncreaseRate;
bool ShouldIncrease_RigWeight;
Rig rig;
[Header("Left Hand IK")]
[SerializeField] TwoBoneIKConstraint leftHandIk;
[SerializeField] Transform leftHandIK_Target;
[SerializeField] float leftHandIkWeightIncreaseRate;
bool ShouldIncrease_LeftHandIkWeight;
Animator animator;
void Start()
{
animator = GetComponentInChildren<Animator>();
rig = GetComponentInChildren<Rig>();
SwitchOn(pistol);
}
void Update()
{
CheckWeaponSwitch();
if (Input.GetKeyDown(KeyCode.R) && isGrabbingWeapon == false)
{
animator.SetTrigger("Reload");
ReduceRigWeight();
}
UpdateRigWeight();
UpdateLeftHandIkUpdate();
}
private void UpdateLeftHandIkUpdate()
{
if (ShouldIncrease_LeftHandIkWeight)
{
leftHandIk.weight += leftHandIkWeightIncreaseRate * Time.deltaTime;
if (leftHandIk.weight >= 1)
{
ShouldIncrease_LeftHandIkWeight = false;
}
}
}
private void UpdateRigWeight()
{
if (ShouldIncrease_RigWeight)
{
rig.weight += rigWeightIncreaseRate * Time.deltaTime;
if (rig.weight >= 1)
{
ShouldIncrease_RigWeight = false;
}
}
}
private void ReduceRigWeight()
{
rig.weight = 0.15f;
}
public void MaximizeRigWeight()
{
ShouldIncrease_RigWeight = true;
}
public void MaximizeLeftHandIkWeight()
{
ShouldIncrease_LeftHandIkWeight = true;
}
private void CheckWeaponSwitch()
{
if (Input.GetKeyDown(KeyCode.Alpha1))
{
SwitchAnimationLayer(1);
SwitchOn(pistol);
PlayWeaponGrabAnimation(GrabType.SideGrab);
}
if (Input.GetKeyDown(KeyCode.Alpha2))
{
SwitchAnimationLayer(1);
SwitchOn(revolver);
PlayWeaponGrabAnimation(GrabType.SideGrab);
}
if (Input.GetKeyDown(KeyCode.Alpha3))
{
SwitchAnimationLayer(1);
SwitchOn(autoRifle);
PlayWeaponGrabAnimation(GrabType.BackGrab);
}
if (Input.GetKeyDown(KeyCode.Alpha4))
{
SwitchAnimationLayer(2);
SwitchOn(shotgun);
PlayWeaponGrabAnimation(GrabType.BackGrab);
}
if (Input.GetKeyDown(KeyCode.Alpha5))
{
SwitchAnimationLayer(1);
SwitchOn(rifle);
PlayWeaponGrabAnimation(GrabType.BackGrab);
}
}
void SwitchOn(Transform gunTransform)
{
SwitchOffGuns();
gunTransform.gameObject.SetActive(true);
currentGun = gunTransform;
AttachLeftHand();
}
private void SwitchOffGuns()
{
for (int i = 0; i < gunTransforms.Length; i++)
{
gunTransforms[i].gameObject.SetActive(false);
}
}
void PlayWeaponGrabAnimation(GrabType grabType)
{
leftHandIk.weight = 0;
ReduceRigWeight();
animator.SetFloat("WeaponGrabType", ((float)grabType));
animator.SetTrigger("WeaponGrab");
SetBusyGrabbingWeaponTo(true);
}
public void SetBusyGrabbingWeaponTo(bool busy)
{
isGrabbingWeapon = busy;
animator.SetBool("BusyGrabbingWeapon", isGrabbingWeapon);
}
void AttachLeftHand()
{
Transform targetTransform = currentGun.GetComponentInChildren<LeftHand_Target_Transform>().transform;
leftHandIK_Target.localPosition = targetTransform.localPosition;
leftHandIK_Target.localRotation = targetTransform.localRotation;
}
void SwitchAnimationLayer(int layerIndex)
{
for(int i = 1; i < animator.layerCount; i++)
{
animator.SetLayerWeight(i, 0);
}
animator.SetLayerWeight(layerIndex, 1);
}
}
public enum GrabType { SideGrab, BackGrab };
유니티 피봇, 고정 타게팅 위치 조절하기 (0) | 2024.10.14 |
---|---|
유니티 마우스 타겟 고정 하기 (0) | 2024.10.12 |
유니티 애니메이터 레이어(Animator layer) 껐다 키기 (1) | 2024.10.08 |
유니티 new input system 뉴 인풋 시스템 이동,애니메이션 구현 (0) | 2024.10.07 |
유니티 Chain Ik, 체인 IK, 애니메이션 리깅 (0) | 2024.10.04 |