TIL

[멋쟁이사자처럼 부트캠프 TIL 회고]

Cadi 2025. 2. 25. 02:10

오늘 배운 것

01. 스테이지 버튼 만들기

02. Scroll View 관련 

 

 

01. 스테이지 버튼 만들기

 

 

하나 만들었을 때 가운데 정렬되는 현상

Grid Layoutgroup - child alignment

 

 

* 스테이지 셀을 프리팹으로 만들었을 때 안보이는 경우

- 스테이지 셀 프리팹의 크기를 체크, 현재는 Grid Layout Group에 의해 사이즈가 자동으로 조절되고 있기 때문에 Content 밑에서 보이는 상황일 수 있음. 

 

 

Clear 상태일 때만 버튼 컴포넌트를 추가하거나,

코드로 Clear 상태일때만 OnClick 해도 동작되게 함. 

 

 

Content의 RectTransform 값을 조정해서 , 마지막으로 클리어한 스테이지까지 한 번에 내려가게 하는 것이 과제

패딩은 각각 안에 들어있는 자식들 기준이 아닌, 부모 오브젝트에서 정하는 것.

 

 

using System;
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(PopupPanelController))]
public class StagePopupPanelController : MonoBehaviour
{
    [SerializeField] private GameObject stageCellPrefab;
    [SerializeField] private Transform contentTransform;
    [SerializeField] private ScrollRect scrollRect;

    
    private void Start()
    {
        GetComponent<PopupPanelController>().SetTitleText("STAGE");

        var lastStageIndex = 90;             // UserInformations.LastStageIndex;
        var maxStageCount = 100;            // Constants.MAX_STAGE_COUNT;

        RectTransform currentStageRect = null;
        
        // Stage Cell 만들기
        for (int i = 0; i < maxStageCount; i++)
        {
            GameObject stageCellObject = Instantiate(stageCellPrefab, contentTransform);
            StageCellButton stageCellButton = stageCellObject.GetComponent<StageCellButton>();

            if (i < lastStageIndex)
            {
                stageCellButton.SetStageCell(i, StageCellButton.StageCellType.Clear);                
            }
            else if (i == lastStageIndex)
            {
                stageCellButton.SetStageCell(i, StageCellButton.StageCellType.Normal);
                currentStageRect = stageCellObject.GetComponent<RectTransform>();
            }
            else
            {
                stageCellButton.SetStageCell(i, StageCellButton.StageCellType.Lock);
            }
        }

        if (currentStageRect != null)
        {
            StartCoroutine(ScrollToStage(currentStageRect));
        }
    }

   

    private IEnumerator ScrollToStage(RectTransform targetStage)
    {
        yield return new WaitForEndOfFrame(); // 레이아웃 업데이트 대기

        RectTransform contentRect = contentTransform.GetComponent<RectTransform>();
    
        float targetY = -targetStage.anchoredPosition.y; // 반대 방향으로 조정
        float minY = 0f;
        float maxY = contentRect.rect.height - scrollRect.viewport.rect.height;

        targetY = Mathf.Clamp(targetY, minY, maxY);

        contentRect.DOAnchorPosY(targetY, 1f).SetEase(Ease.OutQuad);
    }

}

 

 

   private IEnumerator ScrollToStage(RectTransform targetStage)
    {
        yield return new WaitForEndOfFrame(); // 레이아웃 업데이트 대기

        RectTransform contentRect = contentTransform.GetComponent<RectTransform>();
    
        float targetY = -targetStage.anchoredPosition.y; // 반대 방향으로 조정
        float minY = 0f;
        float maxY = contentRect.rect.height - scrollRect.viewport.rect.height;

        targetY = Mathf.Clamp(targetY, minY, maxY);

        contentRect.DOAnchorPosY(targetY, 1f).SetEase(Ease.OutQuad);
    }

\

 

이렇게 셀을 만들면, 보여지지 않는데도 불구하고 준비해야하는문제가 있음

그래서 오브젝트 풀처럼 위 아래 몇 칸씩만 보이는 스크롤 뷰를 만들어보자.

 

 

02. Scroll View 만들기

거의 대부분의 게임에서 사용되는 UI, 에셋스토어에 팔기도 하지만 원리를 잘 이해해야 한다.

 

 

 

 

 

빈 게임 오브젝트 만들기

Scroll Rect 컴포넌트 추가.

VeiwPort (빈 오브젝트) 만들고 할당

 

이렇게 만드는 과정이 우리가 UI - Scroll view 하면 한 번에 되었던 것이다.

 

ScrollVeiw와 VeiwPort는 스트레치 ㅡ 스트레치가 맞으나, Content는 스크롤이 될 영역이기 때문에 너비만 맞으면 된다. 

 

ViewPort 에 image와 Mask 추가

image는 백그라운드가 될 것이고, Mask는 마스킹을 할 것인지, Show mask Graphic은 일반적으로 언체크하나 지금은 일단...

 

Cell 추가 , 하나는 고유한 높이.

Cell 마다의 높이가 달라지기도 함, 기본적으로는 자기 자신만의 고유한 높이를 갖고 있음

 

 

그리고 셀을 하나 만듬

 

 

 

public struct Item
{
    public string itemFlileName;
    public string title;
    public string subtitle;
}

 

아이템 데이터 같은 것은  struct로 선언하는 것이 좋다.

 

ScrollRect의 OnValueChanged는 0과 1값만 들어온다. 스크롤 방향에 따라 !

이 함수를 이용해야하는데 이건 '얼만큼 하는지'를 알려주지 않는다. 

 

이건 완전 혼자 풀어봤다. 

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


[RequireComponent(typeof(ScrollRect))]
[RequireComponent(typeof(RectTransform))]
public class ScrollVeiwController : MonoBehaviour
{
    private ScrollRect _scrollRect;
    private RectTransform _rectTransform;
    //변하는 형태의 배열 ( 실행하면서 넣었다 뺄 수 잇므)
    private List<Item> _items;

    private void Awake()
    {
        _scrollRect = GetComponent<ScrollRect>();
        _rectTransform = GetComponent<RectTransform>();
    }

    private void Start()
    {
        LoadData();
    }

    private void ReloadData()
    {
        //아이템 리스트가 수정되면 다시..
    }
    private void LoadData()
    {
        _items = new List<Item>
        {
            new Item { itemFlileName = "image1", title = "Title1", subtitle = "Subtitle1" },
            new Item { itemFlileName = "image2", title = "Title2", subtitle = "Subtitle2" },
            new Item { itemFlileName = "image3", title = "Title3", subtitle = "Subtitle3" },
            new Item { itemFlileName = "image4", title = "Title4", subtitle = "Subtitle4" },
            new Item { itemFlileName = "image5", title = "Title5", subtitle = "Subtitle5" },
            new Item { itemFlileName = "image7", title = "Title7", subtitle = "Subtitle7" },
            new Item { itemFlileName = "image8", title = "Title8", subtitle = "Subtitle8" },
            new Item { itemFlileName = "image9", title = "Title9", subtitle = "Subtitle9" },
            new Item { itemFlileName = "image10", title = "Title10", subtitle = "Subtitle10" },

        };
        ReloadData();
    }

    public void OnValueChanged(Vector2 value)
    {
        Debug.Log(value);
        
        var x = _scrollRect.content.anchoredPosition.x;
        var y = _scrollRect.content.anchoredPosition.y;

        var w = _rectTransform.rect.width;
        var h = _rectTransform.rect.height;
        
        Debug.Log($"x:{x}, y:{y}, w:{w}, h:{h}");
    }
}

 

이를 바탕으로 ObjectPool을 활용한 Scroll View를 만드는 것이 과제였다. 

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

public class Cell : MonoBehaviour
{[SerializeField] private Image image;
[SerializeField] private TMP_Text text;
[SerializeField] private TMP_Text subTitle;



public void SetItem(Item item)
{
    image.sprite = Resources.Load<Sprite>(item.itemFlileName);
    text.text = item.title;
    subTitle.text = item.subtitle;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public struct Item
{
    
    public string itemFlileName;
    public string title;
    public string subtitle;
}

 

 

일단 여기서 1차적으로 7개를 생성하고 나타내봤다. 

 

private void Start()
{
    LoadData();
    for (int i = 0; i < 7; i++)
    {
       var cell = cellObjectPool.GetPool();
       Debug.Log($"cell name: {cell.name}, is a prefab? {PrefabUtility.IsPartOfPrefabAsset(cell)}");

       cell.GameObject().GetComponent<Cell>().SetItem(_items[i]);
       cell.GameObject().transform.SetParent(_scrollRect.content, false);

    }
}

 

진짜 하루 종일 했다. 자세한 내용은 따로 포스팅할 예정이다. (완)

https://febelo0524.tistory.com/150

 

Scroll View With ObjectPool

오늘의 목표오브젝트 풀을 활용한 스크롤 뷰 만들기 스테이지 등 스크롤뷰의 컨텐트 영역에 들어갈 무언가가 한정적이라면 만들지 않아도 괜찮겠지만,예를 들어 SNS라던가, 무한히 스크롤 되는

febelo0524.tistory.com

 

 

MVC 패턴 - model view Controller의 약자 - > 찾아보기