2012.12.29에 네이버 블로그에 게시했던 글을 이전해온 게시글입니다.


위 두가지 버전의 스와이프 메뉴를 만듭니다.
샘플 데이터는 개인적으로 좋아하는 페르소나5의 괴도단들로 제작했습니다 :)!
Step1. Scroll View 만들기

[UI]-[Scroll View]로 스크롤뷰를 생성해줍니다.

뒷배경을 깔끔하게 해주기위하여 배경도 만들었습니다.
이는 생략하셔도 됩니다.

이번엔 Vertical Scroll은 사용하지않으니 삭제해줍니다.
Step2. 캐릭터 목록 만들기

ScrollView - Viewport - Content 아래에 빈 오브젝트를 만들어줍니다.

빈 오브젝트를 CharacterItem으로 둔 후, 아래에 Image, Text를 만듭니다
빈 오브젝트의 크기는 이미지와 텍스트가 모두 들어갈정도의 크기로 합니다.

나중에 이부분이 될 예정입니다.

ScrollView - Viewport - Content 에
ContentSizeFilter 컴포넌트와 HorizontalLayoutGroup 컴포넌트를 추가합니다.
ContentSizeFilter : Content아래의 Children에 따라 Content의 크기를 조절해줍니다.
HorizontalLayoutGroup : 수직형으로 Children을 정렬해줍니다.

public void SetCharacterItem(Character character)
{
_characterPic.sprite = Resources.Load<Sprite>("Image/" + character.PicName);
_characterName.text = character.Name;
}
이제 캐릭터 목록용 class를 작성해줍니다.
JSON파일에서 가져온 데이터로, 이미지와 이름을 입력해줄것입니다.
(코드 전문은 페이지 제일 아래에 있습니다)

작성한 class를 캐릭터 목록의 컴포넌트로 추가해줍니다.

이를 끌어당겨 Prefab화 해주세요.
Step3. Json파일로부터 목록을 받아와 목록 완성하기

캐릭터 전체 목록을 총괄할 클래스를 만들어줍니다.
저는 CanvasSwiper로 이름지었습니다.

CanvasSwiper에 방금 만든 prefab과 Prefab를 복제할곳을 변수로 만들어줍니다.

SetCharacter를 작성합니다.
For문으로 캐릭터의 배열수만큼 돌리며
캐릭터의 배열수만큼 캐릭터 목록을 복제하고 정보를 넣습니다.

작성한 SetCharacter 함수를 JsonController의 Event에 연결합니다.
이로서 Json파일이 불러오면 SetCharacter를 불러오며
캐릭터 목록을 생성해줄겁니다.

캐릭터 목록이 불러와지는것을 확인할 수 있습니다.

캐릭터 목록이 중앙에서부터 시작되어 중앙에서 끝나도록 하기위하여
Content내의 HorizontalLayoutGroup의 Padding을 수정해줍니다
Left와 Right의 마진을 각각 스크린사이즈/2로 해주시고
Spacing은 보기 편하도록 해줍니다.
(저는 20으로 작성하였습니다)
Step4. 현재 선택된 캐릭터 만들기
(캐릭터 컨트롤러)
캐릭터 선택에 대한 기본 개념은 이렇습니다
ⓛ. 캐릭터가 두개일 경우

②. 캐릭터가 세개일 경우

③. 캐릭터가 n개일 경우
A번째 캐릭터는 1/n * A 보다 크고, 1/n * (A+1) 보다 작게됩니다.
이를 코드로 작성하면 이와같이 됩니다.


for문을 돌리며 (1/n) * distanceIndex 보다 크고, (1/n) * (distanceIndex+1) 보다 작은경우 선택,
그 외의 경우는 선택 해제를 합니다.

slider의 Value값이 0과 1 사이가 아닐때가 있으므로
Mathf.Clamp를 사용하여 0과1사이로 바꿔줍니다.
Mathf.Clamp : 최소, 최댓값을 설정하여 value의 값이 그 사이를 넘지 않도록 해준다.

이제 값이 0과 1 사이이므로, 0인 경우는 첫번째, 1인경우는 마지막이 선택되도록 합니다.

마지막으로 scrollbar를 받아와 start에 리스너로 추가해줍니다.
이로서 스크롤바의 값이 변경되면 OnSliderValueChange 함수를 호출합니다.
/// <summary>
/// 슬라이더 값이 변경되었을 때 불리는 함수
/// </summary>
/// <param name="value">변경된 슬라이더의 값</param>
private void OnSliderValueChange(float value)
{
//value를 0과 1사이로
value = Mathf.Clamp(value, 0f, 1f);
for(int distanceIndex = 0; distanceIndex < _characterItems.Count; distanceIndex++)
{
//(1/n) * distanceIndex 보다 크고, (1/n) * (distanceIndex+1) 보다 작은경우 선택
//그 외의 경우는 선택해제
if (_distance * distanceIndex <= value)
{
if (_distance * (distanceIndex + 1f) > value)
{
_characterItems[distanceIndex].SetSelected();
_selectedIndex = distanceIndex;
continue;
}
}
_characterItems[distanceIndex].SetUnselected();
}
//distance가 0인 경우 첫번째 선택
if (_distance == 0f)
{
_characterItems[0].SetSelected();
}
//distance가 1인 경우 마지막이 선택
else if (_distance == 1f)
{
_characterItems[_characterItems.Count].SetSelected();
}
}
Step5. 현재 선택된 캐릭터 만들기 (각 캐릭터)
이제 캐릭터들이 선택되었을 때 선택되었음을 알 수 있게 애니메이션을 추가해줄 것입니다.

만들어두었던 prefab를 켜서 Animator 컴포넌트를 추가해줍니다.

Create-AnimatorController을 이용해 애니메이터 컨트롤러를 만들어줍니다.

Prefab의 애니메이터 컴포넌트에 이를 연결해줍니다.


선택됐을때 그림이 커지는 애니메이션을 만들어줍니다.
저는 그림 스케일을 0.7에서 1로 변경되도록 했습니다.

이를 애니메이터에 연결하여 트리거로 각각 설정해줍니다.
작아지는경우는 따로 애니를 만들 필요가 없이, 커지는 애니에서 속도만 -1로 설정해주면 됩니다.

마지막으로 선택됐을때와 선택되지 않았을때 각각의 애니가 플레이되도록 설정해주면 됩니다.

이로서 캔버스를 이용한 스와이프 기능이 완성되었습니다.
아래 코드 전문
[CanvasSwiper.cs]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CanvasSwiper : MonoBehaviour
{
//캐릭터 목록 Prefab
[SerializeField]
private GameObject _characterItemPrefab;
//캐릭터 목록이 생성될 곳
[SerializeField]
private Transform _swipeTransform;
[SerializeField]
private Scrollbar _slider;
private List<CharacterItem> _characterItems = new List<CharacterItem>();
private float _distance = 0f;
private int _selectedIndex = 0;
private void Start()
{
//슬라이더에 리스너를 추가하여 값이 변경되면 OnSliderValueChange함수를 호출하도록 함
_slider.onValueChanged.AddListener(OnSliderValueChange);
}
/// <summary>
/// 캐릭터 목록 생성
/// </summary>
public void SetCharacters(Characters charactersList)
{
var characters = charactersList.characters;
for (int charactersIndex = 0; charactersIndex < charactersList.characters.Length; charactersIndex++)
{
//prefab을 복제한다
var charactersObj = Instantiate(_characterItemPrefab, _swipeTransform);
//Json에서 받아온 캐릭터 정보를 캐릭터 프리팹에 넣어준다
var characterItem = charactersObj.GetComponent<CharacterItem>();
characterItem.SetCharacterItem(characters[charactersIndex]);
//캐릭터 목록에 추가한다
_characterItems.Add(characterItem);
}
//각 value들 사이의 거릿값
//A번째 캐릭터는 1/n * A 보다 크고, 1/n * (A+1) 보다 작게된다
//1/n을 매번 계산하면 코스트가 들어가므로 _distance라는 변수에 저장
_distance = 1f / _characterItems.Count;
//첫번째 캐릭터를 선택으로 변경해둔다
_characterItems[0].GetComponent<CharacterItem>().SetSelected();
}
/// <summary>
/// 선택되어있는 캐릭터를 return함
/// </summary>
public CharacterItem GetSelectedItem()
{
return _characterItems[_selectedIndex];
}
/// <summary>
/// 슬라이더 값이 변경되었을 때 불리는 함수
/// </summary>
/// <param name="value">변경된 슬라이더의 값</param>
private void OnSliderValueChange(float value)
{
//value를 0과 1사이로
value = Mathf.Clamp(value, 0f, 1f);
for(int distanceIndex = 0; distanceIndex < _characterItems.Count; distanceIndex++)
{
//(1/n) * distanceIndex 보다 크고, (1/n) * (distanceIndex+1) 보다 작은경우 선택
//그 외의 경우는 선택해제
if (_distance * distanceIndex <= value)
{
if (_distance * (distanceIndex + 1f) > value)
{
_characterItems[distanceIndex].SetSelected();
_selectedIndex = distanceIndex;
continue;
}
}
_characterItems[distanceIndex].SetUnselected();
}
//distance가 0인 경우 첫번째 선택
if (_distance == 0f)
{
_characterItems[0].SetSelected();
}
//distance가 1인 경우 마지막이 선택
else if (_distance == 1f)
{
_characterItems[_characterItems.Count].SetSelected();
}
}
}
[CharacterItem.cs]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CharacterItem : MonoBehaviour
{
private Character _characterData;
[SerializeField]
private Image _characterPic;
[SerializeField]
private Text _characterName;
[SerializeField]
private Animator _animator;
private bool _isSelected = false;
public void SetCharacterItem(Character character)
{
//캐릭터 이미지
_characterPic.sprite = Resources.Load<Sprite>("Image/" + character.PicName);
//캐릭터 이름
_characterName.text = character.Name;
_characterName.gameObject.SetActive(false);
_characterData = character;
}
/// <summary>
/// 캐릭터가 선택됨
/// </summary>
public void SetSelected()
{
if (_isSelected)
return;
_isSelected = true;
_animator.SetTrigger("SetLarge");
_characterName.gameObject.SetActive(true);
}
/// <summary>
/// 캐릭터가 선택되지않음
/// </summary>
public void SetUnselected()
{
if (!_isSelected)
return;
_isSelected = false;
_animator.SetTrigger("SetSmall");
_characterName.gameObject.SetActive(false);
}
/// <summary>
/// 자신이 가진 캐릭터의 정보를 return해줌
/// </summary>
public Character GetCharacterData()
{
return _characterData;
}
/// <summary>
/// 자신이 가진 캐릭터의 이미지를 return해줌
/// 리소스에서 이미지를 두세번씩 가져오는것을 방지하기 위함
/// </summary>
public Sprite GetPicSprite()
{
return _characterPic.sprite;
}
}
뒷 게시글에서 계속됩니다.
'UNITY' 카테고리의 다른 글
Unity로 스칼렛 스트링스 염력 만들어보기 (2) | 2023.11.03 |
---|---|
UNITY로 스와이프 메뉴 UI 만들기 -3- Circle Swipe (0) | 2023.11.03 |
UNITY로 스와이프 메뉴 UI 만들기 -1- Json 캐릭터 파일 생성 (0) | 2023.11.03 |
UNITY Animator 애니메이션 콜백함수 만들기 (1) | 2023.11.03 |
UNITY 버튼 꾹 누르기 이벤트 (0) | 2023.11.03 |