[Unity]TIL (44) | 2023.09.22 | 유니티 상점 만들기

kjg5370·2023년 9월 22일
0

TIL

목록 보기
44/91
post-thumbnail

들어가기 앞서

오늘은 개인 과제의 제출일이였습니다.
필수 기능들은 모두 구현에 성공했고 선택 기능 중
상점을 만드는 것이 있어서 스크롤 뷰를 이용해 상점UI를 만들어보았습니다.

오늘 배운 것

일단 상점을 만드는 데에 필요한 것들이 무엇인지 찾아 보았습니다.

  • 상점에 필요한 기능들
    1. 상점을 여는 버튼
    2. 아이템 리스트를 보여주는 상점 UI
    3. 아이템 정보들을 가지고 있는 스크롤 뷰
    4. 아이템을 사는 버튼
    5. 상점UI를 닫는 기능

이렇게 5개의 기능이 상점에 필요한 것들이였습니다. 일단 상점을 여는 버튼을 만들었습니다.
Hirearchy에 Status버튼과 Inventory버튼을 한번에 안보이게 하려고 만들었던 ButtonUI오브젝트 밑에
상점 버튼을 만들었습니다. 이렇게 하면 인벤토리나 스테이터스를 볼때 상점 버튼이 방해를 하지 않기 때문입니다.

그 다음 상점의 기본적인 UI창을 만들어보았습니다.

임의로 검 이미지를 넣어 스크롤 뷰를 테스트 해보았습니다. 스크롤 뷰에는 여러가지 기능이 있었는데
일단 수평 이동인 Scroll Rect - Horizontal을 체크 해제 하였고 Scrollbar Horizontal을 삭제하였습니다. 그 다음 마우스 휠로 잘 움직일 수 있게 Scroll Secsitivity를 30정도로 올려보았습니다.

Viewport아래의 Content안에 스크롤 뷰에 표시할 UI들을 만들어주었고 이를 정렬하기 위해 Virtical Layout Group 컴포넌트를 추가하여 Spacing 을 5정도로 하여 살짝 떨어트려주고 Child Alignment를 Middle Left로 골라서 정렬해주었습니다. Middle Center로 정렬하면 살짝 오른쪽으로 기울어져서 저것을 선택하였습니다.그리고 안보이는 부분이 늘어날 수 있도록 Content Size Fitter 컴포넌트를 추가하여 Vertical Fit를 Preferred Size로 해주었습니다.

그리고 상점에 보이는 아이템들의 UI에 값을 넣어줄 ShopItemUI스크립트를 하나 만들었습니다.
각 아이템 마다 ItemData 스크립터블 오브젝트를 가지고 있고 상점을 열었을 때 Start 부분에서
스크립터블 오브젝트의 값을 가져와 UI에 들어갈 값을 초기화 해줍니다.

그리고

CharacterStats statsModifier;

캐릭터 스탯 클래스의 statsModirier를 선언하여

  public void OnBuyButtonClick()
  {
      Inventory.instance.AddShopItem(data,statsModifier);
  }

이 함수를 통해 buy 버튼을 눌렀을 때 Inventory클래스의 AddShopItem 함수를 실행하게 됩니다.
Inventory의 AddShopItem은

  public void AddShopItem(ItemData data,CharacterStats stat)
  {
      if (statsHandler.CurrentStats.gold >= stat.gold)
      {
          int count = 0;
          for (int i = 0; i < datas.Length; i++)
          {
              if (datas[i] != null)
                  count++;
          }
          datas[count] = data;
          UpdateUI();
          PurchasePopUp.SetActive(true);
          statsHandler.AddStatModifier(stat);
      }
      else
      {
          Debug.Log("골드가 부족합니다.");
      }
  }

이렇게 플레이어 골드가 충분할 때 실행되며 캐릭터가 가지고 있는 아이템 배열인 datas에서 빈칸의 제일 앞부분에 상점에서 산 아이템의 데이터를 넘기게 됩니다. 그리고 CharcaterStatsHandler 변수의 statsHandler를 통해 플레이어가 가진 골드에서 아이템 가격을 빼줍니다.

플레이어의 골드를 감소시키기 위해 CharacterStats 클래스의 StatsChangeType에 Sub타입을 추가하고
UpdateCharacterStats() 함수에 statsModifiers에 들어있는 모든 수정 사항을 반영하는 반복문에
else if로

else if (modifier.statsChangeType == StatsChangeType.Sub)
{
    UpdateStats((o, o1) => o - o1, modifier);
}

스탯을 감소시키는 부분을 만들어 주었습니다.
이렇게 상점을 만들었고 상점에서 아이템을 사면 인벤토리에 추가되고

추가 된 아이템이 문제 없이 원래 인벤토리에 있던 아이템들처럼 착용도 되고 스탯도 잘 올라가며 문제없이 동작하는 것을 확인했습니다.

기억 할 것 & 진행 사항

  • 스크롤 뷰
    처음 스크롤 뷰를 만들었을 때 스크롤 바를 안 보이게 하려고 지우다가 바가 완전히 사라져서 다시 만들어서 넣었는데 맨 처음 만들었던 모양이 아니라
    스크롤 뷰를 지고 다시 만들고를 3번정도 한 것 같습니다. 그다음부터는 스크롤 뷰를 잘 알아보고 쓰려고 여러 검색을 했는데 생각보다 다양한 기능들이 있었습니다.

  • Scroll Rect의 기능들
    Horizontal : 수평 이동기능
    Vertical : 수직이동 기능
    Movement Type

    • Unrestricted - 스크롤 뷰가 어떠한 제한도 받지 않고 무한대로 스크롤됨
    • Elastic - 스크롤 뷰의 컨텐츠가 스크롤 영역의 끝까지 스크롤될 때 일종의 탄성 효과를 주는 옵션
    • Clamped - 스크롤 뷰의 컨텐츠가 스크롤 영역의 끝에서 더 이상 스크롤되지 않도록 제한하는 옵션

    Inertia : 스크롤 뷰의 관성 옵션
    Scroll Sensitivity : 스크롤 뷰에서 스크롤 감도를 조절
    Horizontal and Vertical Scrollbar : 스크롤 뷰에는 수평 및 수직 스크롤바를 포함
    Visivility : 스크롤 바가 보이는 형식 지정

  • 스크립트를 쓰지 않고 게임오브젝트 활성화
    이때까지 버튼을 누르면 게임오브젝트를 SetActive(true)로 하거나 false를 하는 것을 스크립트로만 진행했었는데 오늘
    스크립트를 쓰지 않고도 버튼 이벤트로 할 수 있다는 사실을 알았다.

    버튼을 추가하면 버튼 컴포넌트가 붙어 있느데

이 버튼 컴포넌트에 On Click부분에 활성화/비활성화 하고 싶은 게임 오브젝트를 넣고

기본적으로 제공해주는 GameObject.SetActive를 선택하고 체크를 하면 SetActive(true)가 되는 것이고
해제를 하면 false가 되는 것이다.

  • 어려웠던 점
    캐릭터의 스탯을 더해주려고 할 때

    public List<CharacterStats> statsModifiers = new List<CharacterStats>();

    를 통해 UpdateCharacterStats()에서 foreach문으로

     foreach (CharacterStats modifier in statsModifiers.OrderBy(o => o.statsChangeType))
          {
              if (modifier.statsChangeType == StatsChangeType.Override)
              {
                  UpdateStats((o, o1) => o1, modifier);
              }
              else if (modifier.statsChangeType == StatsChangeType.Add)
              {
                  UpdateStats((o, o1) => o + o1, modifier);
              }
              else if (modifier.statsChangeType == StatsChangeType.Sub)
              {
                  UpdateStats((o, o1) => o - o1, modifier);
              }
          }

    UpdateStats을 불러와 스탯을 업데이트 하는데 UpdateStats의 구조를 이해하는게 어려웠지만

     private void UpdateStats(Func<float, float, float> operation, CharacterStats newModifier)
      {
          CurrentStats.level = (int)operation(CurrentStats.level, newModifier.level);
          CurrentStats.exp = (int)operation(CurrentStats.exp, newModifier.exp);
          CurrentStats.gold = (int)operation(CurrentStats.gold, newModifier.gold);
          if (CurrentStats.statSO == null || newModifier.statSO == null)
              return;
          UpdateBattleStats(operation, CurrentStats.statSO, newModifier.statSO);
      }
      private void UpdateBattleStats(Func<float, float, float> operation, StatSO currentStat, StatSO newStat)
      {
          if (currentStat == null || newStat == null)
          {
              return;
          }
          currentStat.Atk = operation(currentStat.Atk, newStat.Atk);
          currentStat.Def = operation(currentStat.Def, newStat.Def);
          currentStat.Health = operation(currentStat.Health, newStat.Health);
          currentStat.Critical = operation(currentStat.Critical, newStat.Critical);
      }

    이렇게 짜 두면 스크립트를 따로 쓸 필요 없이 스탯을 계산 할 수 있다는 것을 알았다.

진행 사항

개인과제 마무리 및 제출
개인과제 피드백 및 회고 (진행중)

내일 할 일

  • 하루 계획
    <졸업 작품>
    • 안드로이드 토스 결제 기능 구현
    • 데이터베이스에서 상품 데이터 가져오는 기능 구현
    <강의 듣기>
    • 유니티 숙련 강의 어려웠던 부분이나 이해한된 부분, 못 들었던 부분 재수강
profile
학생입니다

0개의 댓글