UGUI 캐릭터 목록 만들기 2 - UI

Jonghwan Choi·2023년 6월 7일
0

포트폴리오

목록 보기
2/5

캐릭터 목록 화면

일단 재사용 스크롤뷰는 구현하지 않고 Character 데이터 하나마다 캐릭터 카드 객체 하나씩 새로 생성하는 방식을 썼다. 추후 재사용 스크롤뷰 적용할 예정.

동적 그리드 스크롤뷰 코드는 이 글을 참고해서 작성했다.

CharacterListController.cs

동적 스크롤뷰 관련 코드만 표시

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class CharacterListController : MonoBehaviour
{
	public GameObject characterCard;
	public GameObject gridLayout;

	public Toggle toggle;

	private HttpClient client = new HttpClient();
	private List<Character> characters;
    
    private void Start()
	{
    	// 캐릭터 리스트 가져오기 (서버 없이 더미데이터를 넣음)
		characters = client.FetchCharacters();
        // 리스트 UI에 뿌리기
		Populate(characters);
	}
    
    // UI에 리스트 뿌리는 기능
    private void Populate(List<Character> list)
	{
    	// 화면 갱신시 리스트가 계속 쌓이지 않도록 기존 객체들 없애기
		foreach (Transform child in gridLayout.transform)
		{
			Destroy(child.gameObject);
		}
		// GridLayoutGroup 안에 캐릭터 카드 프리팹 넣고 데이터 바인딩
		foreach (Character item in list)
		{
			GameObject go = Instantiate(characterCard, gridLayout.transform);
			go.GetComponent<CharacterCard>().Bind(item);
		}
	}
}

캐릭터 카드


Character 객체의 numOfStar 값에 따라 하단의 별 갯수를 다르게 표시해야 했는데, 이걸 어떻게 구현할지 좀 고민을 했다. 처음엔 스프라이트 없는 Image를 5칸 만들어 두고 numOfStar 값이 3이라면 Image 3칸에 별 스프라이트를 각각 넣는 방식으로 할까 하다가 생각을 바꿨다.

우선 Image 칸은 하나만 만들고, numOfStar 값에 따라 칸 길이만 바뀌게 한 뒤 별 스프라이트를 Tiled 타입으로 넣었다. 이렇게 하니 코딩도 훨씬 간결하고 메모리도 좀더 효율적으로 쓰게 되어 잘된 것 같다.

CharacterItem.cs

데이터와 UI를 바인딩하는 기능을 아이템 객체 안에다 넣었는데, 이건 안드로이드에서처럼 Adapter 클래스를 따로 만들어서 수행시키는 편이 재사용성 면에서 더 좋을 것 같다. 여유가 되면 만들어봐야겠다.

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class CharacterCard : MonoBehaviour
{
    // 캐릭터 카드 상의 각 UI 요소들 참조
    public TMP_Text nameText;
    public Image portraitImage;
    public Image rarityImage;
    public Image jobIconImage;
    public RectTransform starImageTransform;
	public TMP_Text levelText;
    public TMP_Text powerText;

    // UI에 표시될 별 갯수 조절을 위한 별 1개의 길이
    private int widthOfOneStar = 34;

    // Character 객체의 필드들을 캐릭터 카드 UI에 뿌려주는 기능
    // CharacterListController에서 호출
    public void Bind(Character character)
    {
        nameText.text = character.Name;
        levelText.text = character.Level.ToString();
        portraitImage.sprite = Resources.Load<Sprite>(character.PortraitUrl);
        jobIconImage.sprite = Resources.Load<Sprite>(character.Job.IconUrl);
        
        // 별 갯수에 따라 별 스프라이트가 들어갈 Image 크기 조절
        starImageTransform.sizeDelta = 
            new Vector2(widthOfOneStar * character.NumOfStar, starImageTransform.sizeDelta.y);
		
        // 캐릭터 태생 레어도에 따라 카드 오른쪽 띠 색상 변경 
        switch (character.Rarity)
        {
            case 1:
                rarityImage.color = Color.blue;
                break;
            case 2:
                rarityImage.color = Color.green;
                break;
            case 3:
                rarityImage.color = Color.yellow;
                break;
        }
		
        // 캐릭터 스탯으로부터 전투력을 계산하여 UI에 표시
        // 전투력 계산은 다른 곳에서도 쓸 기능이라 Utils 클래스에 전역메서드로 배치
        int power = Utils.CalculatePower(character.MaxHp, character.Damage, character.Armor);
        powerText.text = power.ToString();
    }
}

정렬 및 필터 토글


화면 상단과 우측, 그리고 팝업창 안에 들어가는 버튼들은 Button이 아닌 Toggle로 구현했다. 버튼의 역할이 정렬(혹은 필터) 적용/해제 2가지 뿐이었기 때문이다. '즐겨찾기된 캐릭터만 표시' 토글 및 '소유중인 캐릭터만 표시' 토글은 체크박스 모양의 원본 그대로 썼지만, 다른 토글들은 체크박스를 없애고 On/Off시 아이콘이나 버튼 색상이 바뀌도록 스크립트로 이벤트를 작성했다.

상단 정렬 토글 이벤트

using UnityEngine;
using UnityEngine.UI;

public class SortToggle : MonoBehaviour
{
	public Image buttonImage;

    public void ChangeIcon()
	{
        if (GetComponent<Toggle>().isOn)
            buttonImage.sprite = Resources.Load<Sprite>("Icons/triangle-down");
        else
            buttonImage.sprite = Resources.Load<Sprite>("Icons/triangle-up");
    }
}

팝업창 내 필터 토글 이벤트

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class FilterToggle : MonoBehaviour
{
    public TMP_Text text;

    public void ChangeColor()
    {
        if (GetComponent<Toggle>().isOn)
        {
            GetComponent<Image>().color = new Color32(97, 97, 97, 255);
            text.color = Color.white;
        }
        else
        {
            GetComponent<Image>().color = Color.white;
            text.color = Color.black;
        }
    }
}

사용 리소스

폰트

출처: 고양일산체R
UGUI Text 대신 TextMeshPro를 써보았다. 프로젝트에 별도 리소스가 추가되고 폰트 아틀라스를 직접 만들어야 하는 등 귀찮음이 있었지만 UI를 확대해도 글자 해상도가 깔끔하게 유지되어 확실히 Text보다 괜찮은 것 같다. 참고글

아이콘

출처: 무료 아이콘 제공 사이트 Flaticon
재사용할 일이 많아서 그냥 Resources에 넣었다.

포트레잇

출처: 구글 검색
원본 게임 리소스를 구할 수 있으면 그걸로 바꾸고 싶다...
일러스트와 포트레잇은 캐릭터가 많아지면 용량을 꽤 잡아먹을 것 같아 Resources에 올리기엔 부담이 되고, 에셋 번들을 사용해볼까 하고 있다.

profile
유니티 게임 클라이언트 개발자를 꿈꾸는 뉴비

0개의 댓글