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
(InventoryUIItemWrapperBasefrom) { 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
InventoryUIDragLookupOnEndDrag(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) }

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信