본문 바로가기

TIL

[TIL]2024-2-06 / 32일차 - 개인 과제 버그 수정

어제까지 진행 상황 - UI들은 완성됬지만 다 깡통 상태이다.

 

1. 오늘의 코드 카타 - 3진법

 

답안 :

//공부한 결과 2가지 방법이 존재한다. 하나는 1대1로 과정을 따라하는 것. 하나는 while문을 이용하는 것
//1대1로 따라하는 것은 10진수를 3진법으로 -> 3진수를 10진법으로 변환하는 모든 과정을 따라서 만드는 것. 불가능 하지 않으나 시도해보다가 굉장히 길어졌다.
//다음 방법인 while문은 이 과정을 짧게 표현한 것으로 좀 복잡한 개념이 필요하다.
//answer값이 0으로 시작하는 점을 이용해 n에서 나머지가 나올 때 까지 n값만이 while문에서 3으로 나눠지는 점을 이용
//이후 나머지를 받고 n이 0이 될 때까지 반복, 리턴되는 결과값이 처음 방법과 같다.
using System;

public class Solution {
    public int solution(int n) {
        int answer=0;
    while(n>0)
    {
        answer*=3;
        answer+=n%3;
        n/=3;
    }
    return answer;
    }
}

 

또 주석에다가 고봉밥을 달아 버렸다. 개념에 대해 아는게 중요한 것이므로 추가로 설명은 더 할 필요 없을 것 같다.

 

 


 

 

오늘은 어제 깡통으로 만들어진 UI들에가다가 코드를 만들어 주었다.

대부분 숙련 주차 서바이벌 게임 만들기 강의 영상에서 나온 인벤토리 시스템 만들기를 통해 구현해 볼 수 있었고 스탯 부분도 그 부분이 해결되자 오래 걸리지는 않았다.

 

STORE버튼은 아직 상점 기능이 구현되지 않아 작동하지 않는다.

 

 

오늘 추가된 기능들

- 아이템 장착 기능 완성 ( 장착 표시, 장착 시 갑옷 / 무기 구분, 이전 장비 해체 )

- 스탯 기능 구현 ( 체력 회복, 장비에 따른 공격력 방어력 상승 )

- 드래그앤드롭 UI 기능 개선

- 골드 창 통화 단위 구분

 


 

아이템 장착 기능 완성 + 스탯 기능 구현

구동 모습

장착 기능 부분은 강의에서 제공된 기능 대다수를 사용하여 방어구와 무기 착용으로 코드를 개조했는데,

여기서 예상치 못한 문제가 발생해서 오랜 시간을 소모하게 되었다.

 

원래 선택했던 아이템의 인덱스를 저장하는 기능이 있었는데 그 부분을 방어구와 무기로 나누어 두었다. 그런데 이를 지정하면서 둘다 int (함수명)으로만 선언 해둔 것이 문제가 되었다.

내부적으로 아이템의 인덱스는 0으로 시작하게 되어있는데 int (함수명) = -1 같은 방식으로 선언 해둔 것이 아니라서 기본값인 0으로 두 가지 값이 다 저장되어 있던 것.

    public void OnEquipButton()
    {
        if (selectedItem.item.type == ItemType.Weapon && uiSlots[curEquipWeaponIndex].equipped)
        {
            UnEquip(curEquipWeaponIndex);
        }
        else if (selectedItem.item.type == ItemType.Armor && uiSlots[curEquipArmorIndex].equipped)
        {
            UnEquip(curEquipArmorIndex);
        }
            ..... 생략

 

 

그래서 장착을 담당하던 버튼 코드에서 무기와 방어구를 구분하던 부분이 무기를 장착 후 방어구를 장착하려고 할 때 인덱스 0번에 있던 무기를 멋대로 장착해제한 뒤 방어구를 장착했던 것.

 

이 부분을 인지하지 못하고 여러 부분으로 코드를 살펴봐야 했고 이 과정 속에서 어먼 부분들을 왕창 뜯어 고쳤었다.

 

그렇지만 디버그 로그를 온갓 곳에다가 적어두고 테스트 하던 중 해당 부분이 불러져야 하지 않을 때 불러지고 있다는 것을 확인할 수 있었다.

 

    public void OnEquipButton()
    {
        if (curEquipWeaponIndex >= 0 && selectedItem.item.type == ItemType.Weapon && uiSlots[curEquipWeaponIndex].equipped)
        {
            UnEquip(curEquipWeaponIndex);
        }
        else if (curEquipArmorIndex >= 0 && selectedItem.item.type == ItemType.Armor && uiSlots[curEquipArmorIndex].equipped)
        {
            UnEquip(curEquipArmorIndex);
        }
            ..... 생략

 

이를 해결하는 방법으로 우선 선언했던 함수를 int (함수명) = -1;로 바꾸었고 조건문에도 인덱스가 0보다 크거나 같을 때라고 선 확인 하는 조건을 달아주어 해결되었다.

 

이것이 해결되고 나니 장착중 bool 상태가 true가 되면 착용중 마크를 띄우는 것 use버튼 이용 시 소모품을 하나씩 destroy하고 playerstats에서 회복하는 방법 등등 다 순조롭게 해결 되었다.

 

 

스탯은 강의를 따라하다 보니 내가 기존에 생각하고 쓰던 방식과는 조금 다르게 만들었다.

public class Condition
{
    //[HideInInspector]

    public float curValue;
    public float maxValue;
    public float startValue;
    public Text uiValueText;

    public void Add(float amount)
    {
        curValue = Mathf.Min(curValue + amount, maxValue);
    }

    public void Subtract(float amount)
    {
        curValue = Mathf.Max(curValue - amount, 0.0f);
    }
}

public class PlayerStats : MonoBehaviour
{
    public Condition health;
    public Condition attack;
    public Condition defense;

    public void Start()
    {
        health.curValue = health.startValue;
        attack.curValue = attack.startValue;
        defense.curValue = defense.startValue;
    }
......생략

 

스탯은 현재 이와 같은 방식으로 저장되고 있는데 이에다가 내부적으로는 수치 변화를 주는 것은 어렵지 않았기에 이를 위해 스탯의 변화를 시각적으로 보여주는 스탯 UI용 스크립트를 만들었다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using static UnityEditor.Progress;

public class StatUI : MonoBehaviour
{
    private PlayerStats playerStats;

    public Text healthText;
    public Text attackText;
    public Text defeseText;

    public void Awake()
    {
        playerStats = GetComponent<PlayerStats>();
        healthText.text = playerStats.health.startValue.ToString();
        attackText.text = playerStats.attack.startValue.ToString();
        defeseText.text = playerStats.defense.startValue.ToString();
    }

    public void Update()
    {
        healthText.text = playerStats.health.curValue.ToString();
        attackText.text = playerStats.attack.curValue.ToString();
        defeseText.text = playerStats.defense.curValue.ToString();
    }
}

 

이미 장비를 장착할 때 해당 장비의 값을 Add 혹은 Subtract 메소드를 이용해 내부적으로는 스탯에 변화를 주고있는 만큼 이와같은 코드로 그것이 스탯창에 연결되도록 하였다.

 

    public void StatAdd(string statName ,float amount)
    {
        if(statName ==  "health")
        {
            health.Add(amount);
        }
        else if (statName == "attack")
        {
            attack.Add(amount);
        }
        else if (statName == "defense")
        {
            defense.Add(amount);
        }
    }

    public void StatSubtract(string statName ,float amount)
    {
        if (statName == "health")
        {
            health.Subtract(amount);
        }
        else if (statName == "attack")
        {
            attack.Subtract(amount);
        }
        else if (statName == "defense")
        {
            defense.Subtract(amount);
        }
    }

 

스탯에 증가와 감소는 playerstats에 있는 add와 subtract를 이용해서 스탯이름을 받아 해당 스탯 변화를 주는 메소드를 만들어 두었다. 지금 생각해보니 스위치문으로 만들어도 되지 않았을까 싶다. 내가 if조건문이 익숙해서 그런 것 같다.

 


 

드래그앤드롭 UI 기능 개선

 

어제도 ToDo로서 남겨둔 기능으로, UI를 이동시키고 나서 위치 초기화를 어떻게 시켜야될까 고민했다. 이를 조원께서 조언을 주었고, UI를 키고 끄는 버튼에서 위치를 저장하면 될 것 같다는 이야기를 듣고 좋은 생각 같아 그대로 만들어 보려고 했다. 보자마자 방법을 가르쳐 주다니 역시 잘하는 사람들은 다르다.

 

원래 버튼 스크립트는 단순히 창 두개를 입력받아 하나는 끄고 하나는 키는 메소드 하나만 가지고 있었는데,

이를 나갈 때와 진입할 때, 두 가지 메소드로 나누어 진입할 때 벡터값을 저장 받고 이를 나갈 때 돌려받는 방식으로 하였다.

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

public class UIButton : MonoBehaviour
{
    [SerializeField] private GameObject currentScreen;
    [SerializeField] private GameObject targetUI;
    [SerializeField] private RectTransform UIPosition;
    private Vector2 savedPosition = new Vector2();

    private void Awake()
    {
        savedPosition = UIPosition.anchoredPosition;
    }
    public void OnAccessClick()
    {
        savedPosition = UIPosition.anchoredPosition;
        currentScreen.SetActive(false);
        targetUI.SetActive(true);
    }
    public void OnExitClick()
    {
        currentScreen.SetActive(false);
        targetUI.SetActive(true);
        UIPosition.anchoredPosition = savedPosition;
    }

 

시간이 부족하니 단순하게 만들어 보았다. 타겟UI(킬 화면)을 미리 지정해두어야 작동 하므로 버튼마다 지정해줘야 되서 귀찮은 면도 있지만 자동적으로 할당되게 하는 방법 같은 건 아직 내게 벅차다.

 

사실 지금 생각해보니 굳이 따로 안받고 GetComponent로도 되지 않았을까... 아몰랑

 

 

아무튼 구현된 모습

 


 

 

골드 창 통화 단위 구분

 

현실의 돈은 3자릿수 마다 ,(쉼표)를 적어 칸을 구분한다. 이전 캡처화면에서는 단순히 내가 텍스트에다가 쉼표를 찍어 둔 것이라 장식이지만, MoneyUI 스크립트를 만들어 시작 돈과 현재 돈을 저장하고 해당 값을 3자릿수마다 쉼표를 찍어 골드창에 띄워주는 코드를 만들었다.

 

public class MoneyUI : MonoBehaviour
{
    public int moneyStartValue;
    public int moneyCurValue;
    public Text moneyText;

    private void Awake()
    {
        moneyCurValue = moneyStartValue;
    }
    private void Update()
    {
        moneyText.text = GetThousandCommaText(moneyCurValue).ToString();
    }
    public string GetThousandCommaText(int data) 
    { 
        return string.Format("{0:#,###}", data); 
    }

}

 

이 방법 말고도 코드 리뷰 때 다른 조원은 다른 방식으로도 구현했던데 더 간단해 보여서 신기했다.

 

 

구동 모습 - 실시간으로 돈을 바꾸어 체크


 

오늘은 특강이 1개, 교육 세션이 1개, 조에서 진행하는 개인과제 미니 발표회를 가졌기에 시간이 많이 소요되어 이 이상에 작업을 할 시간은 없었다.

 

노베이스로 시작한 인원이 나 뿐인데다 나를 제외한 조원들은 모두 챌린지 반을 듣고있는 실력자들,

코드 리뷰를 해보니 다른 조원들이 모두 너무 뛰어난 모습을 보여주어 기대가 되면서도 조별과제에 들어서면 내가 짐이 되지는 않을까 걱정이 된다.

 

그런만큼 열심히 해야겠지.