목차
유니티에서 곡선 이동과 가속도 제어: 베지어 곡선과 스플라인의 고급 활용법
게임 개발에서 캐릭터나 오브젝트의 부드러운 이동 경로를 구현하는 일은 유저 경험에 큰 영향을 미칩니다. 특히 비행, 탈 것 게임, 캐릭터 회피 동작 등에서 직선이 아닌 곡선 경로를 따라 이동해야 하는 경우가 많습니다. 이를 위해 많이 사용하는 수학적 개념이 베지어 곡선과 **스플라인(Spline)**입니다. 이 글에서는 유니티를 사용해 곡선 경로를 생성하고 이를 따라 이동하는 방식, 가속도 조절을 포함한 고급 활용법까지 다뤄 보겠습니다.
1. 기본 개념: 베지어 곡선과 스플라인이란?
베지어 곡선은 주로 2D 그래픽 디자인과 3D 애니메이션에서 사용되는 곡선으로, 두 개 이상의 제어점을 기반으로 부드러운 곡선을 만들어 냅니다. 유니티에서는 베지어 곡선을 간단한 수학식을 통해 구현할 수 있으며, 특히 이차 및 삼차 베지어 곡선이 많이 쓰입니다.
**스플라인(Spline)**은 주로 다중 곡선을 연결하여 좀 더 복잡한 경로를 생성하는데 쓰입니다. 스플라인은 여러 베지어 곡선을 이어 붙여 만든 경로라 할 수 있으며, 게임에서 캐릭터나 오브젝트가 특정 경로를 따라 이동하도록 설계할 때 유용합니다.
2. 유니티에서 이차 베지어 곡선 구현하기
간단한 예시로 이차 베지어 곡선을 구현해 보겠습니다. 이차 베지어 곡선은 시작점, 끝점, 그리고 중간 제어점을 사용해 곡선을 생성합니다.
예시 코드: 이차 베지어 곡선
using UnityEngine;
public class QuadraticBezier : MonoBehaviour
{
public Transform startPoint;
public Transform controlPoint;
public Transform endPoint;
public float duration = 2.0f; // 이동 시간
private float elapsedTime = 0f;
void Update()
{
elapsedTime += Time.deltaTime;
float t = elapsedTime / duration; // 0에서 1까지 비율 계산
if (t > 1f) t = 1f;
transform.position = CalculateQuadraticBezierPoint(t, startPoint.position, controlPoint.position, endPoint.position);
}
Vector3 CalculateQuadraticBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
{
// (1-t)^2 * P0 + 2 * (1-t) * t * P1 + t^2 * P2
float u = 1 - t;
return u * u * p0 + 2 * u * t * p1 + t * t * p2;
}
}
코드 설명
CalculateQuadraticBezierPoint
메서드는 이차 베지어 곡선 수식을 구현한 함수로,t
값을 사용해 시작점에서 끝점까지 부드럽게 이동할 수 있습니다.Update
메서드에서t
값을 0에서 1까지 증가시키며,transform.position
을 곡선에 따라 이동시키도록 합니다.
이 코드는 간단한 곡선 이동을 구현할 때 유용하며, 이차 곡선이라서 경로가 단순할 경우에 적합합니다. 단, 경로가 복잡한 경우에는 스플라인을 활용해야 더 효과적입니다.
3. 고급 구현: 스플라인 경로 따라가기
스플라인을 사용하면 다수의 경로를 부드럽게 이어 붙일 수 있습니다. 다음 예시에서는 여러 개의 베지어 곡선을 연결해 스플라인을 만들고, 이를 따라 이동하는 캐릭터를 구현해 보겠습니다.
예시 코드: 스플라인 경로
using UnityEngine;
using System.Collections.Generic;
public class SplinePath : MonoBehaviour
{
public List<Transform> controlPoints; // 경로의 제어점들
public float duration = 5.0f; // 전체 경로 이동 시간
private int segmentCount; // 스플라인 세그먼트 개수
private float elapsedTime = 0f;
void Start()
{
segmentCount = controlPoints.Count - 1;
}
void Update()
{
elapsedTime += Time.deltaTime;
float t = elapsedTime / duration;
if (t > 1f) t = 1f;
transform.position = CalculateSplinePoint(t);
}
Vector3 CalculateSplinePoint(float t)
{
int segmentIndex = Mathf.FloorToInt(t * segmentCount); // 현재 위치한 세그먼트 인덱스
float localT = (t * segmentCount) - segmentIndex; // 세그먼트 내에서의 상대 위치
Vector3 p0 = controlPoints[segmentIndex].position;
Vector3 p1 = controlPoints[segmentIndex + 1].position;
Vector3 p2 = (segmentIndex + 2 < controlPoints.Count) ? controlPoints[segmentIndex + 2].position : p1;
// 두 개의 베지어 곡선 연결하여 스플라인 생성
Vector3 A = Vector3.Lerp(p0, p1, localT);
Vector3 B = Vector3.Lerp(p1, p2, localT);
return Vector3.Lerp(A, B, localT);
}
}
코드 설명
CalculateSplinePoint
메서드는 특정t
값을 이용해 스플라인 경로 상의 위치를 계산합니다. 각 제어점 사이의 세그먼트를 기반으로, 로컬 좌표localT
를 통해 경로를 부드럽게 연결합니다.Update
메서드는t
를 0에서 1까지 증가시키며, 캐릭터가 전체 스플라인 경로를 따라 이동하도록 합니다.
4. 응용: 가속도 적용과 자연스러운 곡선 이동
여기서 한 단계 더 나아가, 가속도를 적용하여 캐릭터가 일정 속도로만 이동하지 않고 점차 가속하거나 감속할 수 있도록 해보겠습니다. 이를 위해선 t
값을 비선형으로 조정하는 방법이 있습니다. t
의 증가 속도를 점진적으로 변화시키면 가속과 감속을 표현할 수 있습니다.
예시 코드: 가속도 적용된 스플라인 이동
using UnityEngine;
public class AcceleratedSplinePath : SplinePath
{
public AnimationCurve speedCurve; // 속도 조절을 위한 애니메이션 곡선
void Update()
{
elapsedTime += Time.deltaTime;
float normalizedTime = elapsedTime / duration;
// speedCurve를 통해 비선형 t값 계산
float t = speedCurve.Evaluate(normalizedTime);
if (t > 1f) t = 1f;
transform.position = CalculateSplinePoint(t);
}
}
코드 설명
speedCurve
는AnimationCurve
를 사용하여 속도를 가감속할 수 있도록 합니다. 예를 들어, S-커브를 사용하면 천천히 출발하여 빠르게 가속한 후 도착 지점에서 서서히 감속하는 경로를 구현할 수 있습니다.Update
메서드에서speedCurve.Evaluate()
를 사용하여t
값을 조절하여 가속도를 조절합니다.
마무리
이와 같은 곡선 경로와 가속도 조절을 활용하면 캐릭터의 움직임이 훨씬 자연스러워지며, 게임 내 몰입감을 높일 수 있습니다. 이 방식은 유니티에서 곡선 이동을 손쉽게 구현할 수 있을 뿐만 아니라, 다양한 응용을 통해 더욱 정교한 경로 이동을 가능하게 합니다.