Unity/Study

유니티 Spline의 정규 값을 통해 World Position값 얻어내기 #다른 Spline으로 자연스럽게 이동시키고 싶을 때

VR하는소년 2024. 9. 27. 08:00

Spline이란?

Spline은 곡선을 나타내기 위한 수학적 표현으로, 객체를 경로를 따라 이동시킬 때 사용됩니다. 

스플라인의 기본 개념은 여러 제어점(Control Points)을 이용해 곡선을 만들어 내고, 곡선을 따라 객체가 움직이도록 하는 것입니다. 곡선은 정규화 값(normalized value), 즉 0에서 1까지의 값을 사용해 스플라인 상의 특정 위치를 계산할 수 있습니다.

 

정규화 값이 0이면 스플라인의 시작점, 1이면 끝점을 나타냅니다. 


Spline의 특정 위치를 계산하기

public Vector3 GetPositionOnSpline(int splineIndex, float normalizedPosition)
{
	//spline Index : 얻고자 하는 Spline
    if (splineIndex >= 0 && splineIndex < splineContainers.Count)
    {
        SplineContainer splineContainer = splineContainers[splineIndex];
        Spline spline = splineContainer.Spline;

        Vector3 localPosition = spline.EvaluatePosition(normalizedPosition);
        Vector3 worldPosition = splineContainer.transform.TransformPoint(localPosition);
        return worldPosition;
    }
    else
    {
        Debug.LogError("Spline index out of range.");
        return Vector3.zero;
    }
}

 

핵심함수는 EvaluatePosition입니다.

 

EvaluatePosition 함수는 Spline 시스템에서 제공하는 함수로, 스플라인의 특정 정규화된 위치(0에서 1 사이의 값)에 해당하는 로컬 좌표(Local Position)를 반환하는 역할을 합니다. 


다른 스플라인으로 자연스럽게 이동해보기

using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Splines;

public class SplineHandler : MonoBehaviour
{
    public SplineAnimate splineAnimator;
    public List<SplineContainer> splineContainers;
    
    [Header("Start lane")]
    [SerializeField, Tooltip("Index + 1이 Lane Num에 속함(Ex.Index : 1-> Lane 2)")] 
    private int currentSplineIndex = 1;

    private void Start()
    {
        splineAnimator.Container = splineContainers[currentSplineIndex];
        Play();
    }

    public void SetSplineContainer(int index, float startOffset = 0f)
    {
        if (index >= 0 && index < splineContainers.Count)
        {
            splineAnimator.Container = splineContainers[index];
            splineAnimator.StartOffset = startOffset;
        }
        else
        {
            Debug.LogError("Spline index out of range.");
        }
    }

  
    public void Play()
    {
        splineAnimator.Play();
    }

    public void Restart(bool isFromStart = true)
    {
        splineAnimator.Restart(isFromStart);
    }

    public void Pause()
    {
        splineAnimator.Pause();
    }

   
    public async UniTask SmoothTransition(int targetSplineIndex, float normalizedPosition, float duration)
    {
        Pause();

        var targetPosition = GetPositionOnSpline(targetSplineIndex, normalizedPosition);

        if (targetSplineIndex < 0 || targetSplineIndex >= splineContainers.Count)
        {
            Debug.LogError("Spline index out of range.");
            return;
        }

        SplineContainer currentSpline = splineAnimator.Container;
        SplineContainer targetSpline = splineContainers[targetSplineIndex];

        float elapsedTime = 0f;
        Vector3 initialPosition = transform.position;

        while (elapsedTime < duration)
        {
            elapsedTime += Time.deltaTime;
            float t = Mathf.Clamp01(elapsedTime / duration);

            transform.position = Vector3.Lerp(initialPosition, targetPosition, t);

            await UniTask.Yield();
        }

        transform.position = targetPosition;
        SetSplineContainer(targetSplineIndex, normalizedPosition);
        Restart(); 
    }

    public Vector3 GetPositionOnSpline(int splineIndex, float normalizedPosition)
    {
        if (splineIndex >= 0 && splineIndex < splineContainers.Count)
        {
            SplineContainer splineContainer = splineContainers[splineIndex];
            Spline spline = splineContainer.Spline;

            Vector3 localPosition = spline.EvaluatePosition(normalizedPosition);
            Vector3 worldPosition = splineContainer.transform.TransformPoint(localPosition);
            return worldPosition;
        }
        else
        {
            Debug.LogError("Spline index out of range.");
            return Vector3.zero;
        }
    }
}

 

이 코드는 UniTask를 활용합니다.

 

유니티 코루틴 대신 unitask

유니티에서 unitask를 사용하기 앞서, 유니티에서 사용하는 코루틴이 무엇인지 알아야 진정한 unitask의 장점을 알 수 있습니다.지피지기 백전불태 그렇기에 유니티에 기본적으로 내장되어 있는

wlsdn629.tistory.com

위 포스팅을 참고해주세요.