안녕하세요. 인텔리원스튜디오(IntelliOneStudio)입니다.
이번 시간에는 Unity에서 DOTween을 활용해 화면 상의 보상 아이템(젬)을 목표 지점으로 이동시키는 연출 효과를 구현하는 방법을 알아보겠습니다. GemMover 스크립트를 중심으로, 여러 개의 젬을 생성하고 일련의 애니메이션을 적용하여 자연스럽게 움직이는 연출을 구현하는 방법을 소개해 드릴게요.
이 스크립트를 통해 보상을 획득할 때 시각적 효과를 극대화하고, 플레이어에게 성취감을 높일 수 있습니다. 단계별로 필요한 코드와 설명을 함께 제공하니, 프로젝트에서 바로 적용해 보세요.
2024.11.14 - [분류 전체보기] - [외워라!창고] 챗GPT를 활용해서 개발한 두 번째 게임을 여러분께 소개합니다!
창고에 물건을 보관하면 더이상 보여주지 않고, 오로지 당신의 기억력으로 찾아야해요.
날이 갈수록 늘어나는 상품들과 주문에도 정확하고 빠르게 물건을 찾아 배송해야해요.
과연 당신은 며칠까지 버틸수 있을까요?
당신의 기억력을 시험해봐요. 지금 다운로드하세요.
[아이폰 앱스토어 다운로드]
https://apps.apple.com/kr/app/%EC%99%B8%EC%9B%8C%EB%9D%BC%EC%B0%BD%EA%B3%A0/id6737766088
[구글 플레이 다운로드]
https://play.google.com/store/apps/details?id=com.intellione.warehousedelivery
저희가 챗GPT를 활용해서 개발한 첫 번째 게임을 여러분께 소개합니다! 이 게임은 챗GPT의 놀라운 AI 기능을 활용해 개발했어요. 즐거움이 가득한 이번 게임은, 챗GPT를 활용해서 누구든지 게임을 재미있게 만들 수 있다는 것을 보여줄 거에요.
* APP Store 에서 다운로드
https://apps.apple.com/kr/app/%EB%86%8D%EB%B6%80%EC%9D%98-%EA%BF%88/id6479183930
*Google Play 에서 다운로드
https://play.google.com/store/apps/details?id=com.intellione.farmersfirstdream&pcampaignid=web_share
아래와 같이 ChatGPT에게 질문했어요.
※ ChatGPT 답변 내용 중 제가 별도로 표시한 굵은 글씨를 기준으로 읽으시면 좀 더 이해가 쉽게 될 거예요.
[질문]
안녕, ChatGPT. Unity에서 DOTween을 사용하여 젬 같은 아이템을 화면 상에서 움직이는 연출을 구현하고 싶어. GemMover 스크립트를 작성했는데, 어떻게 동작하는지 자세히 설명해 줄 수 있어?
[답변]
안녕하세요! GemMover 스크립트를 통해 Unity에서 젬과 같은 아이템을 DOTween을 활용해 이동시키고 연출하는 방법을 단계별로 설명해 드릴게요.
1. 싱글턴 패턴을 통한 인스턴스 관리
public static GemMover Instance { get; private set; }
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
if (canvas == null)
{
canvas = FindObjectOfType<Canvas>();
}
}
설명:
- 싱글턴 패턴을 사용하여 GemMover의 인스턴스를 어디서든 접근할 수 있게 합니다.
- canvas를 찾지 않았을 경우 FindObjectOfType<Canvas>()로 동적으로 할당합니다.
2. 젬 이동 구현 (MoveGems)
public IEnumerator MoveGems(int gemCount, Vector3 customStartPosition)
{
List<bool> tweensCompleted = new List<bool>();
for (int i = 0; i < gemCount; i++)
{
Vector3 spawnPosition = customStartPosition;
// 젬 생성
GameObject gem = Instantiate(gemPrefab, spawnPosition, Quaternion.identity, canvas.transform);
tweensCompleted.Add(false);
float delay = i * 0.1f;
int tweenIndex = i;
// 젬 생성 시 크기를 2배로 했다가 원래 크기로 줄이는 애니메이션
gem.transform.localScale = Vector3.one * 2f;
Sequence gemSequence = DOTween.Sequence();
gemSequence.Append(gem.transform.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack))
.AppendInterval(delay)
.AppendCallback(() =>
{
// 젬 이동 사운드 재생
audioSource.PlayOneShot(gemMoveClip);
})
.Append(gem.transform.DOMove(targetTransform.position, 0.5f)
.SetEase(Ease.InOutQuad)
.OnComplete(() =>
{
Destroy(gem); // 젬 제거
tweensCompleted[tweenIndex] = true;
}));
// 모든 젬 이동이 끝날 때까지 대기
yield return new WaitUntil(() => tweensCompleted.TrueForAll(completed => completed));
}
}
설명:
- MoveGems() 코루틴에서는 지정한 개수(gemCount)만큼의 젬을 순차적으로 생성하고 이동시킵니다.
- 생성 직후 젬 크기를 2배로 키운 뒤, 서서히 원래 크기로 줄이는 애니메이션을 적용합니다.
- 일정 딜레이(delay) 후 젬을 targetTransform 위치로 이동시키며, 이동 시 사운드를 재생합니다.
- 젬이 목표 지점에 도달하면 제거하고, 모든 젬이 완료될 때까지 대기합니다.
3. 랜덤 오프셋 및 빠른 이동 구현 (MoveGemsWithEffects)
public IEnumerator MoveGemsWithEffects(int gemCount, Vector3 customStartPosition)
{
List<GameObject> gemObjects = new List<GameObject>();
List<bool> tweensCompleted = new List<bool>();
audioSource.PlayOneShot(gemMoveClip);
for (int i = 0; i < gemCount; i++)
{
// 랜덤 오프셋 적용
Vector3 offset = Random.insideUnitCircle * 0.5f;
Vector3 spawnPosition = customStartPosition + offset;
// 젬 생성
GameObject gem = Instantiate(gemPrefab, spawnPosition, Quaternion.identity, canvas.transform);
gemObjects.Add(gem);
tweensCompleted.Add(false);
float delay = i * 0.05f;
int tweenIndex = i;
gem.transform.DOMove(targetTransform.position, 1.0f)
.SetEase(Ease.InOutQuad)
.SetDelay(delay)
.OnComplete(() =>
{
Destroy(gem);
tweensCompleted[tweenIndex] = true;
});
}
// 모든 젬 이동 완료까지 대기
yield return new WaitUntil(() => tweensCompleted.TrueForAll(completed => completed));
}
설명:
- MoveGemsWithEffects()에서는 젬 생성 시 약간의 랜덤 오프셋을 적용하여 더욱 자연스러운 연출을 만듭니다.
- 젬을 1초 동안 천천히 목표 지점으로 이동시키며, 이동 전 사운드를 재생합니다.
- 모든 젬 이동이 완료될 때까지 WaitUntil()로 대기합니다.
4. 동작 흐름 정리
- 젬 생성: Instantiate를 통해 캔버스 상에서 젬을 생성합니다.
- DOTween 애니메이션:
- 크기 변환(확대/축소), 위치 이동, 딜레이 등 다양한 애니메이션 시퀀스를 DOTween으로 구현합니다.
- SetEase, SetDelay, OnComplete 등을 사용하여 애니메이션 타이밍과 동작을 제어합니다.
- 사운드 재생: 젬 이동 시 AudioSource.PlayOneShot()을 사용하여 사운드를 재생, 시각적 효과와 청각적 효과를 결합합니다.
- 코루틴 종료 조건: 모든 젬이 목표 지점에 도달하기 전까지 코루틴이 대기하고, 완료되면 코루틴이 끝나며 이후 로직을 진행할 수 있습니다.
전체 코드 예제
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
namespace WarehouseDeliveryQuest.Interaction
{
public class GemMover : MonoBehaviour
{
public static GemMover Instance { get; private set; }
[SerializeField] private GameObject gemPrefab;
[SerializeField] private Transform targetTransform;
[SerializeField] private Canvas canvas;
[SerializeField] private AudioSource audioSource;
[SerializeField] private AudioClip gemMoveClip;
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
if (canvas == null)
{
canvas = FindObjectOfType<Canvas>();
}
}
public IEnumerator MoveGems(int gemCount, Vector3 customStartPosition)
{
List<bool> tweensCompleted = new List<bool>();
for (int i = 0; i < gemCount; i++)
{
Vector3 spawnPosition = customStartPosition;
GameObject gem = Instantiate(gemPrefab, spawnPosition, Quaternion.identity, canvas.transform);
tweensCompleted.Add(false);
float delay = i * 0.1f;
int tweenIndex = i;
gem.transform.localScale = Vector3.one * 2f;
Sequence gemSequence = DOTween.Sequence();
gemSequence.Append(gem.transform.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack))
.AppendInterval(delay)
.AppendCallback(() =>
{
audioSource.PlayOneShot(gemMoveClip);
})
.Append(gem.transform.DOMove(targetTransform.position, 0.5f)
.SetEase(Ease.InOutQuad)
.OnComplete(() =>
{
Destroy(gem);
tweensCompleted[tweenIndex] = true;
}));
yield return new WaitUntil(() => tweensCompleted.TrueForAll(completed => completed));
}
}
public IEnumerator MoveGemsWithEffects(int gemCount, Vector3 customStartPosition)
{
List<GameObject> gemObjects = new List<GameObject>();
List<bool> tweensCompleted = new List<bool>();
audioSource.PlayOneShot(gemMoveClip);
for (int i = 0; i < gemCount; i++)
{
Vector3 offset = Random.insideUnitCircle * 0.5f;
Vector3 spawnPosition = customStartPosition + offset;
GameObject gem = Instantiate(gemPrefab, spawnPosition, Quaternion.identity, canvas.transform);
gemObjects.Add(gem);
tweensCompleted.Add(false);
float delay = i * 0.05f;
int tweenIndex = i;
gem.transform.DOMove(targetTransform.position, 1.0f)
.SetEase(Ease.InOutQuad)
.SetDelay(delay)
.OnComplete(() =>
{
Destroy(gem);
tweensCompleted[tweenIndex] = true;
});
}
yield return new WaitUntil(() => tweensCompleted.TrueForAll(completed => completed));
}
}
}
적용 방법
- DOTween 설치: 에셋 스토어에서 DOTween을 다운로드하고 프로젝트에 추가합니다.
- Gem Prefab 설정:
- gemPrefab에 사용할 젬 이미지를 Image나 Sprite로 설정한 GameObject를 준비합니다.
- 캔버스(Canvas)에 올바르게 표시될 수 있도록 RectTransform 설정을 확인하세요.
- AudioSource 및 AudioClip 설정:
- audioSource 컴포넌트가 있는 GameObject를 할당하고, gemMoveClip을 재생할 사운드 파일을 지정합니다.
- 타겟 위치 지정:
- targetTransform에 젬을 모을 위치에 해당하는 Transform을 설정하세요.
- 코루틴 호출:
- 다른 스크립트에서 StartCoroutine(GemMover.Instance.MoveGems(gemCount, startPosition));와 같이 호출하여 젬 이동 연출을 시작합니다.
- MoveGemsWithEffects()도 유사하게 호출할 수 있습니다.
오늘은 GemMover 스크립트를 활용하여 Unity에서 DOTween을 이용해 젬 이동 연출을 구현하는 방법을 알아봤어요.
이 시스템을 통해 보상을 시각적으로 표현하고, 플레이어에게 보다 매력적인 게임 경험을 제공할 수 있습니다.
지금까지 인텔리원스튜디오(IntelliOneStudio)였습니다!
감사합니다.
'디지털노마드' 카테고리의 다른 글
챗GPT 게임개발73: Unity iOS Native Plugin으로 텍스트와 이미지 공유하기 (0) | 2024.12.11 |
---|---|
챗GPT 게임개발72: Unity에서 타이머와 애니메이션 제어하기 (4) | 2024.12.04 |
챗GPT 게임개발71: Unity에서 Game Center 및 Google Play Games 리더보드 구현하기 (0) | 2024.12.03 |
챗GPT 게임개발70: Unity에서 다국어 지원과 언어별 폰트 적용하기 (4) | 2024.12.02 |
챗GPT 게임개발69: Unity에서 광고 쿨다운 시스템 구현하기 (1) | 2024.12.02 |