1. DOTween?
1-1. Tweening
- 시작 시점과 종료 시점을 설정해 위치/회전/크기 등의 값을 조정해 애니메이션을 쉽게 구현하는 기법
- 모션과 비주얼 이펙트를 자연스럽게 동작하도록 한다.
1-2. DOTween
- 유니티 환경에서 트위닝 기능을 지원하는 API
- 내부적으로 최적화 기법을 사용해 유니티가 제공하는 일반적인 애니메이션/Transform 관련 함수/코루틴보다 향상된 성능을 보임
- 성능상의 오버헤드를 줄이기 위해 custom update 함수를 사용한다.
- [TIPS] 결론적으로 쉽고, 빠르므르 애용하자!
using DG.Tweening;
1-3. Tweener
- 객체나 프로퍼티의 값을 조정해 애니메이션을 수행하는 주체
- DO 계열 함수들은 Tweener를 리턴한다.
- DOTween에서 행동의 주체
1-4. Sequence
- 여러 트윈들을 그룹하해서 관리하고 수행하는 주체
- 트윈들의 묶음이라 생각하면 된다.
1-5. Tween
- 트윈과 시퀀스를 통용해서 부르는 명칭
- 트윈 + 시퀀스
1-6. DOTween Component
- DOTween은 다양한 컴포넌트에 적용 가능하다.
- transform
- Material
- Text/TMP
- Camera
- Light
- RigidBody/RigidBody2D
- AudioSource/AudioMixer(Unity5)
- LineRenderer
- SpriteRenderer
- TrailRenderer
- Outline
- [중요]해당 컴포넌트의 모든 속성은 DOTween으로 Tweening 가능하다 알고 있음 편하다.
2. DOTween 함수
2-0. DOTween 기본 설정
2-0-0. DOTween.Init(bool recycle, bool useSafeMode, LogBehaviour logBehaviour, SetCapacity setCapacity)
- DOTween 함수 기본 설정
- 1. recycle: Tweener를 통해 함수 재사용 가능 여부 설정
- 2. useSafeMode: 실행 중, 실행 대상이 파괴되는 등의 예외사항을 자동 처리(성능 감소 but always true)
- 3. logBehaviour: 오류 메세지 기록 설정
- 4. SetCapacity(Tweener 개수, Sequence 개수): Tweener 개수와 Sequence 개수를 설정
DOTween.Init(false, true, LogBehaviour.Verbose).SetCapacity(200, 50);
3. Tween을 만드는 방법
- DOTween에서 Tween은 각 애니메이션을 수행하는 하나의 단위이다.
- 즉, Tween을 통해 각 행동을 수행한다.
- DOTween에서 Tween을 만드는 방식은 TO 계열과 DO 계열이 존재한다.
3-1. TO 계열
- TO 계열 함수는 람다함수 사용법을 자세히 알아야 한다.
- 람다함수를 통해 다양한 값의 트위닝을 수행
### 1. DOTween.To()
DOTween.To(시작값(getter), setter, 결과값, float duration);
DOTween.To(getter, setter, to, float duration);
DOTween.To(()=>myFloat, x=>myFloat = x, 100f, 1);
DOTween.To(()=>myVector, x=>myVector = x, new Vector3(3,4,5), 10);
DOTween.To(()=>1f, x=>transform.position = new Vector3(0, 0, x), 10f, 5f);
DOTween.To(() => "", str => myString = str, "hello, world!", 3);
3-2. DO 계열
- 모든 트위닝 함수에 붙는 접두사
- TO 계열 보다 직관적인 함수
- DO는 대상의 변화를 지시
- 타겟 값과 변화 기간, snap 여부가 인자로 들어감
- Tween 타입을 리턴
- snap 여부를 true로 설정할 경우 부드럽게 움직임
transform.DO-(100[endvalue], 5[duration(seconds)], true[snap])
3-2-1. Move 계열
DOMove(Vector3 targetPos, float duration)
- curPos에서 targetPos로 duration 초 동안 이동
Vector3 targetPos = new Vector3(5, 5, 5);
transform.DOMove(targetPos, 5.0f);
DOLocalMove(Vector3 targetPos, float duration)
- Local 이동으로 curPos에서 targetPos로 duration 초 동안 이동
Vector3 targetPos = new Vector3(5, 5, 5);
transform.DOLocalMove(targetPos, 5.0f);
DOMoveX/Y/Z(float targetPos, float duration)
- curPos에서 특정 축(X/Y/Z)의 좌표가 targetPos가 되도록 duration 초 동안 이동
transform.DOMoveX(5, 5.0f);
transform.DOMoveY(5, 5.0f);
transform.DOMoveZ(5, 5.0f);
DOLocalMoveX/Y/Z(float targetPos, float duration)
- Local 이동으로 curPos에서 특정 축(X/Y/Z)의 좌표가 targetPos가 되도록 duration 초 동안 이동
transform.DOLocalMoveX(5, 5.0f);
transform.DOLocalMoveY(5, 5.0f);
transform.DOLocalMoveZ(5, 5.0f);
3-2-2. Jump 계열
DOJump(Vector3 targetPos, float jumpPower, int jumpNum, float duration)
- curPos에서 targetPos로 duration 초 동안 jumpPower의 힘으로 jumpNum번 점프하며 이동
Vector3 targetPos = new Vector3(5, 5, 5);
transform.DOJump(targetPos, 5.0f, 5, 5.0f);
DOLocalJump(Vector3 targetPos, float jumpPower, int jumpNum, float duration)
- Local 이동으로 curPos에서 targetPos로 duration 초 동안 jumpPower의 힘으로 jumpNum번 점프하며 이동
Vector3 targetPos = new Vector3(5, 5, 5);
transform.DOJump(targetPos, 5.0f, 5, 5.0f);
3-2-3. Rotate 계열
RotateMode
- 1. Fast(default): targetPos가 되도록 360도 미만의 최소 회전 값으로 회전한다.
- 2. FastBeyond360: targetPos가 되도록 360도 이상의 최대 회전 값으로 (여러 바퀴) 회전한다.
- 3. WorldAxisAdd: 월드 좌표계 기준으로 현재 회전값에서 벡터만큼을 더한다.
- 4. LocalAxisAdd: 로컬 기준계 기준으로 현재 회전값에서 벡터만큼을 더한다.
DORotate(Vector3 targetRot, float duration, RotateMode mode)
- Inspector 창에 Rotation 값을 targetRot 값으로 duration초 동안 변경
public Vector3 targetRot = new Vector3(90, 0, 0);
transform.DORotate(targetRot, 5.0f, RotateMode.Fast);
DOLocalRotate(Vector3 targetRot, float duration, RotateMode mode)
- Local 회전으로 Inspector 창에 Rotation 값을 targetRot 값으로 duration초 동안 변경
public Vector3 targetRot = new Vector3(90, 0, 0);
transform.DOLocalRotate(targetRot, 5.0f, RotateMode.Fast);
DORotateQuaternion(Quaternion targetRot, float duration)
- Quaternion 회전 방식으로 현재 Rotation 값을 targetRot 값으로 duration초 동안 변경
transform.DORotateQuaternion(Quaternion.identity, 5.0f);
DOLocalRotateQuaternion(Quaternion targetRot, float duration)
- Local 회전으로 Quaternion 회전 방식으로 현재 Rotation 값을 targetRot 값으로 duration초 동안 변경
- [TIPS] 작은 값을 회전시킬 때, 종료 지점에서 원치않는 흔들림이 발생할 경우 사용
transform.DOLocalRotateQuaternion(Quaternion.identity, 5.0f);
DOLookAt(Vector3 targetRot, float duration, AxisConstraint axisConstraint = AxisConstraints.None, Vector3 up = Vector3.up)
- 물체의 Local 회전으로 Z축(설정 가능)이 해당 targetRot을 정면으로 바라보도록 duration초 동안 변경
public Vector3 targetRot = new Vector3(90, 0, 0);
transform.DOLookAt(targetRot, 5.0f);
DODynamicLookAt(Vector3 targetRot, float duration, AxisConstraint axisConstraint = AxisConstraints.None, Vector3 up = Vector3.up)
- 지속적으로 위치가 변경되는 물체를 추적하기 위해선 본 함수 사용
- 회전 목표를 매 프레임 계산
- 물체의 Local 회전으로 Z축(설정 가능)이 해당 targetRot을 정면으로 바라보도록 duration초 동안 변경
public Vector3 targetRot = new Vector3(90, 0, 0);
transform.DODynamicLookAt(targetRot, 5.0f);
3-2-4. Scale 계열
DOScale(Vector3 targetScale, float duration)
- curScale에서 targetScale로 duration 초 동안 크기 변경
Vector3 targetScale = new Vector3(5, 5, 5);
transform.DOScale(targetScale, 5.0f);
DOScaleX/Y/Z(float targetScale, float duration)
- curScale에서 특정 축(X/Y/Z)의 크기가 targetScale가 되도록 duration 초 동안 크기 변경
transform.DOScaleX(5, 5.0f);
transform.DOScaleY(5, 5.0f);
transform.DOScaleZ(5, 5.0f);
3-2-5. Effect - Punch
- 펀치 한 대 때린 듯 이동/회전/크기 변경을 수행
- punch: punch Vector 방향에서 펀치를 날림(반대편 이동)
- vibrato: 얼마나 진동하는지를 결정
- elaticity(0-1): 탄성 = 진동 범위(진동하는 범위가 어느정도인지 결정)
0: punch Vector와 시작 위치 사이에서만 진동
1: punch Vector의 반대 방향 사이에서만 진동
DOPunchPosition(Vector3 punch, float duration, int vibrato, float elaticity, bool snapping)
transform.DOPunchPosition(targetPos, 5, 10, 1, false);
DOPunchRotation(Vector3 punch, float duration, int vibrato, float elaticity)
transform.DOPunchRotation(targetPos, 5, 10, 1, false);
DOPunchScale(Vector3 punch, float duration, int vibrato, float elaticity)
transform.DOPunchScale(targetPos, 5, 10, 1, false);
3-2-6. Effect - Shake
- 푸딩이 흔들리는 효과를 주며 이동/회전/크기 변경을 수행
- [TIPS] 각종 충돌 시 흔들리는 효과 연출에 사용
- strenth: flaot의 힘으로 진동 / Vector를 사용할 경우, 특정 축에 대한 흔들림**
- vibrato: 얼마나 진동하는지를 결정
- randomness(0-180): 흔들어지는 범위와 규칙성을 결정
- faseOut: 흔들리는 효과가 점차 감소
- randomnessMove: Full(전적으로 랜덤) / Harmonic(조화롭고 시각적으로 아름답게)
DOShakePosition(float duration, float/Vector3 strength, int vibrato, float randomness, bool snapping, bool fadeOut, ShakeRandomnessMode randomnessMode)
transform.DOShakePosition(1, 1, 10, 1, false, true);
transform.DOShakePosition(1, new Vector3(0, 0, 1), 10, 1, false, true);
DOShakeRotation(float duration, float/Vector3 strength, int vibrato, float randomness, bool fadeOut, ShakeRandomnessMode randomnessMode)
transform.DOShakeRotation(1, 1, 10, 1, false, true);
transform.DOShakeRotation(1, new Vector3(0, 0, 1), 10, 1, false, true);
DOShakeScale(float duration, float/Vector3 strength, int vibrato, float randomness, bool fadeOut, ShakeRandomnessMode randomnessMode)
transform.DOShakeScale(1, 1, 10, 1, false, true);
transform.DOShakeScale(1, new Vector3(0, 0, 1), 10, 1, false, true);
3-2-7. Material
- DOColor: 색상(RGB)값 변환
- DOFade: 투명도(Alpha)값 변환
.DOColor(Color to, float duration);
.DOFade(float to, float duration);
3-2-8. Text
- Typing 연출
- Fade IN&Out 연출
- Color 연출
.DOText(string to, float duration, bool richTextEnabled = true, ScrambleMode scrambleMode = ScrambleMode.None, string scrambleChars = null);
.DOColor(Color to, float duration);
.DOFade(float to, float duration);
3-2-9. [번외]
- 번외 기능 정리(나중에 공부 or 문서보고 개발)
- DOPath 계열(DOPath, DOLocalPath)
- Blendable 계열(DOBlendable[Move/LocalMove/Rotate/LocalRotate/Scale]By)
- [Pro Only]DOSpiral
4. Set
- Set은 Tween에 대한 설정을 수행
- SET은 변화의 방식을 설정
Tween.Set-(...);
transform.DOScale(1.5f, 1.0f).SetLoops(3, LoopType.Restart);
- SET은 여러 개를 한번에 설정하는 것이 가능하다.
transform.DOScale(1.5f, 1.0f)
.SetLoops(3, LoopType.Restart)
.SetId(1)
.SetEase(Ease.-)
.SetAutoKill(false);
SetAs(Tween tween, TweenParams tweenParams)
- 설정 값을 빠르게 적용하도록 해줌
- TweenParams 타입에 Set 값을 저장해넣고, 인자로 이를 넣어 적용
TweenParams tweenParams = new TweenParams()
.SetDelay(1)
.SetEase(Ease.Linear)
.SetRelative()
.SetSpeedBased();
object1.DOLocalMoveX(100,100).SetAs(tweenParams);
object2.DOLocalMoveX(200,200).SetAs(tweenParams);
object3.DOLocalMoveX(300,300).SetAs(tweenParams);
SetAutoKill(bool autoKillOnCompletion = true)
- DOTween은 사용이 완료된 Tween을 자동으로 Kill해 메모리에서 해제
- 즉, Garbage가 생성되고, 쌓이면, Garbage Collector가 작동하며 프레임이 끊길 수 있다.
- AutoKill 기능을 꺼 영구적으로 메모리에 영구적으로 적재하고, Tweener 변수에 할당해 재사용한다.
- 이를 통해 메모리 관리 측면에서 이득을 볼 수 있음
Tweener tr1 = transform.DOScale(1.5f, 2.0f).SetEase(Ease.InBounce).SetAutoKill(false);
SetEase(Ease easeType, AnimationCurve animCurve, EaseFunction customEase)
- Ease: 변환 시, 움직임의 부드러움, 다양함을 주기 위해 사용하는 시간당 변화량 그래프를 의미한다.
- 변화의 정도를 움직임에 적용하는 것
- [TIPS] 제공하는 종류가 많아 헷갈리기 때문에, public Ease 변수를 선언하고 Inspector 창에서 설정하며 테스트하는 것이 좋다.
- 기본값 = Ease.Unset
- 강도: Sine < Quad < Cubic < Quart < Quint < Expo
- In: 변화가 처음에 시작됨
- Out: 변화가 끝에 시작됨
- InOut: 번화가 양쪽에서 시작됨
box.DOLocalMoveX(400, 1).SetEase(Ease.Linear);
SetId(object id)
- 특정 ID로 제어
- Tween or Sequence에 특정 id를 부여
- id를 통해 static 함수 등으로 제어
circle.DOLocalMoveX(0, 1).SetId("circleTween");
DOTween.Kill("circleTween");
box.DOLocalMoveX(200, 1).SetId(1);
DOTween.Rewind(1);
SetLink(GameObject target, LinkBehaviour linkBehaviour = LinkBehaviour.KillOnDestroy)
- Tween or Sequence를 타겟 게임 오브젝트에 연결해 오브젝트의 상태 변화에 따라 트윈을 제어하게 해줌
ex) 오브젝트가 SetActive(true)될 때마다 Tween을 재실행하는 LinkBehaviour 설정
한 Tween or Sequence가 끝나면 AutoKill이 작동하기 때문에 이 기능을 꺼야함
Sequence mySequence = DOTween.Sequence()
.SetAutoKill(false)
.SetLink(Objects, LinkBehaviour.RestartOnEnable)
.Join(circle.DOLocalMoveX(200, 1))
.Join(box.DOLocalMoveX(200, 1));
SetLoops(int loops, LoopType loopType = LoopType.Restart)
- loops: 반복 회수(-1이면 무한루프)
- LoopType = Incremental: 종료된 시점을 시작 지점으로 모션을 다시 시작(연속)
- LoopType = Restart: 처음 시작 지점으로 되돌아가서 모션을 다시 시작
- LoopType = Yoyo: 실행된 모션이 되감기되며 다시 시작(#반복 회수는 돌아가는 모션 포함)
box.DOLocalMoveX(200, 1).SetLoops(-1, LoopType.Restart);
SetRecyclable(bool recyclable)
- Tween이 종료되어도 Kill 되지 않도록 설정
- 변수에 할당할 때 사용
Tweener tr1 = transform.DOMoveX(4, 1).SetRecyclable(true);
SetDelay(float delay, bool asPrependedIntervalIfSequence = false)
- Tweener or Sequence가 실행되는 시간을 dalay초 만큼 지연
- asPrependedIntervalIfSequence는 Sequence에만 사용 가능하고, 각 Tweener마다 delay를 줄지 설정
transform.DOMoveX(4, 1).SetDelay(2.0f);
SetRelative(bool isRelative = true)
- 상대값 설정
- 절대 좌표가 아닌 상대 좌표으로 변환할 수 있는 설정
circle.DOLocalMoveX(200, 1f);
box.DOLocalMoveX(200, 1f).SetRelative();
SetSpeedBased
- 속력 기준 설정
- duration이 distance로 변모
- 같은 속력(distance/1초)으로 일정 거리를 이동
circle.DOLocalMoveX(200, 200).SetRelative().SetSpeedBased();
box.DOLocalMoveX(400, 200).SetRelative().SetSpeedBased();
SetUpdate(UpdateType updateType, bool isIndependentUpdate = false)
- 메인메뉴 or 일시정지 등에 Time.timeScale = 0이 사용됨
- Time.deltaTime과 관련된 모든 함수들의 작동을 멈춤
- but .SetUpdate(true)를 통해 Time.timeScale = 0인 상황에도 움직이도록 설정 가능
- UpdateType - Normal: Update
- UpdateType - Late: Late Update
- UpdateType - Fixed: Fixed Update
- UpdateType - Manual: DOTween Custom Update 사용
transform.DOMoveX(4, 1).SetUpdate(UpdateType.Late, true);
5. On
- 모션의 특정 상황에서 원하는 함수를 호출하는 콜백 기능
OnComplete(TweenCallback callback)
transform.DOMoveX(4, 1).OnComplete(MyCallback);
OnKill(TweenCallback callback)
transform.DOMoveX(4, 1).OnKill(MyCallback);
OnPlay(TweenCallback callback)
transform.DOMoveX(4, 1).OnPlay(MyCallback);
OnPause(TweenCallback callback)
transform.DOMoveX(4, 1).OnPause(MyCallback);
OnRewind(TweenCallback callback)
transform.DOMoveX(4, 1).OnRewind(MyCallback);
OnStart(TweenCallback callback)
transform.DOMoveX(4, 1).OnStart(MyCallback);
OnStepComplete(TweenCallback callback)
- 각 Loop마다 Complete될 때, 자동 호출
transform.DOMoveX(4, 1).OnStepComplete(MyCallback);
OnUpdate(TweenCallback callback)
- Tween이 업데이트되는 매 프레임마다 자동 호출
transform.DOMoveX(4, 1).OnUpdate(MyCallback);
OnWaypointChange(TweenCallback<int>
callback)
- Tween이 waypoint에 도달했을 때, 자동 호출
transform.DOMoveX(4, 1).OnWaypointChange(MyCallback);
On Call Back 사용법
- 단순 사용법(콜백함수(Preb))만을 넣어준다.
- 람다 함수를 통해 함수 객체를 직접 넣어준다.
transform.DOMove(targetPosition, 3).OnComplete(GetTarget);
myTween.OnStart(()=>{
});
myTween.OnComplete(()=>{
});
myTween.OnUpdate(()=>{
});
transform.DOScale(Vector3.zero, 1).OnComplete(() => gameObject.SetActive(false));
6. Sequence
- Tweener들의 모임
- 다른 Tweener들을 제어하고, 그룹으로 애니메이션을 적용
6-1 Sequence 선언
Sequence sequence = new Sequence();
Tween tr1 = transform.DOMove(targetPos, 1.0f).SetEase(Ease.Flash).SetDelay(1.0f).SetLoops(3).OnComplete(()=> Debug.Log("Completed"));
Tween tr2 = transform.DORotate(targetPos, 1.0f).SetEase(Ease.InBack).SetDelay(1.0f).SetLoops(3).OnComplete(() => Debug.Log("Completed"));
Tween tr3 = transform.DOScale(targetPos, 1.0f).SetEase(Ease.InBounce).SetDelay(1.0f).SetLoops(3).OnComplete(()=> Debug.Log("Completed"));
Tween tr4 = transform.DOLocalMove(targetPos, 1.0f).SetEase(Ease.InCirc).SetDelay(1.0f).SetLoops(3).OnComplete(()=> Debug.Log("Completed"));
6-2 Sequence 관리
6-2-1 Append
sequence.Append(tr1);
6-2-2 Insert(float time, Tweener target)
- (현재 시간 기준) 삽입을 원하는 특정 시간(time)에 트윈(target) 추가
sequence.Insert(5.0f, tr3);
6-2-3 Join
- 현재 시퀀스의 마지막 트윈과 인자로 입력된 시퀀스를 묶음(동시 실행)
sequence.Join(tr2);
6-2-4 Prepend
sequence.Prepend(tr4);
6-2-5 동시 사용
- Sequence 명령어를 한번에 선언하는 것도 가능
sequence.Append(tr1)
.Insert(5.0f, tr3)
.Join(tr2)
.Prepend(tr4);