안녕하세요! 스파르타내일배움캠프에서 진행된 김지웅 튜터님의 DOTween 특강 내용을 개인적으로 학습하며 정리한 포스트입니다. 강의의 녹취록을 기반으로 오탈자를 수정하고, 내용을 구조화하여 다시 정리했습니다.
DOTween을 처음 접하시거나, 강의 내용을 복습하고 싶으신 분들께 도움이 되기를 바랍니다.
📚 강의 내용 섹션별 요약
인트로: 트위닝(Tweening)이란?
시작과 끝 사이를 부드럽게 보간하여 애니메이션을 만드는 기법. 코루틴보다 간편함.
보간(Interpolation)과 외삽(Extrapolation) 소개
트위닝은 주로 범위 내의 중간 값을 추정하는 보간 원리를 사용함.
DOTween 에셋 소개 및 설정
강력하고 직관적인 유니티 트위닝 라이브러리. Setup을 통해 간편하게 설정.
핵심 기능 실습
DoMove, DoRotate, DoScale, DoJump, DoShake 등 직관적인 메서드로 다양한 움직임 구현.
트윈 제어 및 고급 옵션 (메서드 체이닝)
.Kill()로 트윈 중지, .SetEase()로 가속도 조절, .SetLoops()로 반복, .OnComplete()로 콜백 지정.
UI와 코루틴에서의 활용
DoFade, DOTween.To 등으로 UI 애니메이션을 쉽게 구현하고, WaitForCompletion()으로 코루틴과 동기화.
심화: 플루언트 메서드 체이닝 구현 원리
메서드의 반환 타입을 자기 자신 클래스로 만들어 가독성 높은 코드를 작성하는 기법.
이상으로 DOTween 특강 내용 정리를 마칩니다. 읽어주셔서 감사합니다!
트위닝(Tweening)은 '인비트위닝(In-betweening)'을 줄여서 부르는 말입니다. 시작 값과 목표 값 사이의 중간 값들을 자동으로 계산해서, 자연스럽고 부드러운 애니메이션을 생성하는 기법입니다.
게임은 프레임 단위로 움직이기 때문에, 이 프레임이 바뀌는 동안 게임 오브젝트의 움직임이나 변수 값, 상태 값을 부드럽게 바꾸고 싶을 때 주로 사용됩니다.
과거 코루틴 세션에서 Vector3.Lerp
를 이용해 오브젝트를 부드럽게 이동시키는 함수를 만들었었습니다.
// 코루틴 내에서 Lerp를 사용한 이동 예시
float elapsedTime = 0f;
float duration = 3f;
Vector3 startPosition = transform.position;
Vector3 endPosition = new Vector3(5, 0, 0);
while (elapsedTime < duration)
{
float t = elapsedTime / duration;
transform.position = Vector3.Lerp(startPosition, endPosition, t);
elapsedTime += Time.deltaTime;
yield return null;
}
transform.position = endPosition; // 이동 완료 보정
하지만 사실 코루틴을 이용하는 것보다, 이런 간단한 움직임은 트윈을 이용해 구현하는 것이 훨씬 편합니다.
트위닝의 기반이 되는 두 가지 수학적 개념입니다.
보간(Interpolation): 주어진 데이터 구간 내에서 중간 값을 추정하는 것입니다. (A -> B로 가는 중간 과정)
외삽(Extrapolation): 주어진 데이터 범위를 벗어나는 값을 예측할 때 사용합니다. (A와 B의 움직임을 보고 그 이전이나 이후의 위치를 예측)
게임 개발에서 외삽은 3인칭 카메라가 플레이어의 이동 방향을 살짝 앞서 비추거나, 네트워크 지연 속에서도 다른 플레이어의 움직임을 부드럽게 예측하여 보여줄 때 사용됩니다.
우리가 오늘 다룰 트위닝은 주로 보간의 개념을 사용합니다.
오늘 실습할 'DOTween'은 유니티 개발자들이 표준처럼 사용하는 매우 강력하고 직관적인 트위닝 라이브러리입니다.
에셋 스토어에서 DOTween (무료 버전)을 검색하여 임포트합니다.
임포트 후 나타나는 패널(또는 Tools > Demigiant > DOTween Utility Panel)에서 Setup DOTween 버튼을 클릭합니다.
모든 모듈을 체크하고 Apply를 눌러 설정을 완료합니다.
스크립트 상단에 using DG.Tweening;을 추가하는 것을 잊지 마세요!
DoMove (이동): transform.DoMove(목표위치, 시간);
지정한 시간 동안 목표 위치까지 부드럽게 이동합니다.
DoRotate (회전): transform.DoRotate(목표회전값, 시간, RotateMode);
RotateMode 옵션으로 최단 거리 회전(Fast), 360도 초과 회전(FastBeyond360) 등을 설정할 수 있습니다.
DoScale (크기 조절): transform.DoScale(목표크기, 시간);
지정한 시간 동안 목표 크기로 부드럽게 변경됩니다.
DoJump (점프): transform.DoJump(목표위치, 점프높이, 점프횟수, 시간);
통통 튀는 점프 움직임을 쉽게 구현할 수 있습니다. 아이템 드랍 연출 등에 유용합니다.
DoShake (흔들기): transform.DoShakePosition(시간, 강도, 진동횟수);
카메라를 흔들어 화면 진동 효과를 만드는 등 다양하게 활용됩니다.
DOTween의 가장 강력한 기능은 메서드 체이닝(Method Chaining)으로 여러 옵션을 점(.)으로 연결하여 설정하는 것입니다.
트윈 중지 및 재사용: DoMove 같은 함수는 'Tween' 객체를 반환합니다.
Tween myTween = transform.DOMoveX(5, 2);
// 필요할 때 아래 코드로 트윈을 즉시 중지시킬 수 있습니다.
myTween.Kill();
고급 설정 예시:
transform.DOMove(new Vector3(5, 5, 0), 2f)
.SetEase(Ease.OutBounce) // 움직임의 가속도 조절 (끝에서 튕기는 효과)
.SetLoops(-1, LoopType.Yoyo) // 무한 반복 (왔다 갔다)
.OnComplete(() => { // 트윈이 완료되면 실행할 내용
Debug.Log("이동 완료!");
});
.SetEase(): Ease.Linear(등속), Ease.InSine(부드럽게 시작) 등 다양한 가속도 곡선을 제공합니다.
.SetLoops(): 반복 횟수와 방식(Restart, Yoyo)을 지정합니다. -1은 무한 반복입니다.
.SetSpeedBased(): 시간을 속도의 개념으로 바꿉니다.
.OnComplete(): 트윈 완료 시 실행할 함수(콜백)를 지정합니다. OnStart, OnUpdate 등도 있습니다.
DoFade (투명도 조절): Image.DOFade(목표투명도, 시간);
UI가 부드럽게 나타나거나 사라지는 효과를 쉽게 만들 수 있습니다.
DOTween.To (범용 트윈): DOTween.To(() => 현재값, x => 현재값 = x, 목표값, 시간);
숫자, 벡터뿐만 아니라 텍스트(string) 등 거의 모든 타입을 변화시킬 수 있습니다.
타이핑 효과 예시:
string targetText = "안녕하세요. DOTween입니다.";
myText.text = ""; // 텍스트 초기화
DOTween.To(() => myText.text, x => myText.text = x, targetText, 2f)
.SetEase(Ease.Linear); // 글자별 속도를 일정하게
코루틴 내에서 트윈이 끝날 때까지 기다려야 할 때, WaitForCompletion()을 사용합니다.
public IEnumerator MyRoutine()
{
Debug.Log("점프 시작!");
Tween jumpTween = transform.DOJump(Vector3.zero, 1, 1, 1f);
yield return jumpTween.WaitForCompletion(); // 점프가 끝날 때까지 대기
Debug.Log("점프 완료!");
}
DOTween처럼 메서드를 계속 연결해서 사용하는 방식의 핵심 원리는 메서드의 반환 타입을 자기 자신 클래스로 지정하는 것입니다.
public class Monster
{
// 반환 타입을 void가 아닌 Monster로 지정
public Monster SetPosition(Vector3 pos)
{
transform.position = pos;
return this; // 자기 자신(인스턴스)을 반환
}
public Monster SetScale(Vector3 scale)
{
transform.localScale = scale;
return this;
}
}
// 이렇게 사용 가능
Monster monster = new Monster();
monster.SetPosition(Vector3.zero).SetScale(Vector3.one * 2);
이러한 방식은 코드의 가독성을 높여주며, 빌더 패턴(Builder Pattern) 등에서 유용하게 사용됩니다.