상세 컨텐츠

본문 제목

유니티 탑다운 게임 개발 Version.1

유니티/기능

by MJ_119 2024. 10. 10. 10:51

본문

- 화면이 캐릭터를 따라가도록 개발.

- 캐릭터 이동(걷기, 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 };

 

관련글 더보기