init
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
using System;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Dict;
|
||||
using VOID.Generic.Objects.Abstract.Events;
|
||||
using VOID.Generic.Objects.Item;
|
||||
using VOID.Generic.Objects.Item.Events;
|
||||
using VOID.Generic.Objects.Unit.Events;
|
||||
using VOID.Generic.Util;
|
||||
|
||||
namespace VOID.Generic.Objects.Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// Module of <see cref="UnitObject"/> which manage currently carried items by this unit.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UnitObjectBackpack : ObjectComponent<UnitObject>
|
||||
{
|
||||
#region Initialize
|
||||
|
||||
protected override void SelfInitialize()
|
||||
{
|
||||
// Get empty GameObject where all items from backpack are "attached" - OR - create if missing
|
||||
_backpackGameObject = parent.transform.Find("_backpack")?.gameObject;
|
||||
if (_backpackGameObject == null)
|
||||
{
|
||||
_backpackGameObject = new GameObject("_backpack");
|
||||
_backpackGameObject.transform.parent = parent.gameObject.transform;
|
||||
_backpackGameObject.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
// Instantiate all prefabs
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
if (items[i] == null) continue;
|
||||
|
||||
// Instantiate prefab and get references to its GameObject and ItemObject
|
||||
FakePickOnInit(i, items[i]);
|
||||
}
|
||||
|
||||
Resize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only when <see cref="UnitObject"/> is initializing:<br/>
|
||||
/// - Instantiate item if it is prefab asset<br/>
|
||||
/// - Inform it by events that it has been picked<br/>
|
||||
/// - Finally just resume with <see cref="Take(int,VOID.Generic.Objects.Item.ItemObject)"/><br/>
|
||||
/// </summary>
|
||||
private void FakePickOnInit(int itemIndex, ItemObject item)
|
||||
{
|
||||
// If item is prefab asset then we need to instantiate it first
|
||||
if (!item.gameObject.scene.IsValid())
|
||||
item = UnityEngine.Object.Instantiate(item.gameObject).GetComponent<ItemObject>();
|
||||
|
||||
var pickEvent = new PickEvent
|
||||
{
|
||||
item = item,
|
||||
unit = parent
|
||||
};
|
||||
|
||||
item.itemEvents.onPickedBefore.Invoke(pickEvent);
|
||||
item.itemEvents.onPickedAfter.Invoke(pickEvent);
|
||||
|
||||
// Make this slot empty so we can rightfully start whole "Take" machine
|
||||
items[itemIndex] = null;
|
||||
|
||||
Take(itemIndex, item);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[ShowInInspector, ReadOnly] private GameObject _backpackGameObject;
|
||||
|
||||
[SerializeField, DisableInPlayMode] private ItemObject[] _items = Array.Empty<ItemObject>();
|
||||
public ItemObject[] items => _items;
|
||||
|
||||
/// <summary>
|
||||
/// Puts given item into given backpack's slot, if slot is occupied then puts it into first empty.
|
||||
/// </summary>
|
||||
public void Take(int itemIndex, ItemObject item)
|
||||
{
|
||||
if (items.Length <= itemIndex)
|
||||
Resize(itemIndex);
|
||||
|
||||
if (items[itemIndex])
|
||||
{
|
||||
Take(item);
|
||||
return;
|
||||
}
|
||||
|
||||
items[itemIndex] = item;
|
||||
|
||||
var backpackPickEvent = new BackpackPickEvent
|
||||
{
|
||||
unit = parent,
|
||||
item = item,
|
||||
slotIndex = itemIndex,
|
||||
};
|
||||
|
||||
parent.unitEvents.onBackpackPick.Invoke(backpackPickEvent);
|
||||
|
||||
var itemGameObject = item.gameObject;
|
||||
itemGameObject.transform.parent = _backpackGameObject.transform;
|
||||
itemGameObject.transform.localPosition = Vector3.zero;
|
||||
itemGameObject.transform.localRotation = new Quaternion();
|
||||
|
||||
item.basicEvents.onRemove.AddListener(OnItemRemove);
|
||||
|
||||
Resize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts given item into first empty slot.
|
||||
/// </summary>
|
||||
public void Take(ItemObject item)
|
||||
{
|
||||
// Find first free slot in backpack
|
||||
var firstFreeIndex = Array.IndexOf(items, null);
|
||||
|
||||
// No free slots, we need to resize array
|
||||
if (firstFreeIndex == -1)
|
||||
{
|
||||
firstFreeIndex = items.Length;
|
||||
Resize();
|
||||
}
|
||||
|
||||
Take(firstFreeIndex, item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops item from given slot, BUT! Unit still carry that.<br/>
|
||||
/// This is purely for moving item between modules in UnitObject or preparing to drop it on scene.
|
||||
/// </summary>
|
||||
public void Drop(int itemIndex)
|
||||
{
|
||||
var tempDroppedItem = items[itemIndex];
|
||||
|
||||
items[itemIndex].basicEvents.onRemove.RemoveListener(OnItemRemove);
|
||||
|
||||
items[itemIndex] = null;
|
||||
|
||||
var backpackDropEvent = new BackpackDropEvent
|
||||
{
|
||||
unit = parent,
|
||||
item = tempDroppedItem,
|
||||
slotIndex = itemIndex,
|
||||
};
|
||||
|
||||
parent.unitEvents.onBackpackDrop.Invoke(backpackDropEvent);
|
||||
|
||||
var tempItemGameObject = tempDroppedItem.gameObject;
|
||||
tempItemGameObject.gameObject.transform.parent = null;
|
||||
tempItemGameObject.gameObject.transform.position = parent.transform.position;
|
||||
|
||||
Resize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds given item's index and then run: <see cref="Drop(int)"/>
|
||||
/// <br/><br/>
|
||||
/// <see cref="Drop(int)"/>:
|
||||
/// <inheritdoc cref="Drop(int)"/>
|
||||
/// </summary>
|
||||
public void Drop(ItemObject item)
|
||||
{
|
||||
Drop(Array.IndexOf(items, item));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swaps content of two slots by given slot indexes.
|
||||
/// </summary>
|
||||
public void Swap(int firstItemIndex, int secondItemIndex)
|
||||
{
|
||||
Resize(Math.Max(firstItemIndex, secondItemIndex));
|
||||
|
||||
(items[firstItemIndex], items[secondItemIndex]) = (items[secondItemIndex], items[firstItemIndex]);
|
||||
|
||||
var backpackSwapEvent = new BackpackSwapEvent
|
||||
{
|
||||
unit = parent,
|
||||
firstSlotIndex = firstItemIndex,
|
||||
firstItem = items[firstItemIndex],
|
||||
secondSlotIndex = secondItemIndex,
|
||||
secondItem = items[secondItemIndex],
|
||||
};
|
||||
|
||||
parent.unitEvents.onBackpackSwap.Invoke(backpackSwapEvent);
|
||||
|
||||
Resize();
|
||||
}
|
||||
|
||||
public void Sort(Func<ItemObject, IComparable> valueGetter, SortDirectionType sortDirection) {
|
||||
ItemObjectSortUtil.Sort(ref _items, valueGetter, sortDirection);
|
||||
|
||||
var backpackSortEvent = new BackpackSortEvent {
|
||||
unit = parent,
|
||||
};
|
||||
|
||||
parent.unitEvents.onBackpackSort.Invoke(backpackSortEvent);
|
||||
|
||||
Resize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executed when ItemObject is removed. Removes item's reference from backpack.
|
||||
/// </summary>
|
||||
private void OnItemRemove(RemoveEvent removeEvent)
|
||||
{
|
||||
var removedItem = removeEvent.obj as ItemObject;
|
||||
Drop(removedItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resizes backpack with rule: last slots row must be empty AND each row have 10 slots
|
||||
/// </summary>
|
||||
public void Resize(int minSize = 0, int rowSize = 10)
|
||||
{
|
||||
var beforeSlotCount = items.Length;
|
||||
var lastItemIndex = Array.FindLastIndex(items, item => item);
|
||||
var afterSlotCount = Mathf.CeilToInt((Mathf.Max(lastItemIndex, minSize) + rowSize) / (float)rowSize) * rowSize;
|
||||
|
||||
// Size not changed, do nothing
|
||||
if (beforeSlotCount == afterSlotCount) return;
|
||||
|
||||
// Resize backpack's arrays
|
||||
var tempItems = items;
|
||||
Array.Resize(ref tempItems, afterSlotCount);
|
||||
_items = tempItems;
|
||||
|
||||
var backpackResizeEvent = new BackpackResizeEvent
|
||||
{
|
||||
unit = parent,
|
||||
beforeSlotCount = beforeSlotCount,
|
||||
afterSlotCount = afterSlotCount,
|
||||
lastItemIndex = lastItemIndex,
|
||||
};
|
||||
|
||||
parent.unitEvents.onBackpackResize.Invoke(backpackResizeEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user