본문 바로가기
카테고리 없음

유니티 3D 게임 개발 - TPS 반동구현

by 라이티아 2024. 11. 26.

구현 완료

1. 이동구현

2. 이동 애니메이션

3. 카메라 무빙
4. 대각 이동시 원을 그리게 변경해야함

 

 

불안전 요소

1. 카메라 이동 속도가 빠를시 생기는 계단현상

2. 벽넘기가 불안정함

3. 총기 조작 기능 <- 현재 부분

 

현재 완성까지 필요한 요소

1. 엄폐기능

2. 시네마씬을 이용한 게임 씬 제작

3. 강한 공격 맞을시 뒤로 밀려나기 = 피격 판정

 

 

이번 글에서는 사격중 반동을 구현해보려 한다

현재까지 개발된 부분을 테스트용으로 만든 구역이다

 

현재 보이는 가장 큰 문제는 카메라의 y각도가 고정되어 있어서 위, 아래를 조준할 수 없는 것이다

또한, 이로 엮이는 문제로 총기의 반동을 구현하지 못했다

 

오늘은 이러한 부분을 구현하려 한다

 

private void RotatePlayer()
{
    transform.Rotate(0, _mouseX * viewSpeed * Time.deltaTime, 0);
    if (_vertical > 0.01f && _horizontal != 0) // WD
    {
        Debug.Log("check");
        transform.rotation = transform.rotation * Quaternion.Euler(0, _horizontal * 0.5f, 0);
    }
}

 

현재 마우스를 돌리면 캐릭터 자체를 회전시키는 구조를 가지고 있다

 

여기에, 마우스를 위아래로 회전시키면 조준점이 움직이게 해야 한다

 

언제나 그렇듯 대충 설계를 끄적이고 시작한다

 

대충 캐릭터의 상반신에 카메라를 달고, 상반신의 회전각을 조절하는 방식을 취해보려 한다

 

public class CameraMovement : MonoBehaviour
{
    private Vector3 _cameraVelocity = Vector3.zero;
    public void MoveCamera(PlayerMovement PlayerScript, Transform AimTarget)
    {
        Vector3 targetPosition = PlayerScript.isAiming ? AimTarget.position : PlayerScript.gameObject.transform.position;

        Quaternion cameraRotation = Quaternion.Euler(0f, PlayerScript.gameObject.transform.eulerAngles.y, 0f);
        Vector3 desiredPosition = targetPosition + cameraRotation * PlayerScript.cameraOffset;

        // 카메라의 목표 위치 계산
        Vector3 finalPosition;
        if (!PlayerScript.isAiming)
        {
            finalPosition = Vector3.SmoothDamp(Camera.main.transform.position, desiredPosition, ref _cameraVelocity, 0.1f);
        }
        else
        {
            finalPosition = desiredPosition;
        }

        Vector3 localPosition = PlayerScript.gameObject.transform.InverseTransformPoint(finalPosition);

        localPosition.z = -3f;

        localPosition.x = Mathf.Clamp(localPosition.x, -1.5f, 1.5f);

        finalPosition = PlayerScript.gameObject.transform.TransformPoint(localPosition);

        Camera.main.transform.position = finalPosition;
        //Debug.Log("pos = " + PlayerScript.gameObject.transform.InverseTransformPoint(Camera.main.transform.position));

        Camera.main.transform.LookAt(targetPosition + new Vector3(0f, 1.5f, 0f));
    }
}

현재 카메라의 경우 이러한 코드를 가지고 있고, 카메라 스크립트는 플레이어 스크립트에 의존하는 형태를 하고 있다

이때 카메라는 Playermovemt라는 형태로 받고 있는데, 이를 Gameobject로 수정한뒤, 상반신에 붙이려 한다

 

는 유니티짱 아바타의 허리 회전이 이상해서 포기했다

 

애초에 모든 아바타에 적용될 수 없는 설계이니 과감히 파기한다

 

다음 아이디어를 설계해야 할 것 같다

뭔가 생각나는게 없으니, GPT의 아이디어를 빌려보자

 

 

 

카메라에 직접적으로 마우스의 y값을 받아서 적용하는걸 권하고 있다

 

이를 스크립트에 적용하면

 

float mouseY = Input.GetAxis("Mouse Y") * verticalSensitivity;

// 상하 회전 값 갱신 (마우스 입력에 따라 증가/감소)
_verticalRotation -= mouseY;
_verticalRotation = Mathf.Clamp(_verticalRotation, -verticalRotationLimit, verticalRotationLimit);

이러한 형태가 된다

 

이를 적용해서 확인하면

카메라가 떨리는걸 확인할 수 있다

 

예측한데로, Lookat과 강제로 카메라의 회전을 수정한것이 충돌하고 있는것 같다

 

만약 조준시만 이를 적용하면 괜찮을 것 같다

if (PlayerScript.isAiming)
{
    float mouseY = Input.GetAxis("Mouse Y") * verticalSensitivity;

    // 상하 회전 값 갱신 (마우스 입력에 따라 증가/감소)
    _verticalRotation -= mouseY;
    _verticalRotation = Mathf.Clamp(_verticalRotation, -verticalRotationLimit, verticalRotationLimit);
}
else
{
    _verticalRotation = 9.5f;
}

조건문을 걸어 필요 상황 = 조준시에만 마우스를 상하로 이동할 수 있게 제한을 걸었다

 

이제 조준시 시점이 자유로워 졌다

 

이제 여기에 총을 발사시 반동을 구현하면 된다

 

if (_mouseLeft && Time.time >= lastFireTime + fireRate && _leftBullets > 0 && !isReload)
{
    lastFireTime = Time.time;
    --_leftBullets;
    if (Physics.Raycast(muzzlePosition, directionToTarget, out RaycastHit enemy, maxDistance))
    {
        if (enemy.collider.CompareTag("Enemy"))
        {
            Debug.Log("적 맞춤");
            enemy.collider.GetComponent<Enemy_3D>().HP -= 1;
            Debug.Log("enemy HP = " + enemy.collider.GetComponent<Enemy_3D>().HP);
        }
    }
}

현재 총을 발사할시 실행되는 부분이다

여기에서 카메라의 회전각, 플레이어의 회전을을 강제로 올려준다

_cameraMovement.verticalRotation -= 0.5f;

이렇게 강제로 회전값을 높이는 방식으로 상반동을 구현한다

 

_cameraMovement.verticalRotation -= 0.5f;
float RandomHorizontalValue = Random.Range(-0.5f, 0.5f);
transform.rotation = transform.rotation * Quaternion.Euler(0f, RandomHorizontalValue, 0f);

Random으로 만들어낸 float값을 첫번째 Part1에서 배운 Quaternion의 합을 사용하는 방식으로 사용한다

 

 

반동이 잘 구현된 것을 확인할 수 있다