지난 포스팅까지는 플레이어와 몬스터간의 전투까지 진행했다.
이제 몬스터가 죽은 후 아이템을 떨구면 플레이어가 습득하는 과정이 필요한데 이를 위해서 먼저 Inventory창이 필요할거 같아 먼저 제작한다.
Inven을 만드는 김에 각종 다른 UI 까지 동시에 제작해보자.
InventoryUI
인벤토리의 구성은 창을 드래그할 수 있는 Title과 아이템들을 담을 수 있는 Grid 그리고 골드로 구성되어 있다.
여기에 나와있는 값들은 전부 서버에서 데이터를 긁어와서 채워주어야만 한다.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class UI_Inventory : UI_Base
{
enum Buttons
{
ExitButton
}
enum Texts
{
CoinText
}
public List<UI_InvenSlot> Items { get; } = new List<UI_InvenSlot>();
public GameObject grid;
public override void Init()
{
BindButton(typeof(Buttons));
BindText(typeof(Texts));
GetButton((int)Buttons.ExitButton).gameObject.BindEvent((e) => { var ui = Managers.UI.SceneUI as UI_GameScene; ui.CloseUI("Inven"); });
Items.Clear();
foreach (Transform child in grid.transform)
Destroy(child.gameObject);
for (int i = 0; i < 24; i++)
{
GameObject go = Managers.Resource.Instantiate("UI/SubItem/UI_InvenSlot", grid.transform);
UI_InvenSlot item = go.GetOrAddComponent<UI_InvenSlot>();
Items.Add(item);
}
RefreshUI();
}
public void RefreshUI()
{
if (Items.Count == 0)
return;
List<Item> items = Managers.Inven.Items.Values.ToList();
items.Sort((left, right) => { return left.Slot - right.Slot; });
foreach (Item item in items)
{
if (item.Slot < 0 || item.Slot >= 24)
continue;
Items[item.Slot].SetItem(item);
}
GetText((int)Texts.CoinText).text = Managers.Inven.Money.ToString("N0");
}
}
이 작업은 단순히 InventoryManager에서 데이터를 긁어와 뿌리는 역할인 것이다.
그렇다면 InventoryManager는 어떻게 구성이될까
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InventoryManager
{
public Dictionary<int, Item> Items { get; } = new Dictionary<int, Item>();
public Item[] EquipItems { get; } = new Item[8];
public int Money { get; set; }
public void Add(Item item)
{
Items.Add(item.ItemDbId, item);
}
public Item Get(int itemDbId)
{
Item item = null;
Items.TryGetValue(itemDbId, out item);
return item;
}
public Item Find(Func<Item, bool> condition)
{
foreach (Item item in Items.Values) {
if (condition.Invoke(item))
{
return item;
}
}
return null;
}
public void Clear()
{
Items.Clear();
}
public void Remove(Item item)
{
Items.Remove(item.ItemDbId);
}
public void EquipAdd(int i, Item item)
{
EquipItems[i] = item;
}
public Item EquipGet(int i)
{
if (EquipItems[i] == null)
return null;
return EquipItems[i];
}
public void EquipClear()
{
for (int i = 0; i < EquipItems.Length; i++)
{
EquipItems[i] = null;
}
}
public void EquipRemove(int i)
{
EquipItems[i] = null;
}
public void AddMoney(int add)
{
Money += add;
}
}
단순히 가지고 있는 아이템을 Dictionary로 가지고 있는 것이다. 또한 착용 중인 아이템과 골드도 여기서 관리한다.
플레이어가 로비에서 특정 캐릭터로 접속할 때, 이전에는 플레이어에 대한 정보만 클라로 보내주었는데 이제 데이터베이스에 있는 아이템 정보를 플레이어의 Inven에 넣어주면 된다.
public static void S_ItemListHandler(PacketSession session, IMessage packet)
{
S_ItemList itemList = (S_ItemList)packet;
Managers.Inven.Clear();
// 메모리에 아이템 정보 적용
foreach (ItemInfo itemInfo in itemList.Items)
{
Item item = Item.MakeItem(itemInfo);
Managers.Inven.Add(item);
}
Managers.Inven.Money = itemList.Money;
}
이런식으로 말이다. 물론 이건 클라입장에서만 서술한 것이다. 서버쪽에서는 AppdbContext에 접근해서 데이터를 전부 긁어와 S_ItemList 패킷으로 보내야한다.
이렇게 간단하게 Inventory를 만들 수 있다.
StatUI
스탯을 보여주는 UI는 더 별게 없다. 단순히 현재 저장된 Player의 StatInfo를 가져와 출력하는게 전부이다.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class UI_Stat : UI_Base
{
MyPlayerController myPlayer;
bool isInit = false;
enum Texts
{
PlayerStatNameText,
AttackText,
RemainPointText,
StrText,
DexText,
LukText,
IntText,
HpText,
MpText,
}
enum Buttons
{
ExitButton,
StrUpButton,
DexUpButton,
LukUpButton,
IntUpButton
}
public override void Init()
{
BindText(typeof(Texts));
BindButton(typeof(Buttons));
GetButton((int)Buttons.ExitButton).gameObject.BindEvent((e) => { var ui = Managers.UI.SceneUI as UI_GameScene; ui.CloseUI("Stat"); });
myPlayer = Managers.Object.MyPlayer;
isInit = true;
RefreshUI();
}
public void RefreshUI()
{
if (isInit == false) return;
GetText((int)Texts.PlayerStatNameText).text = $"닉네임 : <color=#F3E3AE>{myPlayer.objectInfo.Name}</color>";
GetText((int)Texts.HpText).text = $"HP\t: <color=#F3E3AE>{myPlayer.Hp}</color> / <color=#F3E3AE>{myPlayer.MaxHp}</color>";
GetText((int)Texts.MpText).text = $"MP\t: <color=#F3E3AE>{myPlayer.Mp}</color> / <color=#F3E3AE>{myPlayer.MaxMp}</color>";
GetText((int)Texts.AttackText).text = $"공격력\t: <color=#F3E3AE>{myPlayer.MinAttack}</color> ~ <color=#F3E3AE>{myPlayer.MaxAttack}</color>";
GetText((int)Texts.RemainPointText).text = $"남은 스텟 포인트 : <color=#F3E3AE>{myPlayer.Stat.StatPoint}</color>";
GetText((int)Texts.StrText).text = $"Str\t: <color=#F3E3AE>{myPlayer.Stat.Str}</color>";
GetText((int)Texts.DexText).text = $"Dex\t: <color=#F3E3AE>{myPlayer.Stat.Dex}</color>";
GetText((int)Texts.LukText).text = $"Luk\t: <color=#F3E3AE>{myPlayer.Stat.Luk}</color>";
GetText((int)Texts.IntText).text = $"Int\t: <color=#F3E3AE>{myPlayer.Stat.Int}</color>";
}
}
EquipUI
장비창도 딱히 다를건 없다. 인벤과 마찬가지로 데이터를 긁어 표기만 해주는 역할이다.
아직은 장비를 착용하는 기능은 없기에 추후 테스트를 하며 코드가 추가될 것이다.
using Data;
using Google.Protobuf.Protocol;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UI_Equip : UI_Base
{
enum Images
{
HelmetIcon,
ArmorIcon,
ShieldIcon,
BootsIcon,
CapeIcon,
WeaponIcon,
GlovesIcon,
AssistanceWeaponIcon,
}
enum Buttons
{
ExitButton,
}
public override void Init()
{
BindButton(typeof(Buttons));
BindImage(typeof(Images));
GetButton((int)Buttons.ExitButton).gameObject.BindEvent((e) => { var ui = Managers.UI.SceneUI as UI_GameScene; ui.CloseUI("Stat"); });
RefreshUI();
}
public void RefreshUI()
{
for (int i = 0; i < 8; i++)
{
GetImage(i).enabled = false;
}
Item[] items = Managers.Inven.EquipItems;
for (int i = 0; i < items.Length; i++)
{
if (items[i] != null)
{
ItemData itemData = null;
if (Managers.Data.ItemDict.TryGetValue(items[i].TemplateId, out itemData) == false)
return;
Sprite icon = Managers.Resource.Load<Sprite>(itemData.iconPath);
if (items[i].ItemType == ItemType.Weapon)
{
Weapon weapon = (Weapon)items[i];
if (weapon.WeaponType == WeaponType.Assistance)
{
GetImage((int)Images.AssistanceWeaponIcon).enabled = true;
GetImage((int)Images.AssistanceWeaponIcon).sprite = icon;
}
else
{
GetImage((int)Images.WeaponIcon).enabled = true;
GetImage((int)Images.WeaponIcon).sprite = icon;
}
}
else if (items[i].ItemType == ItemType.Armor)
{
Armor armor = (Armor)items[i];
switch (armor.ArmorType)
{
case ArmorType.Helmet:
GetImage((int)Images.HelmetIcon).enabled = true;
GetImage((int)Images.HelmetIcon).sprite = icon;
break;
case ArmorType.Armor:
GetImage((int)Images.ArmorIcon).enabled = true;
GetImage((int)Images.ArmorIcon).sprite = icon;
break;
case ArmorType.Boots:
GetImage((int)Images.BootsIcon).enabled = true;
GetImage((int)Images.BootsIcon).sprite = icon;
break;
case ArmorType.Cape:
GetImage((int)Images.CapeIcon).enabled = true;
GetImage((int)Images.CapeIcon).sprite = icon;
break;
case ArmorType.Gloves:
GetImage((int)Images.GlovesIcon).enabled = true;
GetImage((int)Images.GlovesIcon).sprite = icon;
break;
}
}
}
}
}
}
전체적인 모습
전체적인 모습은 다음과 같다. UI끼리 서로 가려도 되는 이유는 UI를 드래그로 원하는 위치로 이동하게 설정해두었고 UI의 order를 내가 트는 UI의 순서에 따라 자동으로 조절하도록 만들었기 때문에 걱정안해도 된다.
'Unity > 온라인 RPG' 카테고리의 다른 글
[Unity 3D] 획득한 아이템 착용하기 (1) | 2024.06.11 |
---|---|
[Unity 3D] 아이템 드랍 및 획득 (0) | 2024.05.29 |
[Unity 3D] 오브젝트 전투 및 몬스터의 플레이어 추격 (0) | 2024.05.13 |
[Unity 3D] 몬스터 움직임 동기화 with Dedicated Server (0) | 2024.05.02 |
[Unity 3D] 캐릭터 공격 애니메이션 동기화 (0) | 2024.04.24 |