本篇想总结的是Inventory Pro中通用窗口的具体实现,但还是要强调下该插件的重点还是装备系统而不是通用窗口系统,所以这里提到的通用窗口类其实是通用装备窗口类(其实该插件中也有非装备窗口比如NoticeUI等)。

本篇涉及的功能用加出标出,具体的功能如下:

1、实现了两个窗口,通过点击键盘I来,打开或者关闭窗口也就是Toggle功能

2、装备窗口中的物品栏空格数量动态生成可控,可以在属性窗口手动配置

3、窗口具有拖拽功能

4、窗口物品具有拖拽,及窗口间拖拽

5、可以在窗口使用物品的功能,物品有消耗扇形显示功能

6、通用窗口的类体系结构

这里开动之前给自己提几个问题:

1、UGui原生实现使用物品扇形消耗效果(即冷却实现)是如何实现的?

这个比较简单,UGUI图片本身就有这种雷达效果的遮罩,这篇文章讲的很详细,这里就不用说了

[入门教程] 用UGUI实现技能冷却效果

2、装备格子是如何与1所提到的方法接合在一起的?

这里回忆下装备格子是用InventoryUItemWrapper这个UI类实现的,所以答案就在这个类里,但使用这个类并非易事,它是用ItemCollectionBase类(集合容器)动态生成的,在前篇讲过这里再温习一下,这里我们发现如果没有值得话,它取的InventorySettingsManager.itemButtonPrefab,也就是个装备格子预设

        protected virtual void FillUI()
{
if (manuallyDefineCollection == false)
{
items = new InventoryUIItemWrapperBase[initialCollectionSize]; // Fill the container on startup, can add / remove later on
for (uint i = ; i < initialCollectionSize; i++)
{
items[i] = CreateUIItem<InventoryUIItemWrapper>(i, itemButtonPrefab != null ? itemButtonPrefab : InventorySettingsManager.instance.itemButtonPrefab);
}
}
else
{
for (uint i = ; 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;
}

回忆一下这个配置是一个必填配置,必须在Setting中进行设置,

找到该预设,找到真相

看的出来这个预设绑定了InventoryUIItemWrapper类,其公共的Field也以此列了出来分别是Amout Text物品数量,Item Name物品名称(None),Icon(Image)这就是物品的图标了比如苹果,Cooldown Image 就是图片表面的遮罩层,用来做雷达效果的。

3、装备格子是如何与苹果等可以吃的动态物品接合在一起的?

从上面的图片我们也看的出来,其实默认的Icon应该是装备格子的背景(黑底),它是如何变成苹果梨,或者刀剑的呢?这里比较简单的线索就是通过拾取地上的包裹,然后在背包里多了一个物品(这个过程不表述了比较复杂,留在以后专门分析),顺藤摸瓜,最终还是要加入到背包里面,这样我们去看看ItemCollectionBase类中的AddItem方法,这里这个方法本身很复杂主要是有类似20个血瓶1打东西放置的时候需要重新计算格子什么的比较麻烦,核心的函数是SetItem

        /// <summary>
/// This function can be overridden to add custom behavior whenever an object is placed in the inventory.
/// This happens when 2 items are swapped, items are merged, anytime an object is put in a slot.
/// <b>Does not handle repainting</b>
/// </summary>
/// <param name="slot"></param>
/// <param name="item"></param>
/// <returns>Returns true if the item was set, false if not.</returns>
public virtual bool SetItem(uint slot, InventoryItemBase item)
{
if (CanSetItem(slot, item) == false)
return false; // _item ugly work around, but no other way to keep it safe...
items[slot].item = item;
return true;
}

这里我们还记得InventoryUIItemWrapper是Item的包装,所以这里设置了其的Item为新增的Item,顺着这个思路剩下相关的就是绘制部分了,再去看看InventoryUIItemWrapper的绘制部分看看是如何显示的以及冷却效果是如何实现的

        public override void Repaint()
{
if (item != null)
{
if (amountText != null)
{
// Only show when we have more then 1 item.
if (item.currentStackSize > )
amountText.text = item.currentStackSize.ToString();
else
amountText.text = string.Empty;
} if (itemName != null)
itemName.text = item.name; if(icon != null)
icon.sprite = item.icon;
}
else
{
if (amountText != null)
amountText.text = string.Empty; if (itemName != null)
itemName.text = string.Empty; if(icon != null)
icon.sprite = startIcon != null ? startIcon : InventorySettingsManager.instance.defaultSlotIcon;
} //RepaintCooldown(); // Already called by update loop
}
icon.sprite = item.icon; 这一行代码我们看到了,其实icon这个Image Field 对应Item.icon,而且是一个sprite对象(原来sprite是Image的一个部分),再看下Update Loop的代码,只是在每一帧调用了
RepaintCooldown(),也就是执行冷却刷新,具体代码如下:
        public virtual void RepaintCooldown()
{
if (cooldownImage == null)
return; if (item != null)
{
if(item.isInCooldown)
{
cooldownImage.fillAmount = 1.0f - item.cooldownFactor;
return;
}
} // To avoid GC
if (cooldownImage.fillAmount != 0.0f)
cooldownImage.fillAmount = 0.0f;
}

当然这里有控制cooldown的逻辑,isInCooldown是一个属性逻辑都在里面,包括同类型物品使用的冷却控制(有点复杂,这里先不表了)

4、物品是如何被触发使用的?

触发使用一定是在点击的时候触发的,接合UGui的事件机制,Inventory Pro 分别在OnPointerDown和OnPointerUP中进行了实现,有一些触控相关的判断见一下源码

        public virtual void OnPointerDown(PointerEventData eventData)
{
if (itemCollection == null)
return; pointerDownOnUIElement = InventoryUIUtility.clickedUIElement;
if (pointerDownOnUIElement == false)
return; if (InventorySettingsManager.instance.useContextMenu && (eventData.button == InventorySettingsManager.instance.triggerContextMenuButton || Application.isMobilePlatform))
{
if (item != null)
TriggerContextMenu(); return;
} if (InventorySettingsManager.instance.mobileUnstackItemKey == MobileUIActions.SingleTap)
{
TriggerUnstack();
return;
}
else if(InventorySettingsManager.instance.mobileUseItemButton == MobileUIActions.SingleTap)
{
TriggerUse();
return;
} if (item != null && pressing == false && Time.timeSinceLevelLoad - InventorySettingsManager.instance.mobileDoubleTapTime < lastDownTime)
{
// Did double tap
if (InventorySettingsManager.instance.mobileUnstackItemKey == MobileUIActions.DoubleTap)
{
TriggerUnstack();
return;
}
else if(InventorySettingsManager.instance.mobileUseItemButton == MobileUIActions.DoubleTap)
{
TriggerUse();
return;
}
} lastDownTime = Time.timeSinceLevelLoad;
pressing = true;
}

物品的具体使用在TriggerUse() 实现

        public override void TriggerUse()
{
if (item == null)
return; if (itemCollection.canUseFromCollection == false)
return; int used = item.Use();
if (used >= )
{
Repaint();
}
}

这里最终物品的使用时调用的Item Model中的Use()来实现的,这个应该是一种基类方法,需要特定的子类Item来实现,具体实现还要和容器有一定关系,比较复杂本文不表,有机会日后再展开,反正使用后调用了Repaint()方法也就是在使用完毕物品后装备格子进行了重绘刷新操作。

总结

把这四个问题回答完毕,基本本篇的主题也就清楚了,走人

												

最新文章

  1. CGContextRef 画线简单用法
  2. &lt;%%&gt;标签 什么意思
  3. 翻译qmake文档(一) qmake指南和概述
  4. 获取图片base64编码的几种方法
  5. HDU 1576 (乘法逆元)
  6. 转 Eric Raymond对于几大开发语言的评价
  7. 8 Regular Expressions You Should Know
  8. WPF 多线程处理(3)
  9. shared_ptr的简单实现
  10. Ubuntu 14.04 &amp; ant: Unable to locate tools.jar. Expected to find it in /usr/lib/jvm/java-7-openjdk-i386/lib/tools.jar
  11. Learning JavaScript Design Patterns The Observer Pattern
  12. careercup-数学与概率 7.6
  13. 【python自动化第四篇:python入门进阶】
  14. jquery 核心
  15. 一段JAVA签名算法的PHP改写
  16. abstract class 和 interface区别
  17. ●BZOJ 1855 [Scoi2010]股票交易
  18. 理解性能的奥秘——应用程序中慢,SSMS中快(4)——收集解决参数嗅探问题的信息
  19. 机器学习入门18 - 生产机器学习系统(Production ML Systems)
  20. XBee PRO 900HP远距离无线模块

热门文章

  1. 如何开发ecshop支付插件
  2. 使用photoshop,把图片背景变成透明
  3. laravel 数据填充
  4. nginx 配置多个二级域名
  5. Linguistic corpora 种子语料库-待分析对象-分析与更新语料库
  6. ajax+jsp自动刷新
  7. [教程] 以本论坛为例,手把手教你使用按键精灵POST登陆网页
  8. 【转】Laravel+Angularjs+D3打造可视化数据,RESTful+Ajax
  9. 添加Ubuntu的库文件路径
  10. 转 创建 JavaScript XML 文档注释