오늘은 내일 제출인 유니티 개인프로젝트를 마무리하고, 챌린지반 특강을 들었다.
프로젝트
구현 내용
인벤토리
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Inventory : MonoBehaviour
{
public List<GameObject> InventorySlot = new List<GameObject>();
public List<GameObject> InventorySlotTempImage = new List<GameObject>();
private Image image;
private SpriteRenderer spriteRenderer;
private Weapon weapon;
private Armor armor;
private void Start()
{
ShowItemInInventory();
}
private void ShowItemInInventory()
{
int count = 0;
foreach(GameObject item in InventorySlot)
{
// 인벤토리 창에 이미지 표시
InventorySlotTempImage[count].SetActive(true);
image = InventorySlotTempImage[count].GetComponent<Image>();
spriteRenderer = item.GetComponent<SpriteRenderer>();
image.sprite = spriteRenderer.sprite;
// 장비 장착 여부 확인
if(item.tag == "WeaponItem")
{
weapon = item.GetComponent<Weapon>();
if(weapon.isEquip == true)
{
InventorySlotTempImage[count].transform.Find($"EquipButton{count}/Text (TMP)").gameObject.SetActive(true);
}
}
else
{
armor = item.GetComponent<Armor>();
if (armor.isEquip == true)
{
InventorySlotTempImage[count].transform.Find($"EquipButton{count}/Text (TMP)").gameObject.SetActive(true);
}
}
count++;
}
}
}
InventoryManger가 관리하도록 했으며, 인스펙터창에 각 슬롯을 연결하여 Inventory List에 있는 아이템들의 이미지로 변경했다. 장비 장착 여부를 확인하기 위해서는 Item 스크립트의 isEquip에 접근하여야 하는데, 모든 아이템은 Item을 상속받는 Weapon과 Armor 두가지 뿐이다. 그래서 두 스크립트를 구분하기 위해, Tag로 구분했다. 사실 좋은 방법은 아닌 것 같지만 부모 클래스인 Item에 접근하기 위해 여러가지 시도를 해봤지만 잘 되지 않았다. 이 부분은 추후, 수정해야 할 것 같다. 그리고 isEquip 의 true, false 값에 따라, 장착 표시[E]를 SetActive 해주었다.
장착 리스트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Equipment : MonoBehaviour
{
public List<GameObject> equipmentList;
[SerializeField] private Player player;
private Weapon weapon;
private Armor armor;
private void Start()
{
equipmentList = new List<GameObject>();
}
public void Equip(GameObject item)
{
equipmentList.Add(item);
if (item.tag == "WeaponItem")
{
weapon = item.GetComponent<Weapon>();
player.SetPlusAtk(weapon.atk);
}
else
{
armor = item.GetComponent<Armor>();
player.SetPlusDef(armor.def);
player.SetPlusHp(armor.Hp);
}
}
public void DisEquip(GameObject item)
{
equipmentList.Remove(item);
if (item.tag == "WeaponItem")
{
weapon = item.GetComponent<Weapon>();
player.SetPlusAtk(-weapon.atk);
}
else
{
armor = item.GetComponent<Armor>();
player.SetPlusDef(-armor.def);
player.SetPlusHp(-armor.Hp);
}
}
}
장착 List를 따로 구현해서 장착한 Item들을 List로 따로 관리했다. 그리고 아이템 장착 또는 해제 시, 각 아이템의 능력만큼 플레이어에게 적용하도록 했다.
버튼
using UnityEngine.EventSystems;
public string GetButtonName()
{
string EventButtonName = EventSystem.current.currentSelectedGameObject.name;
return EventButtonName;
}
public void EquipButton()
{
string str = GetButtonName().Substring(11);
int count = int.Parse(str);
if(inventory.InventorySlot[count].tag == "WeaponItem")
{
weapon = inventory.InventorySlot[count].GetComponent<Weapon>();
if (weapon.isEquip == true)
{
weapon.isEquip = false;
inventory.InventorySlotTempImage[count].transform.Find($"EquipButton{count}/Text (TMP)").gameObject.SetActive(false);
equipment.DisEquip(inventory.InventorySlot[count]);
}
else
{
weapon.isEquip = true;
inventory.InventorySlotTempImage[count].transform.Find($"EquipButton{count}/Text (TMP)").gameObject.SetActive(true);
equipment.Equip(inventory.InventorySlot[count]);
}
}
else
{
armor = inventory.InventorySlot[count].GetComponent<Armor>();
if (armor.isEquip == true)
{
armor.isEquip = false;
inventory.InventorySlotTempImage[count].transform.Find($"EquipButton{count}/Text (TMP)").gameObject.SetActive(false);
equipment.DisEquip(inventory.InventorySlot[count]);
}
else
{
armor.isEquip = true;
inventory.InventorySlotTempImage[count].transform.Find($"EquipButton{count}/Text (TMP)").gameObject.SetActive(true);
equipment.Equip(inventory.InventorySlot[count]);
}
}
}
클릭한 버튼 이름에 접근해서 인벤토리 순서에 있는 아이템에 접근하도록 했다.
특강 내용
안좋은 코드란?
1. 이상한 이름
- 명확한 이름이 떠오르지 않는다면 설계가 잘못되었을 수 있다는 것을 명심
- 이름을 잘 짓는 것은 아주 중요
2. 중복 코드
- 똑같은 구조의 반복은 최악임
3. 긴 함수
- 짧은 함수와 좋은 이름의 조합이 최고
- 짧은 함수는 재사용성도 좋고, 코드를 이해하고 공유하기도 쉬움
- 하나의 함수에서 길게 모든걸 처리하는 것보다는 짧은 함수를 여러개를 호출하는 구조가 좋음
4. 전역 변수의 남용
- 전역 변수는 어디서나 변경이 가능해서, 변경 시점을 추적하기 힘들고, 디버깅을 어렵게 만들고, 버그의 원인이 됨
- 전역변수를 사용해야만 할 경우, 변수를 캡슐화하는 것을 습관화 해야함
5. 주석의 남용
- 주석을 사용하지 않고, 코드만으로 명확하게 이해되는게 더 좋음
- 주석이 필요한 상황일 경우, 주석이 필요없는 코드로 먼저 바꾸는게 우선임
6. 가변 데이터
- 중요한 데이터 불변성의 개념
- 데이터가 생성된 후에는 데이터가 변경 되는 것에는 신중을 가해야 함
7. 뒤엉킨 변경
- 하나의 클래스는 하나의 기능만 하도록 함
8. 기본형 집착
- 복잡한 데이터를 단순한 기본형 (int, string)에 과도하게 의존하는 경향
- 복잡한 개념은 기본형 대신 클래스나, 구조체를 사용해서 미리 해결
9. 반복되는 switch, if 문
- switch문은 협업에서 거의 안쓰는 구조
- 객체지향 프로그래밍의 다형성을 활용해야 함
10. 성의 없는 요소
- 필요하지 않는 클래스, 메소드, 인터페이스는 그때 그때 삭제해주거나, 인라인화를 해야함
오늘의 회고
오늘 들었던 특강은 저번에 들었던 안좋은 코드에 대해서 이어서 강의했다. 전체적으로 정리를 하고 항상 코드 작성시 유의를 해야할 것 같다. 그리고 오늘 유니티 개인 프로젝트를 어찌저찌 완성했다. 결과물은 나름 괜찮았지만, 코드 내용은 상당히 복잡하고, 특강에서 들었던 안좋은 코드라고 느껴지는 부분이 많았다. 특히, 인벤토리는 원래 각각의 슬롯이 개별적으로 작동해야 하지만, 내가 구현한 인벤토리는 항상 인벤토리 List를 순회해서 순서대로 이미지를 띄우는 방식이었다. 프로젝트 구현 기준에는 무리가 없지만 더욱 큰 게임을 만들기 위해서는 다른 방법으로 인벤토리를 구현하는 방법도 생각을 해봐야 할 것 같다.
'Unity_2기 내일배움캠프 TIL' 카테고리의 다른 글
Unity_2기 6주차 (231214) (0) | 2023.12.14 |
---|---|
Unity_2기 6주차 (231213) (0) | 2023.12.13 |
Unity_2기 6주차 (231211) (0) | 2023.12.11 |
Unity_2기 5주차 (231208) (0) | 2023.12.08 |
Unity_2기 5주차 (231207) (1) | 2023.12.07 |