-
Unity에서 연속 카드 스와이프 효과 구현하기: Tinder 스타일의 인터랙션2024년 03월 22일
- 유니얼
-
작성자
-
2024.03.22.:59
728x90Tinder의 카드 스와이프 기능은 사용자에게 직관적이고 매력적인 인터페이스를 제공하는 좋은 예입니다. 이러한 인터랙션은 사용자의 결정을 시각적으로 나타내는 강력한 방법이며, 게임이나 어플리케이션에 몰입감을 더할 수 있습니다. Unity와 C#을 활용해, 게임 내에서 연속 카드 스와이프 효과를 구현하는 방법을 알아봅시다.
참고링크:
https://github.com/Vikings-Tech/Unity-Card-Swipe-Effect
기본 개념 및 구현
연속 카드 스와이프 효과
이 효과는 사용자가 카드를 한 방향으로 스와이프하면, 해당 카드가 화면에서 사라지고 다음 카드가 자리를 채우며 조금 더 커지는 방식으로 나타납니다. 사용자가 계속해서 카드를 스와이프할 수 있도록, 뒤이은 카드들도 동일한 효과를 반복합니다.
스크립트 설명
1, StoryCardEffect
StoryCardEffect 스크립트는 카드의 스와이프 동작을 처리합니다. IDragHandler, IBeginDragHandler, IEndDragHandler 인터페이스를 구현해 드래그 동작을 감지하고, 카드의 위치와 회전을 조정합니다. 사용자가 카드를 충분히 멀리 드래그하면, 카드는 화면 밖으로 스와이프되며 페이드 아웃됩니다.
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using UnityEngine.EventSystems; using UnityEngine.UI; public class StoryCardEffect : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler { private Vector3 _initialPosition; // 카드의 초기 위치입니다. private float _distanceMoved; // 초기 위치에서 카드가 이동한 거리입니다. private bool _swipeLeft; // 스와이프 방향을 결정하는 플래그입니다. 왼쪽으로 스와이프했는지 여부입니다. public event Action cardMoved; // 카드가 상당히 이동했을 때 트리거되는 이벤트입니다. // 드래그가 시작될 때 호출됩니다. public void OnBeginDrag(PointerEventData eventData) { _initialPosition = transform.localPosition; // 카드의 초기 위치를 저장합니다. } // 드래그하는 동안 계속해서 호출됩니다. public void OnDrag(PointerEventData eventData) { // 드래그 델타를 기반으로 카드를 이동시킵니다. transform.localPosition = new Vector2(transform.localPosition.x + eventData.delta.x, transform.localPosition.y); // 드래그 방향과 거리에 기반하여 카드를 회전시킵니다. if (transform.localPosition.x - _initialPosition.x > 0) { transform.localEulerAngles = new Vector3(0, 0, Mathf.LerpAngle(0, -30, (_initialPosition.x + transform.localPosition.x) / (Screen.width / 2))); } else { transform.localEulerAngles = new Vector3(0, 0, Mathf.LerpAngle(0, 30, (_initialPosition.x - transform.localPosition.x) / (Screen.width / 2))); } } // 드래그가 끝났을 때 호출됩니다. public void OnEndDrag(PointerEventData eventData) { _distanceMoved = Mathf.Abs(transform.localPosition.x - _initialPosition.x); // 이동한 거리를 계산합니다. if (_distanceMoved < 0.4 * Screen.width) { // 카드가 충분히 이동하지 않았다면, 원래의 위치와 방향으로 되돌립니다. transform.localPosition = _initialPosition; transform.localEulerAngles = Vector3.zero; } else { // 애니메이션을 위한 스와이프 방향을 결정합니다. _swipeLeft = transform.localPosition.x <= _initialPosition.x; cardMoved?.Invoke(); // 카드 이동 이벤트를 호출합니다. StartCoroutine(MovedCard()); // 카드 제거 애니메이션을 시작합니다. } } private IEnumerator MovedCard() { float time = 0; // 카드가 화면 밖으로 이동하고 페이드아웃되면서 사라지는 애니메이션입니다. while (GetComponent<Image>().color != new Color(1, 1, 1, 0)) { time += Time.deltaTime; if (_swipeLeft) { transform.localPosition = new Vector3(Mathf.SmoothStep(transform.localPosition.x, transform.localPosition.x - Screen.width, time), transform.localPosition.y, 0); } else { transform.localPosition = new Vector3(Mathf.SmoothStep(transform.localPosition.x, transform.localPosition.x + Screen.width, time), transform.localPosition.y, 0); } // 카드의 색상을 점차적으로 투명하게 변경하여 사라지게 합니다. GetComponent<Image>().color = new Color(1, 1, 1, Mathf.SmoothStep(1, 0, 4 * time)); yield return null; // 다음 프레임까지 기다립니다. } Destroy(gameObject); // 카드 게임 오브젝트를 파괴합니다. } }
2, SecondCard
SecondCard 스크립트는 첫 번째 카드가 스와이프된 후에 앞으로 나오는 다음 카드의 행동을 정의합니다. 이 스크립트는 첫 번째 카드의 움직임에 기반해 두 번째 카드의 스케일을 조정하며, 첫 번째 카드가 완전히 스와이프될 때 StoryCardEffect 기능을 물려받아 자신도 스와이프될 수 있게 합니다.
using UnityEngine; public class SecondCard : MonoBehaviour { private StoryCardEffect _storyCardEffect; // 첫 번째 카드에 적용된 StoryCardEffect 컴포넌트를 참조합니다. private GameObject _firstCard; // 첫 번째 카드의 GameObject를 참조합니다. void Start() { _storyCardEffect = FindObjectOfType<StoryCardEffect>(); // Scene 내에서 StoryCardEffect 컴포넌트를 찾아 참조합니다. _firstCard = _storyCardEffect.gameObject; // 찾은 StoryCardEffect 컴포넌트가 부착된 GameObject(첫 번째 카드)를 참조합니다. _storyCardEffect.cardMoved += StoryCardMovedFront; // 첫 번째 카드가 움직였을 때 호출될 메서드를 이벤트에 등록합니다. transform.localScale = new Vector3(0.8f, 0.8f, 0.8f); // 두 번째 카드의 초기 크기를 설정합니다. } void Update() { float distanceMoved = _firstCard.transform.localPosition.x; // 첫 번째 카드가 이동한 거리를 계산합니다. if (Mathf.Abs(distanceMoved) > 0) { // 첫 번째 카드가 이동함에 따라 두 번째 카드의 크기를 점진적으로 변경합니다. float step = Mathf.SmoothStep(0.8f, 1, Mathf.Abs(distanceMoved) / (Screen.width / 2)); transform.localScale = new Vector3(step, step, step); // 두 번째 카드의 크기를 업데이트합니다. } } void StoryCardMovedFront() { gameObject.AddComponent<StoryCardEffect>(); // 첫 번째 카드가 움직임을 마친 후 두 번째 카드에 StoryCardEffect 컴포넌트를 추가합니다. Destroy(this); // SecondCard 컴포넌트 자체를 제거합니다. 이제 이 객체는 StoryCardEffect의 동작을 따릅니다. } }
3, StoryCardView
CardView 스크립트는 두번째 카드가 파괴가 되었을 때 새로운 카드를 생성합니다. Update 메소드를 통해 매 프레임마다 자식 개체의 수를 체크하고, 부족하면 InstantiateNewStoryCard 메소드를 호출해 storyCardPrefab 프리팹을 기반으로 새 스토리 카드를 생성하고, 이 카드에 SecondCard 컴포넌트를 추가하여 생성된 카드를 부모 객체의 첫 번째 자식으로 설정합니다.
using UnityEngine; public class StoryCardView : MonoBehaviour { public GameObject storyCardPrefab; private void Update() { if (transform.childCount < 2) { InstantiateNewStoryCard(); } } private void InstantiateNewStoryCard() { GameObject newCard = Instantiate(storyCardPrefab, transform, false); newCard.GetOrAddComponent<SecondCard>(); newCard.transform.SetAsFirstSibling(); } }
핵심 구현 사항
- 드래그 감지 및 처리: 사용자의 드래그 입력에 따라 카드의 위치와 회전을 실시간으로 업데이트합니다.
- 스와이프 결정: 사용자가 카드를 충분한 거리만큼 드래그했는지 판단하여, 충분치 않다면 원래 위치로 복귀시키고, 충분하다면 스와이프 효과를 적용합니다.
- 연속 카드 효과: 첫 번째 카드가 스와이프된 후, 두 번째 카드가 자동으로 활성화되어 같은 효과를 반복할 수 있게 합니다.
결론
Unity에서 카드 스와이프 효과를 구현하는 것은 게임이나 어플리케이션에 독특한 인터랙션을 추가하는 훌륭한 방법입니다. 위에서 설명한 방법을 통해, 사용자의 행동에 따라 시각적인 피드백을 제공하며, 게임의 스토리나 선택지를 보다 몰입감 있게 전달할 수 있습니다. 이러한 인터랙션은 특히 스토리 기반 게임이나 소셜 미디어 애플리케이션, 그리고 사용자의 선택을 중요시하는 어떠한 앱에서도 유용하게 활용될 수 있습니다.
반응형다음글이전글이전 글이 없습니다.댓글