作者:quincyhuanghk
 
茶水君干货系列,小白必学,大神必喷。
首发泰斗,http://www.taidous.com,欢迎转发,请注明出处哦,违者,我也有没办法。
交易系统的UI设计,和数据交互,代码大幅更新过,所以茶水君会分几个小章节来分析更新过的代码和交易系统的UI设计。

本章内容较多,且更新幅度巨大,所以,我们现在看看先结果好了,这样大家有个直接点的感觉。

那么下载好附件之后,打开测试,如图1,

 
大家会看到3个主要界面,商店,装备栏,背包,和一个次要界面,最下面的那个描述面板。

这几个界面的交互操作请看彩色剪头。

红色:从背包出售道具到商店
蓝色:从商店购买道具到背包。
绿色:装备与卸载。
另外,在背包中,双击消耗品则会直接使用,这里黄金鸭是一个消耗品。

这里,我们将那个水晶球作为通货,在交易过程中,大家看见通货的数量会发生变化,而且,这个商店是不回收武器(这里树枝是武器),所以丢武器过去的时候,商店是没有反应了,这样我们可以自定义NPC的回收项目了。

细心的你们还会发现,背包中的道具时可以分栏的,不一定是强制叠堆的,这里的API都已经提供完全了,大家可以根据项目的实际需求来使用和修改,如图2,

 

最后,当鼠标滑过UISlot的时候,描述面板会显示相应的信息,怎么样,还不错吧。

这个Demo基本上实现了道具系统的交互操作了。(每次只能操作单组道具,日后如有需要,会添加更多操作。这里有个小小的非致命bug,当背包满格后,就不能替换装备,因为在程序上来说,是先卸载后装备的,所以程序会认为没有空位,所以卸载失败,就不能装备了,这个bug大家有兴趣可以尝试修复下,这里茶水留在以后再修复吧,因为考虑到如果装备也可以叠堆的话,则这个逻辑是没有错的,所以视实际情况吧。)

 
**************我是儿童不宜分割线****************

那么,为了适应这种道具分栏的操作,我们需要更新一下我们的UISlot的设计,使其能对某些操作做出适当的反应。

直接为UISlot添加一个Box Collider,然后size等于这个UISlot的长宽,厚度Z为1,(只要比UIStorage的厚度厚就好了,主要是避免被UIStorage遮挡了,这样射线检测会有问题),Trigger,如图3,

 

 

然后,为了更好的效果,我们可以重调整一下他的层级结构,如图4,(非必要,可无视)

 

 

主要将BG Frame提出来了,放到UISlot首席了。

然后,更新UISlot代码部分,其中比较重要的是,修改和添加了新的代理函数,代码:

[C#] 纯文本查看 复制代码

public delegate void OnFunction(int id);
public OnFunction onClick, onEnter, onExit;
和鼠标的事件函数,代码:

[C#] 纯文本查看 复制代码

        #region IPointerClickHandler implementation
        public void OnPointerClick (PointerEventData eventData)
        {
                if (clickable && eventData.clickCount == 2)
                {
                        if (onClick!=null)
                        {
                                onClick(slot_id);
                        }
                }
                        
        }
        #endregion

        #region IPointerEnterHandler implementation
        
        public void OnPointerEnter (PointerEventData eventData)
        {
                if (onEnter!=null)
                {
                        onEnter(slot_id);
                }
        
        }
        
        #endregion
        
        #region IPointerExitHandler implementation
        
        public void OnPointerExit (PointerEventData eventData)
        {
                if (onExit!=null)
                {
                        onExit(slot_id);
                }
        }
        
        #endregion
这样,我们就可以处理鼠标双击,和滑进滑出的事件了。

最后,当然要更新一下他的初始化函数,这样,UIStroage在初始化UISlot的时候,就可以赋值代理函数了,代码:

[C#] 纯文本查看 复制代码

        // this is called by storage
        public void Init(UIStorageBase sb, int id, OnFunction clickFunc, OnFunction enterFunc, OnFunction exitFunc)
        {
                slot_id = id;
                storage = sb;
                AddOnClick(clickFunc);
                AddOnEnter(enterFunc);
                AddOnExit(exitFunc);
                // more here
        }

 

**************我是儿童不宜分割线****************

然后,就是更新UIStorageBase的代码了,首先,我们添加一些参数,代码:

        public BackpackSystem backpackSys = null;
        public string moneyID = "Money";
        public UIDescrption descrption;
 
按顺序,每个面板对应一个指定的背包数据,交易用的通货(主要用于商店),还有一个描述面板。

通货何以有好多,类似WOW中的各种牌子,所以自定义通货可以灵活设计NPC的交易货币,增加游戏乐趣吧。

然后,添加几个虚函数,用来给UISlot代理的几个事件,代码:

[C#] 纯文本查看 复制代码

// this is called by slot, need to assign to slot first
        virtual public void Slot_OnClick(int id)
        {
                Debug.Log("Slot " + id + " on click!");
        }

        // this is called by slot, need to assign to slot first
        virtual public void Slot_OnEnter(int id)
        {
                if (descrption)
                {
                        ItemBase item = ItemDatabase.GetItem(slots[id].item_id);
                        if (item != null)
                        {
                                string info = "["+item.displayName +"]\n\n"+ item.comment;
                                descrption.Set(slots[id],info);
                        }
                        
                }
        }

        // this is called by slot, need to assign to slot first
        virtual public void Slot_OnExit(int id)
        {
                if (descrption)
                {
                        descrption.Set(null,"");
                }
        }

和一个同步需函数,用于将背包的数据和UISlot关联起来,代码:

[C#] 纯文本查看 复制代码

        virtual public void Sync()
        {
                for(int i=0;i<slots.Count;i++)
                {
                        slots[i].SetIconEmpty();
                }
        }
还有一个用于获取被交互的UISlot,这个功能主要用在分栏和装备栏中,因为装备栏有类型限制,例如武器只能放在武器的栏目里,所以我们需要知道用户将道具拖到那个UISlot上了,代码:

[C#] 纯文本查看 复制代码

        // get the ui slot which will be hit by the ray after the draging action.
        virtual public UISlot Get_UISlot_On_End_Drag()
        {
                // set current camera
                if (Camera.current == null)
                        Camera.SetupCurrent(Camera.main);
                
                RaycastHit hitinfo;
                Ray ray = Camera.current.ScreenPointToRay(Input.mousePosition);
                if (Physics.Raycast(ray, out hitinfo))
                {
                        UISlot us = hitinfo.collider.gameObject.GetComponent<UISlot>();
                        return us;
                }

                return null;
        }
以上虚函数,将会根据实际情况,在子类中重写。

 

**************我是儿童不宜分割线****************

最后还有点时间,那么我们快速将UIDescrption过一遍吧,如图5,

 

其实看着也简单,一些前景背景,一个UISlot没有Text Info Group的,一个文本框,用于显示文字的,直接看结构吧,如图6,

 

 

很好, 然后为它添加上UIDescrption的脚本,配置好,如图7,

 

 
由于我们并不需要和描述中的UISlot交互,所已,将他的UISlot的3个参数,Dragable, Clickable, Infoable 全部反选即可,如图8,

 

 
这样,就完成了。

至于UIDescrption的代码,没有什么特别,目前就一个函数,用于设置显示的Icon和文字而已,代码:

[C#] 纯文本查看 复制代码

        public void Set(UISlot _slot, string _info)
        {
                if (_slot == null)
                {
                        slot.SetIconEmpty();
                        slot.gameObject.SetActive(false);
                }
                else
                {
                        slot.gameObject.SetActive(true);
                        slot.SetIcon(_slot.icon.texture);
                        slot.SetAtt1(_slot.att1.texture);
                        slot.SetColor(_slot.fg.color);
                        info.color = _slot.fg.color;
                }

                info.text = _info;
        }

 

**************我是儿童不宜分割线****************

 

好了,那么我们今天更新了UISlot和UIStorage,新设计了UIDescrption这3个基本的组件和代码,下次我们继续其他的吧。
PS:茶水君发现UIDescrption打错了,但是让他错下去吧,茶水君读得书少,哎。。。

PS:为了保持数据系统的通用性,所以UI面板中的交互操作成为了很重要的一个道具类型限制的手段,例如商店,背包和装备栏是使用一样的数据系统,所以我们需要在其对应的UI面板中,限制其操作方式,例如装备中,武器和护甲需要分别装备在指定的UISlot中,而且不能叠堆(如果该道具原本支持叠堆的话),同类装备可以替换,替换出来的道具会自动放到背包中,等等,这些操作都会在UI面板(UIStorage)中实现,从而保证我们的数据系统一致性,和便于维护。下次我们就来更新我们的背包数据系统吧。

本项目基于 Unity 5.1.2,

新建一个空项目,然后覆盖 Assets ,和 ProjectSettings 就好了。

下载地址,原文:http://www.taidous.com/forum.php?mod=viewthread&tid=32190​