이제 슬슬 막바지에 다다르고 있는 느낌이 든다.
이번 포스팅에서는 아이템을 인벤칸 내에서 이동하는 코드를 작성해보자.
아이템 드래그 추가적인 처리
아이템 드래그를 해서 이제 큇슬롯에 등록하는 거를 아이템 드래그의 마지막에서 했다.
이제 이것을 추가적인 처리를 해주어야한다.
_icon.gameObject.BindEvent((e) =>
{
if (itemData == null) return;
if (dragObj == null) return;
Managers.Resource.Destroy(dragObj);
string name = e.pointerCurrentRaycast.gameObject.name;
if (name == null) return;
// 아이템 창끼리 인벤 교환
if (name.Contains("InventorySlot_"))
{
RequestChangeInvenSlot(ExtractNumberFromName(name));
return;
}
if(itemData.itemType == ItemType.Consumable && name != null)
(Managers.UI.SceneUI as UI_GameScene).RequestQuickSlotUI(name, TemplateId, false);
}, Define.UIEvent.DragEnd);
public void RequestChangeInvenSlot(int changeSlotNum)
{
if (changeSlotNum == -1) return;
Item item = Managers.Inven.Get(ItemDbID);
if (item == null) return;
int curSlot = item.Slot;
if (changeSlotNum == curSlot)
return;
C_ChangeItemSlot changeSlot = new C_ChangeItemSlot()
{
ItemDbId = ItemDbID,
CurSlot = curSlot,
ChangeItemSlot = changeSlotNum
};
Managers.Network.Send(changeSlot);
}
public int ExtractNumberFromName(string name)
{
Match match = Regex.Match(name, @"\d+");
if (match.Success)
{
return int.Parse(match.Value);
}
return -1;
}
필자의 경우 아이템의 Inven의 각각의 Slot은 InventorySlot_{숫자}형태로 이루어져있다. 그렇기 때문에 드래그가 끝난 위치가 InventorySlot_를 포함하고 있는지 확인하고 만약 그렇다고 한다면 아이템 슬롯 옮기기를 진행한다.
Extract를 통해 어떤 Slot의 위치로 가려고 하는지를 추출해서 Request한다. 이때 인벤에 아이템이 존재하지 않는 경우는 옮기려고 하는 위치가 현재 위치랑 같거나 하는 등등 예외처리를 하고 어떤 아이템이, 어떤 위치에서 어떤 위치로 가는지를 서버에 알려주는 패킷을 보낸다.
서버 처리
public void HandleChangeItemSlot(C_ChangeItemSlot itemSlotPacket)
{
Item curItem = Inven.Get(itemSlotPacket.ItemDbId);
if (curItem == null)
return;
Item pointItem = Inven.Find(i=> i.Slot == itemSlotPacket.ChangeItemSlot);
if(pointItem == null)
{
curItem.Slot = itemSlotPacket.ChangeItemSlot;
pointItem = new Item(ItemType.None) { ItemDbId = -1, Slot = -1, Count = -1 };
MakeChangeItemSlotPacket(curItem, pointItem);
}
else
{
if (curItem.Slot == pointItem.Slot) return;
if(curItem.TemplateId == pointItem.TemplateId && curItem.ItemType == ItemType.Consumable && pointItem.ItemType == ItemType.Consumable)
{
if (DataManager.ItemDict.TryGetValue(pointItem.TemplateId, out ItemData itemData) == false) return;
int maxCount = ((ConsumableData)itemData).maxCount;
if (pointItem.Count == maxCount) return;
int addCount = curItem.Count + pointItem.Count;
if (addCount > maxCount)
{
curItem.Count -= (maxCount - pointItem.Count);
pointItem.Count = maxCount;
MakeChangeItemSlotPacket(curItem, pointItem);
}
else
{
pointItem.Count = addCount;
Inven.Remove(curItem);
curItem.Slot = -1;
curItem.Count = -1;
MakeChangeItemSlotPacket(curItem, pointItem);
}
}
else
{
(pointItem.Slot, curItem.Slot) = (curItem.Slot, pointItem.Slot);
MakeChangeItemSlotPacket(curItem, pointItem);
}
}
DbTransaction.ChangeItemSlotNoti(this, curItem, pointItem);
}
public void MakeChangeItemSlotPacket(Item curItem, Item pointItem)
{
S_ChangeItemSlot changeItemSlotOk = new S_ChangeItemSlot()
{
ItemDbIdOne = curItem.ItemDbId,
CountOne = curItem.Count,
SlotOne = curItem.Slot,
ItemDbIdTwo = pointItem.ItemDbId,
SlotTwo = pointItem.Slot,
CountTwo = pointItem.Count
};
Session.Send(changeItemSlotOk);
}
서버쪽 처리가 조금 복잡할 수 있다.
크게 4가지로 분류할 수 있다.
- 내가 옮기려고 한 슬롯에 아이템이 존재하지 않는경우
- 내가 옮기려고 한 슬롯에 아이템이 존재하며 아이템 id가 같고 겹칠 수 있는 아이템이여서 겹치면 최대 개수를 넘지 않는 경우
- 내가 옮기려고 한 슬롯에 아이템이 존재하며 아이템 id가 같고 겹칠 수 있는 아이템이지만 겹치면 최대 개수를 넘어가는 경우
- 위의 상황이 아니며 내가 옮기려고 한 슬롯에 아이템이 존재하는 경우
로 분류할 수 있다. 이제 DB에는 다음과 같이 저장한다.
public static void ChangeItemSlotNoti(Player player, Item curItem, Item pointItem = null)
{
if (player == null) return;
ItemDb item1 = new ItemDb()
{
ItemDbId = curItem.ItemDbId,
Count = curItem.Count,
Slot = curItem.Slot,
};
ItemDb item2 = null;
if(pointItem != null)
{
item2 = new ItemDb()
{
ItemDbId = pointItem.ItemDbId,
Count = pointItem.Count,
Slot = pointItem.Slot,
};
}
Instance.Push(() => {
using (AppDbContext db = new AppDbContext())
{
if(curItem.Slot == -1)
{
ItemDb itemDb = db.Items.SingleOrDefault(i => i.ItemDbId == curItem.ItemDbId);
db.Items.Remove(itemDb);
}
else
{
db.Entry(item1).State = EntityState.Unchanged;
db.Entry(item1).Property(nameof(ItemDb.Slot)).IsModified = true;
db.Entry(item1).Property(nameof(ItemDb.Count)).IsModified = true;
}
if(item2 != null)
{
db.Entry(item2).State = EntityState.Unchanged;
db.Entry(item2).Property(nameof(ItemDb.Slot)).IsModified = true;
db.Entry(item2).Property(nameof(ItemDb.Count)).IsModified = true;
}
bool success = db.SaveChangesEx();
if (!success)
{
}
}
});
}
위의 상황에 맞춰 DB를 수정하거나 삭제한다.
클라이언트 아이템 위치 변경
이제 서버쪽에서 슬롯의 위치를 바꾸거나 Count를 변경했으니 클라이언트에서도 이를 맞춰 변경해주어야한다.
public static void S_ChangeItemSlotHandler(PacketSession session, IMessage packet)
{
S_ChangeItemSlot itemSlot = (S_ChangeItemSlot)packet;
if(itemSlot.SlotOne == -1 && itemSlot.ItemDbIdTwo != -1)
{
Item item1 = Managers.Inven.Get(itemSlot.ItemDbIdOne);
Item item2 = Managers.Inven.Get(itemSlot.ItemDbIdTwo);
if (item1 == null || item2 == null) return;
Managers.Inven.Remove(item1);
item2.Count = itemSlot.CountTwo;
item2.Slot = itemSlot.SlotTwo;
}
else
{
// 빈 곳에 아이템 옮김
if(itemSlot.ItemDbIdTwo == -1)
{
Item item = Managers.Inven.Get(itemSlot.ItemDbIdOne);
if (item == null) return;
item.Count = itemSlot.CountOne;
item.Slot = itemSlot.SlotOne;
}
else
{
Item item1 = Managers.Inven.Get(itemSlot.ItemDbIdOne);
Item item2 = Managers.Inven.Get(itemSlot.ItemDbIdTwo);
if (item1 == null || item2 == null) return;
item1.Count = itemSlot.CountOne;
item1.Slot = itemSlot.SlotOne;
item2.Count = itemSlot.CountTwo;
item2.Slot = itemSlot.SlotTwo;
}
}
UI_GameScene gameSceneUI = Managers.UI.SceneUI as UI_GameScene;
gameSceneUI.InvenUI.RefreshUI();
}
위의 상황에 맞춰 똑같이 진행하면된다.
결과 영상
큇슬롯에서는 인벤에 있는 같은 templateId 의 Count를 측정해서 띄워주는것도 같이 확인할 수 있다.
'Unity > 온라인 RPG' 카테고리의 다른 글
[Unity 3D] 클라이언트, 서버 최적화 (0) | 2024.07.04 |
---|---|
[Unity 3D] 상점 Npc - 아이템 구매, 판매하기 (0) | 2024.07.04 |
[Unity 3D] UI 이미지 드래그 그리고 퀵슬롯 등록하기 (0) | 2024.06.21 |
[Unity 3D] 스탯 포인트 사용하기 (0) | 2024.06.11 |
[Unity 3D] 획득한 아이템 착용하기 (1) | 2024.06.11 |