(Unity) 캐릭터 모션 코드 수정, 카메라 트래킹

03.10

캐릭터 이동속도 보정 부분

//player.cs
void Update()
    {
        // Movement input
        Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0, moveSpeed);
        // 입력 받은 값을 방향으로 변환하고 움직임 속도를 곱할 겁니다.
        // 입력의 방향을 얻기 위해 moveInput를 정규화(nomalized)하여 가져옵니다 (nomarlized는 방향을 가리키는 단위벡터로 만드는 연산)
        // 거기에 moveSpeed를 곱해줍니다
        Vector3 moveVelocity = moveInput.normalized * moveSpeed;
        // controller에게 velocity값을 넘겨줌
        controller.Move(moveVelocity);
    }

앞으로 달릴 때는 속도를 줄이고 좌우로 움직일 때는 속도를 높여야 한다.

– 코드 열기



학습시 갑자기 전진 속도 감소 = moveSpeed ​​값 감소

왼쪽 및 오른쪽 이동 속도 증가 = Input.GetAxisRaw(“Horizontal”)*moveSpeed

이것이 문제를 해결할 것이라고 생각했습니다.

moveSpeed ​​= 3.0f로 변경하고 Input.GetAxisRaw(“Horizontal”)*moveSpeed ​​하므로 괜찮은지 모르겠지만 해결되었습니다 … .? 더 좋은 방법이 있을 것 같은데…

Input.GetAxisRaw(문자열 이름)

  • 세 가지 값 -1, 0, 1 중 하나가 반환됩니다. 키보드 값을 눌렀을 때 즉시 반응해야 하는 경우 GetAxisRaw를 사용할 수 있습니다.

좌우 버튼을 누를 때마다 x값으로 -1, 0, 1을 입력하는데 비교해보면 z값이 5.0f이니 당연히 빨라야 했고.. 그래서 버티고 있다. 입력 .GetAxisRaw(“Horizontal”)*moveSpeed ​​좋은 방법을 위해 … ?

정상화하기는 좀 어려울 것 같습니다. 속도는 속도 + 방향이므로 입력 값은 방향 벡터로 변환되어 속도가 곱해진 것처럼 보입니다.

이상한 부분은 다음과 같습니다. 예를 들어 input.GetAxisRaw(“Horizontal”), 0, Input.GetAxisRaw(“Vertical”)를 인수로 사용하고 이 위치 값이 정규화되었다고 가정해 보겠습니다. 이때 왼쪽과 위쪽 화살표 키를 동시에 누르면 위쪽과 왼쪽으로 이동해야 한다. 그러면 Vector3.Left와 Vector3.Forward가 번갈아 입력됩니까?

그래서 내가 (Input.GetAxisRaw(“Horizontal”), 0, moveSpeed)

Vector3 moveVelocity = moveInput.normalized * moveSpeed;

좌우 이동…? 좌우움직임과 전진움직임 모두 크기가 1인 방향벡터로 변환되는데 왜 왼쪽(=Vector3(-1, 0, 0))과 앞으로(=Vector3(0, 0, 1 ))로부터의 속도가 계산되는가? 다르게? 해결되었습니다. 속도에만 크기 1의 벡터를 곱합니다. 왜 이런 일이 발생합니까?

방향 벡터 – 정규화 벡터 단위 – Marc Studio

(수학) 정규화(1) – 벡터와 좌표의 정규화


벡터를 정규화하면 벡터를 벡터의 길이로 나누어 해당 벡터의 길이를 1로 만듭니다.

길이가 1인 벡터를 단위 벡터라고 합니다.

왼쪽과 위쪽 방향으로 번갈아 입력하는 대신 왼쪽 위 벡터가 입력으로 입력됩니다.

이와 같이 좌우 입력은 -1,0,1을 입력하고 전면 방향의 입력은 항상 5.0f를 입력하므로 정규화하면 좌우 방향의 크기는 작은 반면 전면(top )의 입력은 좌우 방향 5번 비교하면 크겠죠. 그래서 방향이 좌우가 작고 앞이 커서 속도가 달라지는 것 같다.

Unity 및 C# concept_007_Unity 변수 유형 요약

Vector3 유형은 3차원(x, y, z)에서 객체의 위치를 ​​다시 결정하는 데 사용됩니다. x, y 및 z는 모두 float 유형입니다.

Unity에서 객체의 위치는 변환 구성 요소 위치의 각 차원 값에 의해 결정됩니다.

UnityEngine.Vector3 – Unity 스크립팅 API

Vector3 – 스크립팅 API – Unity – 매뉴얼


Position이라는 변수를 Vector3 타입으로 선언하고 새 Position의 이름을 지정하려면 다음과 같이 작성합니다.

vector3 위치 = 새로운 vector3 (2.0f, 3.0f, 4.0f) ;

더보기

Unity: Vector3의 매우 혼란스러운 사용 이해

Unity Vector3가 스택에 새로 생성됩니다.

C#에서 Vector는 구조체 형식입니다. 그리고 이 구조체 타입은 프리미티브 int, float, char, enum 등과 같은 값 타입이기 때문에 스택에 저장되며 new를 수행할 때 힙에 메모리 할당이 발생하지 않습니다.

객체와 문자열은 다른 언어와 마찬가지로 참조 유형입니다. 문자열은 스택에 저장되지만 변수는 참조입니다.

transform.position으로 가져온 Vector3는 참조가 아니므로 복사한 값이 저장되는 Vector3입니다. 따라서 Set()을 실행하면 복사된 값이 변경되므로 적용되지 않습니다.

new를 사용하고 있는데 update에서 반복해서 불러도 괜찮나요? 이전 내용의 확장으로 Vector3는 구조체 타입이고 유니티를 위해 new를 사용하기 때문에 실제로 스택에 생성되기 때문에 반복적인 메모리 누수나 할당/해제 문제가 없습니다. 즉, 자유롭게 사용할 수 있습니다.

참고로 쿼터니언도 구조체입니다. 값 유형에 대해 이야기하십시오.



위의 유니티 매뉴얼을 보면 Vector3.normalized 에 대한 내용도 나와있는데 역시 한글이 더 편하네요…

Vector3의 크기 및 정규화 – 천천히 흘러도 괜찮음

방향 벡터 정보는 1. 거리(크기) 및 2. 실제 방향 정보를 포함합니다.

1. 거리(크기) 크기

벡터의 길이를 반환합니다(읽기 전용). 벡터의 길이는 (xx+yy+z*z)의 제곱근입니다.

2. 오리엔테이션 정보 정규화

크기가 1(읽기 전용)인 벡터를 반환합니다. 즉, 크기 1의 벡터인 단위 벡터를 얻을 수 있으며 단위 벡터는 방향을 의미합니다. 예를 들어 (1, 0, 0)은 xyz 순서로 x축을 단위로 하는 벡터입니다.

이 값으로 해당 값에 대한 속도 계산을 할 때나 사용자의 프레임 속도를 곱하여 적용할 때 사용됩니다. B. 델타 시간.


방향 벡터 – 정규화 벡터 단위 – Marc Studio

벡터가 정규화되는 이유는 객체가 균일한 속도로 움직이기 때문입니다.

모든 방향 벡터의 길이는 1이어야 방향을 따라 이동하는 속도가 동일합니다.


정규화 없는 대각선 벡터는 1.414… 정규화 없이 변위를 적용하는 값에 도달하면 대각선 변위는 1.414… 배가 더 빨리 움직이고 있습니다.

참조! 대각선 벡터는 (0.7071068…, 0.7071068…)로 변환됩니다.

또 다른 예로 작은 값을 가진 벡터도 길이 1로 변환됩니다.

(0.5, 0).정규화 => (1, 0) : → 방향

(0.2, 0.2).정규화 => (0.7071068, 0.7071068) : 방향

이 정규화된 벡터를 방향 벡터라고 합니다.

(수학) 정규화(1) – 벡터와 좌표의 정규화

카메라 움직임의 일부

메인 카메라(유닛) 움직임 – Life in Balance

// CameraController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    GameObject player;

    // Start is called before the first frame update
    void Start()
    {
        player = GameObject.Find("Player");
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 PlayerPos = player.transform.position;
        transform.position = new Vector3(transform.position.x, transform.position.y, PlayerPos.z-7);
    }
}

위 블로그를 보고 코드를 조금 수정해서 코드를 작성했는데 실행해보니 생각만큼 잘 되는 것 같습니다.

그러나 마음에 들지 않는 구절이 몇 개 있습니다.

  1. 위의 플레이어 코드를 작성하면서 나는 transform.position이 그다지 좋은 코드가 아니라는 것을 깨달았습니다. 이것도 MovePosition에서 변경가능한가요?? Rigidbody.MovePosition이라 카메라에 적용은 안되는거 같은데 카메라를 효율적으로 움직일 수 있는 기능은 없을까요?
  2. transform.position = new Vector3(transform.position.x, transform.position.y, PlayerPos.z-7); 이 부분은 한번 이렇게 썼는데 원래 생각한게 현재 카메라 위치와 현재 캐릭터 위치 고정? 현재 캐릭터와의 거리를 유지하면서 Z 값이 카메라를 따라가길 원했습니다.

현재 카메라의 z 점수는 -55.61이고 플레이어의 z 점수는 -49.18입니다. 그래서 플레이어의 위치에서 7을 빼서 카메라의 위치를 ​​업데이트하도록 코드를 수정했습니다.

흠… 게임 카메라 컨트롤러를 실행하기 위한 아래 코드가 훨씬 좋아 보입니다.

https://github.com/Chaker-Gamra/Endless-Runner-Game/blob/master/Assets/Scripts/Player/CameraController.cs


오프셋 = 카메라 위치 – 플레이어 위치

이제 z만 보면 현재 카메라의 z-score는 -55.61이고 플레이어의 z-score는 -49.18입니다.

오프셋.z= (-55.61)-(-49.18) = (-55.61)+49.18=-6.43

newPosition= offset.z+target.position.z= (-49.18)+(-6.43)= -55.61

내가 바보가 된 기분이야… 이 코드를 보기 전에 Z포지션 값 두 개를 빼고 음… 생각해봤는데 두 값이 모두 음수라서 어디를 빼야할지 정하지 못했다.

얼마 전에 Lerp를 언급한 영상을 봤는데, 그런 식으로 쓰면 안 된다고 본 것 같아요. 당시 본 부분을 보면 lerp 부분은 수정이 필요할 것 같습니다.

그런데 왜 이 코드에서 lerp가 사용됩니까? 변환. 위치 = newPosition; 이렇게 해도 괜찮을 것 같고 실제로 코드를 바꿔봐도 둘의 차이를 잘 못느끼는데 왜 이걸 사용했을까요?

아직 Lerp를 조금 공부해야 할 것 같습니다.

03.11-03.12 코드를 바꾸고 싶어서 Lerp()를 조금 공부했는데 잘 안되네요.

공식 문서에서 Vector3.Lerp()를 확인하십시오.

https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html

public static Vector3 Lerp(Vector3 a, Vector3 b, Float t);

다시 말해서, 반환된 값은 a + (ba) * t입니다.a 값의 점진적인 증가가 예상됩니다. a의 증가는 점차 감소하여 b 값에 ​​도달하는데, 이는 도달 위치에 가까워질수록 속도가 느려진다는 것을 의미합니다.

(이 공식은 a * (1-t) + b * t로 대체하여 사용할 수도 있습니다.)

(Unity) Unity 3D Vector의 Linear Interpolation Lerp 정확한 사용법 Lerp는 선형 보간 함수입니다. 선형 보간법은 직선 거리에 따라 선형적으로 계산하여 양 끝점의 값을 주어 양 끝점 사이에 위치한 값을 추정하는 방법이다.

Unity에서는 값이 한 숫자에서 다른 숫자로 변경될 때 즉시 변경하지 않고 매끄럽게 변경하고 싶을 때 lerp를 사용합니다.

  • Mathf.Lerp: 숫자 사이의 선형 보간
  • Vector2.Lerp: Vector2 사이의 선형 보간
  • Vector3.Lerp: Vector3 사이의 선형 보간
  • Quaternion.Lerp: 쿼터니언 간의 선형 보간(회전)

개체를 부드럽게 이동하거나 회전하는 데 자주 사용됩니다. 카메라 추적 스크립트에서 사용할 수 있습니다.

Vector3.Lerp와 같은 형태로 사용(시작 위치, 끝 위치, 0과 1 사이의 실수)

Vector3.Lerp(시작 위치, 끝 위치, 0)은 시작 위치입니다.

Vector3.Lerp(시작 위치, 종료 위치, 1)이 종료 위치가 됩니다.

Time.deltatime은 마지막 프레임이 완료되는 데 걸린 시간을 초 단위로 나타냅니다(읽기 전용).

업데이트 기능은 프레임당 한 번 호출됩니다.

업데이트 함수에 Time.deltatime을 인수로 넣으면 그들 사이의 거리 *(이전 프레임에서 걸린 시간)만큼 위치 1을 위치 2로 이동합니다.해야 할 일.

Vector3.Lerp(0, 10, 시간.델타타임)

이전 프레임에 걸린 시간을 0.1f라고 가정하면 초당 10프레임, 즉 10fps입니다.

업데이트0 → 위치1 = 0

Update1 → Position1 = 1 // 이전 프레임의 위치(=0)+(둘 사이의 거리(=10)*Time.deltatime(=0.1f))

Update2 → Position1 = 1.9 // 이전 프레임의 위치(=1) + (둘 사이의 거리(=9)*Time.deltatime(=0.1f))

Update3 → 위치 1 = 2.71 // 이전 프레임의 위치(=1.9) + (둘 사이의 거리(=8.1) * Time.deltatime(=0.1f))

업데이트하려면? → 숫자 1 = 숫자 2

결국 위치 1과 2가 일치할 때까지 더 작은 숫자로 증가합니다.

Unity 카메라 플레이어 추적 → Lerp가 필요한 이유

Lerp가 없으면 플레이어가 속도를 높이면 카메라가 순간이동하는 것처럼 보일 수 있습니다. lerp를 사용하면 시작점과 끝점 사이의 중앙값을 찾아 카메라를 보다 부드럽게 이동할 수 있습니다.

Unity Vector3.Lerp()는 무엇입니까?

public class Move : MonoBehaviour
{
    public Transform startPosition;
    public Transform endPosition;
    
    float lerpTime = 0.5f;
    float currentTime = 0;

    void Start()
    {
    	this.transform.position = startPosition.position;
    }

    void Update()
    {
    	// currentTime은 시간 흐름에 따라 증가함
    	currentTime += Time.deltaTime;
        // 이 코드를 넣어주면 0부터 증가하다가 최대 0.5(lerpTime)까지만 증가함
        if (currentTime>=lerpTime)
        {
        	currentTime = lerpTime;
        }
        // 이전에 넣어뒀던 보간값을 t에 저장하고
        float t = currentTime/lerpTime;
        // sine 형태의 계산을 가져온다.
        t = Mathf.Sin(t * Mathf.PI * 0.5f);
        
    	this.transform.position = Vector3.Lerp(startPosition.position, endPosition.position, t);
    }
}

사실 이런건 update 문에 쓰지 않고 별도의 코루틴하나의 코루틴을 만들고 필요한 만큼만 움직이게 하는 것이 좋습니다. update 문에서 사용하면 매 프레임마다 호출되므로 가급적 update 문에서는 사용하지 않는 것이 좋다(자주 사용하면 성능이 저하된다).

위의 GitHub에서 lateUpdate로 전환하는 코드를 작성했고 이유를 확인하기 위해 lateUpdate를 확인했습니다.

Update(), FixedUpdate() 및 LateUpdate()의 차이점 – Developug

  • 업데이트하려면() – 스크립트가 활성화되면 모든 프레임에서 호출됩니다. 가장 많이 사용하는 기능입니다 물리적인 효과, 간단한 타이머, 키 입력 없이 물체의 움직임을 받을 때 사용것이 가능하다.
  • 고정 업데이트() – 프레임 단위로 호출되는 Update와 달리 Fixed Timestep에서 설정한 값에 따라 주기적으로 호출됩니다. rigidbody 객체를 맞출 때 사용(Update는 드물게 호출되므로 물리 엔진의 충돌 검사가 제대로 작동하지 않을 수 있습니다.)
  • 늦은 업데이트() – 모든 업데이트 함수가 호출된 후 마지막으로 호출됩니다. 주로 객체를 따르도록 조정된 카메라는 LateUpdate를 사용합니다.(카메라가 따라가는 물체가 업데이트 기능 내에서 움직일 수 있기 때문입니다.)

Player = GameObject.Find(“플레이어”);

player.transform.position.x 사용

target = GameObject.FindGameObjectWithTag(“플레이어”).transform;

transform.position.x 사용

마지막에 코드가 있습니다

using UnityEngine;

public class CameraController : MonoBehaviour
{
    private Transform target;
    private Vector3 offset;

    float lerpTime = 0.6f;
    float currentTime = 0;

    void Start()
    {
        target = GameObject.FindGameObjectWithTag("Player").transform;
        offset = transform.position - target.position;
    }

    void LateUpdate()
    {
        // currentTime은 시간 흐름에 따라 증가함
        currentTime += Time.deltaTime;
        // 이 코드를 넣어주면 0부터 증가하다가 최대 0.5(lerpTime)까지만 증가함
        if (currentTime >= lerpTime) currentTime = lerpTime;
        float t = currentTime / lerpTime;

        // 플레이어 이동에 따라 변하는 카메라 위치
        Vector3 newPosition = new Vector3(transform.position.x, transform.position.y, offset.z + target.position.z);
        transform.position = Vector3.Lerp(transform.position, newPosition, t);
    }
}

이렇게 하고 나중에 수정이 필요하다고 생각되면 하기로 했습니다.