当前位置:网站首页>Game backpack system, "inventory Pro plug-in", research and learning ----- mom doesn't have to worry that I won't make a backpack anymore (unity3d)
Game backpack system, "inventory Pro plug-in", research and learning ----- mom doesn't have to worry that I won't make a backpack anymore (unity3d)
2022-07-25 11:27:00 【InfoQ】
- CSDN Home page
- GitHub Open source address
- Unity3D Plug in sharing
- Jane book address
- My personal blog
- QQ Group :1040082875
One 、 Preface
Two 、 Reference article
3、 ... and 、 Text

1、 The overall structure

- Not UI relevant InventoryItem Goods system , For example, equipment , consumables , Store items, etc
- UI relevant InventoryUIItemWrapper Goods system
- UIItem Of UI Packaged Item Inheritance system
- ItemCollection Such a class , Because simple increase 、 Deletion and modification are inevitable , Complex as exchange , Exchange between containers and other operations
- UIWindow Window class of the system , Specific roles , Bank , Skill , Shops and other windows
- InventoryUIDialog Dialog class under the system , There is a confirmation box , business , General tips
- Special window ( Non inheritance system window ), Menu above and below , Notification window, etc
- Configuration Management
- InvertoryManager
- ItemManger
- Database operation


2、 Use the tutorial

- choice 1( Automatically ) Open the setup wizard , It can be found in Tools/Inventory Pro/Setup wizard For mistakes “ There are no objects found by managers ”; Click the OK button and a management object named "_managers" Will be automatically added to your scene .
- choice 2( Manual ) Creating an empty GameObject will inventorymanager form , You can find it in stock / The manager / inventorymanager You will get several manager components including inventorymanager,inventorysettingsmanager And more , We don't need now .
3、Demo analysis






4、 example
- 1、 Two windows are implemented , By clicking on the keyboard I Come on , Open or close the window, that is Toggle function
- 2、 The number of spaces in the item column in the equipment window is dynamically generated and controllable , You can configure it manually in the properties window
- 3、 The window has drag and drop function
- 4、 Window items have drag , And drag between windows
- 5、 You can use the function of the object in the window , Items have consumption sector display function

5、 summary

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
namespace Devdog.InventorySystem
{
[AddComponentMenu("InventorySystem/UI Helpers/DraggableWindow")]
public partial class DraggableWindow : MonoBehaviour, IBeginDragHandler, IDragHandler
{
public float dragSpeed = 1.0f;
private Vector2 dragOffset;
public void OnBeginDrag(PointerEventData eventData)
{
if (InventorySettingsManager.instance.isUIWorldSpace)
dragOffset = transform.position - eventData.worldPosition;
else
dragOffset = new Vector2(transform.position.x, transform.position.y) - eventData.position;
}
void IDragHandler.OnDrag(PointerEventData eventData)
{
transform.position = new Vector3(eventData.position.x + dragOffset.x * dragSpeed, eventData.position.y + dragOffset.y * dragSpeed, 0.0f);
}
}
}

public virtual void Hide()
{
if (isVisible == false)
return;
isVisible = false;
if (OnHide != null)
OnHide();
if (hideAudioClip != null)
InventoryUIUtility.AudioPlayOneShot(hideAudioClip);
if (hideAnimation != null)
{
animator.enabled = true;
animator.Play(hideAnimation.name);
if (hideCoroutine != null)
{
StopCoroutine(hideCoroutine);
}
hideCoroutine = _Hide(hideAnimation);
StartCoroutine(hideCoroutine);
}
else
{
animator.enabled = false;
SetChildrenActive(false);
}
}
/// <summary>
/// Hides object after animation is completed.
/// </summary>
/// <param name="animation"></param>
/// <returns></returns>
protected virtual IEnumerator _Hide(AnimationClip animation)
{
yield return new WaitForSeconds(animation.length + 0.1f);
// Maybe it got visible in the time we played the animation?
if (isVisible == false)
{
SetChildrenActive(false);
animator.enabled = false;
}
}
/// <summary>
/// Container that olds the items, if any.
/// </summary>
public RectTransform itemContainer;
public UIWindow windowParent { get; set; }
public override void Awake()
{
base.Awake();
windowParent = transform.parent.GetComponentInParent<UIWindow>();
if (windowParent == null)
Debug.LogWarning("No UIWindow found in parents", gameObject);
// Register our page with the window parent
windowParent.AddPage(this);
}
public override void Show()
{
if(isEnabled == false)
{
Debug.LogWarning("Trying to show a disabled UIWindowPage");
return;
}
base.Show();
windowParent.NotifyPageShown(this);
}
/// <summary>
/// Keys to toggle this window
/// </summary>
public KeyCode[] keyCombination;
public virtual void Update()
{
if (keyCombination.Length == 0)
return;
bool allDown = true;
foreach (var key in keyCombination)
{
if (Input.GetKeyDown(key) == false)
{
allDown = false;
}
}
if (allDown)
Toggle();
}
- 1、 Two windows are implemented , By clicking on the keyboard I Come on , Open or close the window, that is Toggle function
- 2、 The number of spaces in the item column in the equipment window is dynamically generated and controllable , You can configure it manually in the properties window
- 3、 The window has drag and drop function
- 4、 Window items have drag , And drag between windows
- 5、 You can use the function of the object in the window , Items have consumption sector display function
- 6、 Class architecture of general window


protected virtual void FillUI()
{
if (manuallyDefineCollection == false)
{
items = new InventoryUIItemWrapperBase[initialCollectionSize];
// Fill the container on startup, can add / remove later on
for (uint i = 0; i < initialCollectionSize; i++)
{
items[i] = CreateUIItem<InventoryUIItemWrapper>(i, itemButtonPrefab != null ? itemButtonPrefab : InventorySettingsManager.instance.itemButtonPrefab);
}
}
else
{
for (uint i = 0; i < items.Length; i++)
{
items[i].itemCollection = this;
items[i].index = i;
}
}
}
protected T CreateUIItem<T>(uint i, GameObject prefab) where T : InventoryUIItemWrapperBase
{
T item = GameObject.Instantiate<GameObject>(prefab).GetComponent<T>();
item.transform.SetParent(container);
item.transform.localPosition = new Vector3(item.transform.localPosition.x, item.transform.localPosition.y, 0.0f);
item.itemCollection = this;
item.transform.localScale = Vector3.one;
item.index = i;
return item;
}
- 1、 The initiator of drag and drop events should be of that kind ?
- 2、 Drag and drop events Drag How to determine the following UI Elemental ?
- 3、 Logical operation after dragging , Which class should undertake ?
- 4、 Drag and drop between windows , both Drag And then there is Drop, How to solve this problem more reasonably ?
- 5、 What is the logical process of dragging objects between windows and objects in the same window ?


- 1) Click the left mouse button on the item ( Record the elements clicked by the mouse )->
- 2) In mouse not up, And move The drag start is confirmed in the event (Drag event ) –>
- 3) mouse Move Get the element under the mouse in the event ->
- 4)mouse up Events trigger Drop, Determine whether the mouse position and elements under the mouse can drop If it can be done Drop This is the logic , This drag operation ends
- OnPointerEnter: OK, click that UI Elements , Corresponding 1)
- OnBeginDrag: Start dragging , Corresponding 2)
- OnDrag: Dragging , Corresponding 3)
- OnEndDrag: End drag , Corresponding 4)
- OnPointExit: Empty the selected element , Restore defaults
public virtual void OnBeginDrag(PointerEventData eventData)
{
if (itemCollection == null)
return;
if (item != null && eventData.button == PointerEventData.InputButton.Left && itemCollection.canDragInCollection)
{
// Create a copy
var copy = GameObject.Instantiate<InventoryUIItemWrapper>(this);
copy.index = index;
copy.itemCollection = itemCollection;
var copyComp = copy.GetComponent<RectTransform>();
copyComp.SetParent(InventorySettingsManager.instance.guiRoot);
copyComp.transform.localPosition = new Vector3(copyComp.transform.localPosition.x, copyComp.transform.localPosition.y, 0.0f);
copyComp.sizeDelta = GetComponent<RectTransform>().sizeDelta;
InventoryUIUtility.BeginDrag(copy, (uint)copy.index, itemCollection, eventData); // Make sure they're the same size, copy doesn't handle this.
}
}
public virtual void OnDrag(PointerEventData eventData)
{
if (item != null && itemCollection != null && itemCollection.canDragInCollection) // Can only drag existing item
InventoryUIUtility.Drag(this, index, itemCollection, eventData);
}
public virtual void OnEndDrag(PointerEventData eventData)
{
if (item != null && itemCollection != null && itemCollection.canDragInCollection)
{
var lookup = InventoryUIUtility.EndDrag(this, index, itemCollection, eventData);
// Didn't end on a button or used wrong key.
if (lookup == null)
return;
if (lookup.endOnButton)
{
// Place on a slot
lookup.startItemCollection.SwapOrMerge((uint)lookup.startIndex, lookup.endItemCollection, (uint)lookup.endIndex);
}
else if (lookup.startItemCollection.useReferences)
{
lookup.startItemCollection.SetItem((uint)lookup.startIndex, null);
lookup.startItemCollection[lookup.startIndex].Repaint();
}
else if(InventoryUIUtility.clickedUIElement == false)
{
TriggerDrop();
}
}
}
public static InventoryUIDragLookup BeginDrag(InventoryUIItemWrapper toDrag, uint startIndex, ItemCollectionBase collection, PointerEventData eventData)
{
if (draggingItem != null)
{
Debug.LogWarning("Item still attached to cursor, can only drag one item at a time", draggingItem.gameObject);
return null; // Can only drag one item at a time
}
if (eventData.button != PointerEventData.InputButton.Left)
return null;
draggingItem = toDrag;
//draggingButtonCollection = collection;
// Canvas group allows object to ignore raycasts.
CanvasGroup group = draggingItem.gameObject.GetComponent<CanvasGroup>();
if(group == null)
group = draggingItem.gameObject.AddComponent<CanvasGroup>();
group.blocksRaycasts = false; // Allows rays to go through so we can hover over the empty slots.
group.interactable = false;
var lookup = new InventoryUIDragLookup();
lookup.startIndex = (int)startIndex;
lookup.startItemCollection = collection;
return lookup;
}
public static void Drag(InventoryUIItemWrapper toDrag, uint startSlot, ItemCollectionBase handler, PointerEventData eventData)
{
if(eventData.button == PointerEventData.InputButton.Left)
draggingItem.transform.position = new Vector3(eventData.position.x, eventData.position.y, 0.0f);
}
public static InventoryUIDragLookup EndDrag(InventoryUIItemWrapper toDrag, uint startSlot, ItemCollectionBase handler, PointerEventData eventData)
{
if(eventData.button == PointerEventData.InputButton.Left)
{
var lookup = new InventoryUIDragLookup();
lookup.startIndex = (int)draggingItem.index;
lookup.startItemCollection = draggingItem.itemCollection;
if (hoveringItem != null)
{
lookup.endIndex = (int)hoveringItem.index;
lookup.endItemCollection = hoveringItem.itemCollection;
}
Object.Destroy(draggingItem.gameObject); // No longer need it
draggingItem = null;
//draggingButtonCollection = null;
return lookup;
}
return null;
}
/// <summary>
/// When the cursor enters an item
/// </summary>
public static void EnterItem(InventoryUIItemWrapper item, uint slot, ItemCollectionBase handler, PointerEventData eventData)
{
hoveringItem = item;
//hoveringItemCollection = handler;
}
/// <summary>
/// When the cursor exits an item
/// </summary>
/// <param name="item"></param>
/// <param name="slot">The slot is the IButtonHandler index not the inventory index.</param>
/// <param name="handler"></param>
/// <param name="eventData"></param>
public static void ExitItem(InventoryUIItemWrapper item, uint slot, ItemCollectionBase handler, PointerEventData eventData)
{
hoveringItem = null;
//hoveringItemCollection = null;
}
public static InventoryUIItemWrapper hoveringItem { get; private set; }
if (lookup.endOnButton)
{
// Place on a slot
lookup.startItemCollection.SwapOrMerge((uint)lookup.startIndex, lookup.endItemCollection, (uint)lookup.endIndex);
}
public override void TriggerDrop(bool useRaycast = true)
{
if (item == null || itemCollection.canDropFromCollection == false)
return;
if(item.isDroppable == false)
{
InventoryManager.instance.lang.itemCannotBeDropped.Show(item.name, item.description);
return;
}
Vector3 dropPosition = InventorySettingsManager.instance.playerObject.transform.position;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, InventorySettingsManager.instance.maxDropDistance,
InventorySettingsManager.instance.layersWhenDropping))
{
dropPosition = hit.point;
}
else
{
return; // Couldn't drop item
}
var s = InventorySettingsManager.instance;
if (useRaycast && s.showConfirmationDialogWhenDroppingItem && s.showConfirmationDialogMinRarity.ID <= item.rarity.ID)
{
// Not on a button, drop it
var tempItem = item; // Capture list stuff
var msg = InventoryManager.instance.lang.confirmationDialogDrop;
s.confirmationDialog.ShowDialog(msg.title, msg.message, s.defaultDialogPositiveButtonText, s.defaultDialogNegativeButtonText, item,
(dialog) =>
{
ItemCollectionBase startCollection = tempItem.itemCollection;
uint startIndex = tempItem.index;
var d = tempItem.Drop(dropPosition);
if (d != null)
{
startCollection[startIndex].Repaint();
}
},
(dialog) =>
{
//Debug.Log("No clicked");
});
}
else
{
var d = item.Drop(dropPosition);
if (d != null)
{
Repaint();
}
}
}
public class InventoryUIDragLookup
{
public int startIndex = -1;
public ItemCollectionBase startItemCollection;
public int endIndex = -1;
public ItemCollectionBase endItemCollection;
public bool endOnButton
{
get
{
return endItemCollection != null;
}
}
}
#region Variables
private static InventoryUIItemWrapper draggingItem;
public static InventoryUIItemWrapper hoveringItem { get; private set; }
public static bool isDraggingItem
{
get
{
return draggingItem != null;
}
}
public static bool clickedUIElement
{
get
{
return EventSystem.current.IsPointerOverGameObject();
}
}
public static bool isFocusedOnInput
{
get
{
if (EventSystem.current.currentSelectedGameObject != null)
if (EventSystem.current.currentSelectedGameObject.GetComponent<UnityEngine.UI.InputField>() != null)
return true;
return false;
}
}
#endregion
边栏推荐
- SQL语言(三)
- Ue4.26 source code version black screen problem of client operation when learning Wan independent server
- Database design - Simplified dictionary table [easy to understand]
- Nowcodertop12-16 - continuous updating
- shell-第四天作业
- MySQL advanced statement (I) (there is always someone who will make your life no longer bad)
- Learn NLP with Transformer (Chapter 7)
- 常见的几种PCB表面处理技术!
- 新能源销冠宏光MINIEV,有着怎样的产品力?
- Reinforcement learning (III)
猜你喜欢

MySQL master-slave replication and read-write separation

Implementation of recommendation system collaborative filtering in spark

玩游戏想记录一下自己超神的瞬间?那么就来看一下如何使用Unity截图吧
Details of the list of state products that Apple announced to be eligible for the sales tax holiday in the United States

Ue4.26 source code version black screen problem of client operation when learning Wan independent server

让运动自然发生,FITURE打造全新生活方式

Want to record your supernatural moments when playing games? Let's take a look at how to use unity screenshots

【IJCAI 2022】参数高效的大模型稀疏训练方法,大幅减少稀疏训练所需资源

SQL注入 Less17(报错注入+子查询)

PostgreSQL踩坑 | ERROR: operator does not exist: uuid = character varying
随机推荐
Motivation of enterprises to practice open source
Shell Chapter 7 exercise
SQL注入 Less18(头部注入+报错注入)
[flask advanced] combined with the source code, explain the operation mechanism of flask (in and out of the stack)
Database design - Simplified dictionary table [easy to understand]
Review recitation finishing version
Ue4.26 source code version black screen problem of client operation when learning Wan independent server
Definition of information entropy
JS convert pseudo array to array
Dataframe print ellipsis problem
从宏观到微观 零基础 详解bert
Learn NLP with Transformer (Chapter 7)
最详细的mysql索引解析(文末附赠思维导图)
Some errors of tensorflow calling multiple GPUs
SQL语言(二)
Reinforcement Learning 强化学习(三)
信息熵的定义
[domain generalization] 2022 IJCAI domain generalization tutorial Report
PostgreSQL stepping on the pit | error: operator does not exist: UUID = character varying
Nowcodertop1-6 - continuous updating