Unity3D的简单商店、背包与装备系统(UGUI)

Store And Equipment System In Unity3D

Introduction

物品元素可以说是所有RPG的必备系统,毕竟,如果没有物品系统就没有消耗,没有消耗哪能骗玩家充钱呢?最简单的物品系统应该是所谓的商店、背包加装备的结构,而这个Demo则主要基于UGUI实现一个简单的上述系统

UI

制作系统的第一步便是UI的绘制了。无论美术资源来自何方,画风如何,应该基本包括如下几个层面:

  • 角色信息界面,用于显示主角的装备槽位以及正在穿戴中的装备
  • 背包界面,用于显示主角拥有的物品集合
  • 金钱标签,用于显示主角当前拥有的钱币
  • 商店界面,用于显示当前售卖的物品集合
  • (可选)快速物品栏,通常与技能栏合用,让玩家能够快速使用物品

在我的Demo中也基本实现了上述模块

Bag System

一个背包系统的组成很简单,即面板+很多的格子,再贴一个金钱的文本框和几个图标就能够完成,我的背包也是基于上述想法来实现的:

  • 通过Unity3D的Scroll View作为背包系统的主面板
  • 创建Grid对象,并设置其Image为相应的Spirit作为物品图标
  • 实现物品拖动逻辑,主要是在C#脚本实现动画表现,Lua更新数据,即注册onDrag事件,当鼠标拖动一个Grid时,创建一个当前Grid的副本,并在onDraging中不断获取当前鼠标所在的屏幕坐标赋值给副本的Transform,最后进行鼠标弹起位置的判断是否放在有效的区域,若位置合法则移动物品,并将数据写入Lua类,同步到服务器
// copy current grid
public static InventoryUIItemWrapperBase CreateDragObject(InventoryUIItemWrapperBase from)
{
    var copy = GameObject.Instantiate<InventoryUIItemWrapperBase>(from);
    copy.index = from.index;
    copy.itemCollection = from.itemCollection;
    copy.item = from.item;

    var copyComp = copy.GetComponent<RectTransform>();
    copyComp.SetParent(InventorySettingsManager.instance.guiRoot.transform);
    copyComp.transform.localPosition = new Vector3(copyComp.transform.localPosition.x, copyComp.transform.localPosition.y, 0.0f);
    copyComp.sizeDelta = from.GetComponent<RectTransform>().sizeDelta;

    group.blocksRaycasts = false;
    group.interactable = false;

    return copy;
}

//draging event
public static void OnDrag(PointerEventData eventData)
{
    if (currentDragHandler != null)
    {
        currentDragHandler.OnDrag(eventData);

        if (OnDragging != null) OnDragging(currentDragHandler.dragLookup, currentDragHandler.currentlyDragging, eventData);
    }
}


//finish drag
public static InventoryUIDragLookup OnEndDrag(PointerEventData eventData)
{
    if (currentDragHandler == null) 
    {
        return null;
    }
    var lookup = currentDragHandler.OnEndDrag(InventoryUIUtility.currentlyHoveringWrapper, eventData);
    if (OnEndDragging != null)
    {
        OnEndDragging(lookup, currentDragHandler.currentlyDragging, eventData);
        AppFacade.instance.CallLua("pg.global.bag.moveItem", curItemId, eventData.getTargetGrid()); 
    }

    return lookup;
}
  • 在初步实现中发现缺少了一个考虑的点,即拖拽到相同的物品应该合并,因此应当加入判断
  • 此外,能合并物品理应能拆分,于是加入左Shift键的监听事件,物品的拆分逻辑可重用拖动逻辑,即直接调用DragItem(curItemId, targetGrid)将物品移入下一格,并创建一个相应的克隆对象,改变其下标的数量。当然,当背包满时直接Return即可
  • 在Lua中应当调用服务器方法将数据写入数据库以保证数据的持久化
function onEndMoveItem(curItemId, grid)
    self.server.MoveItem(curItemId, grid)
end
  • 最后实现右键使用物品的逻辑,分消耗品和装备来进行不同的逻辑处理

Advandace Bag System

在上述的第一版实现完成后,其实还存在着一些不足:

  • 背包的格子很多,一次性加载会造成卡顿
  • 没必要每次移动物品后都写入数据库,可以在服务器内存里保留一个Map映射,当玩家下线后再根据此映射将整个背包的数据写入
    对于第一个问题,我采用类型WOW里的背包模式,即增加一个仅能装备背包的装备栏,并加入“背包”这个物品,根据玩家选择的背包动态加载格子而非一次性全部加载。第二个问题则在Bag.xml里新增一个属性ItemBagMap保存物品id与格子id的映射

Store and PlayerInfo

商店界面和个人信息界面和背包类似,只不过在每个Grid里加上了价格标签而已,并且点击物品可以弹出购买界面,这只是UI与逻辑的不同罢了,在这里就不详谈了。出于美观,还可以在个人信息界面的中间做一个人物立绘,通过设定相机渲染到一个Reneder Texture便可以实现了

Pick Up Item

有了物品系统,相应的拾取逻辑也是必不可少的。在我的实现中主要基于碰撞检测的回调函数:

  • 人物和掉落在地上的物品具有碰撞检测
  • 当产生碰撞时判断背包是否已满,未满创建物品对应的grid对象并销毁地上物品的GameObject
  • 物品存入背包成功则写入Lua
public virtual void OnTriggerEnter(Collider col)
{
    TryPickup(col.gameObject);
}



public virtual void OnTriggerEnter2D(Collider2D col)
{
    TryPickup(col.gameObject);
}

protected virtual void TryPickup(GameObject obj)
{

    if (obj.layer == InventorySettingsManager.instance.equipmentLayer)
    {
        return;
    }

    if (InventorySettingsManager.instance.itemTriggerOnPlayerCollision || CanPickupGold(obj))
    {
        var item = obj.GetComponent<ObjectTriggererItem>();
        if (item != null)
        {
            item.Use(this);
        }
    }
}

protected virtual bool CanPickupGold(GameObject obj)
{
    return InventorySettingsManager.instance.alwaysTriggerGoldItemPickupOnPlayerCollision && obj.GetComponent<CurrencyInventoryItem>() != null;
}

protected virtual void PickUpSucc(itemId, gridId)
{
    AppFacade.instance.CallLua("pg.global.bag.addItem", curItemId, gridId)
}

猜你喜欢

转载自blog.csdn.net/feiyagogogo/article/details/81174142