658 lines
26 KiB
Python
658 lines
26 KiB
Python
# coding=utf-8
|
||
|
||
from BlueFoxSystem import BlueFoxClientSystem
|
||
from ControllableUi.Animation import MoveToPos
|
||
from ..ItemTools import IsSameItem, GetItemBaseInfoSafely, GetItemDurabilityPercent, DeclareItemAnyNum, IsItemDict
|
||
from ..OtherTools import Mount, FixList
|
||
from ..ScreenTools import ScreenTools
|
||
from ..ToolsConfig import *
|
||
|
||
|
||
class SlotOffset(dict):
|
||
def __getitem__(self, item):
|
||
return super(SlotOffset, self).get(item, 0)
|
||
|
||
|
||
@Mount(BlueFoxClientSystem)
|
||
class RucksackScreen(baseScreen):
|
||
flyingItemRender = None
|
||
slotOffset = SlotOffset()
|
||
flyingMoveControl = None # type:MoveToPos
|
||
blueFoxClient = BlueFoxClientSystem if 0 else None
|
||
|
||
def __init__(self, name_spase, ui_key, param, items=None, customData=None, flyingPanelPath=None):
|
||
super(RucksackScreen, self).__init__(name_spase, ui_key, param)
|
||
self._selectSlot = -1
|
||
self.__itemNum = [] # 物品数量
|
||
self.__itemD = [] # (目前,总) 耐久度
|
||
self.__itemId = [] # 物品ID
|
||
self.__isItemNone = [] # 是否为缺失物品
|
||
self.flyingItem = {} # 跟随鼠标的物品
|
||
self.moveControls = []
|
||
self.exchangeLock = False
|
||
self.items = items # 所有物品
|
||
if self.items is None: self.items = [] # type:List[Dict]
|
||
self.customData = customData # 自定义数据
|
||
self.gridIndex = {}
|
||
self.flyingPanelPath = flyingPanelPath
|
||
self.offsetSlot = {}
|
||
|
||
self._selectSlot = -1
|
||
|
||
@property
|
||
def selectSlot(self):
|
||
return self._selectSlot
|
||
|
||
@selectSlot.setter
|
||
def selectSlot(self, index):
|
||
self._selectSlot = index
|
||
|
||
def GetStartAndFinalIndex(self, collectName):
|
||
"""
|
||
获取起止索引段
|
||
:param collectName:
|
||
:return:
|
||
"""
|
||
offsetKey = self.offsetSlot.keys()
|
||
offsetKey.sort()
|
||
offset = self.slotOffset[collectName]
|
||
if offset == offsetKey[-1]: return offset, len(self.items)
|
||
for index in range(len(offsetKey) - 1):
|
||
if offset == offsetKey[index]: return offset, offsetKey[index + 1]
|
||
|
||
def RecalculateOffsetSlot(self):
|
||
"""
|
||
重新计算OffsetSlot
|
||
:return:
|
||
"""
|
||
self.offsetSlot = {}
|
||
for _ in self.slotOffset.items(): self.offsetSlot[_[1]] = _[0]
|
||
|
||
def PrintSlotName(self):
|
||
offsetKey = self.offsetSlot.keys()
|
||
offsetKey.sort()
|
||
for _ in offsetKey:
|
||
print (_, self.offsetSlot[_])
|
||
print '--------------'
|
||
|
||
def AddSlot(self, slotName, gridPath, items, dim, refresh=True):
|
||
"""
|
||
增加槽位,需要在Create函数执行之前绑定所需的connectionName
|
||
:param slotName: 槽位名称
|
||
:param refresh: 是否刷新数据
|
||
:param gridPath: 网格路径
|
||
:param items: 物品集
|
||
:param dim: 网格尺寸
|
||
:return:
|
||
"""
|
||
if slotName in self.slotOffset: return
|
||
self.InitSlot(slotName, gridPath, items, dim)
|
||
self.InitItemData() if refresh else 0
|
||
|
||
def DelSlot(self, slotName, refresh=True):
|
||
"""
|
||
删除槽位,包括items,slotOffset,offsetSlot
|
||
:param slotName:槽位名称
|
||
:param refresh: 是否刷新数据
|
||
:return:
|
||
"""
|
||
if not slotName in self.slotOffset: return
|
||
offsetKey = self.offsetSlot.keys()
|
||
offsetKey.sort()
|
||
startAndEndIndex = self.GetStartAndFinalIndex(slotName)
|
||
oldOffset = startAndEndIndex[0]
|
||
size = startAndEndIndex[1] - startAndEndIndex[0]
|
||
del self.items[startAndEndIndex[0]: startAndEndIndex[1]]
|
||
del self.offsetSlot[oldOffset]
|
||
del self.slotOffset[slotName]
|
||
del self.gridIndex[slotName]
|
||
for index in offsetKey[::-1]:
|
||
if oldOffset < index: self.slotOffset[self.offsetSlot[index]] = index - size
|
||
self.RecalculateOffsetSlot()
|
||
self.InitItemData() if refresh else 0
|
||
|
||
# ------------------------------ init ------------------------------
|
||
def InitItemDataOne(self, slot, slotName, item):
|
||
"""
|
||
对某个槽位进行初始化,需要在InitData之后调用
|
||
"""
|
||
if item:
|
||
itemInfo = GetItemBaseInfoSafely(item)
|
||
self.__itemNum[slot] = item['count']
|
||
self.__itemId[slot] = itemInfo['id_aux']
|
||
self.__itemD[slot] = GetItemDurabilityPercent(item, itemInfo)
|
||
self.__isItemNone[slot] = False
|
||
else:
|
||
self.__itemNum[slot] = 0
|
||
self.__itemD[slot] = (0.0, 0.0)
|
||
self.__itemId[slot] = 0
|
||
self.__isItemNone[slot] = False
|
||
|
||
def InitItemData(self):
|
||
"""
|
||
依据当前items初始化显示所需的物品数据
|
||
:return:
|
||
"""
|
||
self.moveControls = [None for _ in self.items]
|
||
self.__itemNum = [0 for _ in self.items]
|
||
self.__itemD = [(0.0, 0.0) for _ in self.items]
|
||
self.__itemId = [0 for _ in self.items]
|
||
self.__isItemNone = [False for _ in self.items]
|
||
offsets = self.offsetSlot.keys()
|
||
offsets.sort()
|
||
for offsetIndex in range(len(offsets[:-1])):
|
||
for index in range(offsets[offsetIndex], offsets[offsetIndex + 1]):
|
||
if not IsItemDict(self.items[index]): self.items[index] = {}
|
||
self.InitItemDataOne(index, self.offsetSlot[offsets[offsetIndex]], self.items[index])
|
||
for index in range(offsets[-1], len(self.items)):
|
||
if not IsItemDict(self.items[index]): self.items[index] = {}
|
||
self.InitItemDataOne(index, self.offsetSlot[offsets[-1]], self.items[index])
|
||
|
||
def InitFlyingPanel(self, path):
|
||
self.flyingItemRender = self.GetBaseUIControl(path).asItemRenderer()
|
||
self.flyingMoveControl = MoveToPos(self.flyingItemRender, 0.1)
|
||
|
||
def InitSlot(self, slotName, gridPath, items, dimension):
|
||
"""
|
||
初始化物品槽
|
||
:param dimension: 物品槽网格的尺寸
|
||
:param items: 物品槽内的物品
|
||
:param slotName:物品槽名称
|
||
:param gridPath:物品槽的网格路径
|
||
:return:
|
||
"""
|
||
items = FixList(items, dimension[0] * dimension[1], {})
|
||
self.GetBaseUIControl(gridPath).asGrid().SetGridDimension(tuple(dimension))
|
||
self.gridIndex[slotName] = gridPath
|
||
offset = len(self.items)
|
||
self.slotOffset[slotName] = offset
|
||
self.offsetSlot[offset] = slotName
|
||
self.items += items
|
||
self.BindingAll(slotName)
|
||
|
||
# ------------------------------ init ------------------------------
|
||
|
||
def PlayerInvItemChanged(self, args):
|
||
"""
|
||
玩家背包服务端主动发生改变时触发
|
||
"""
|
||
self.SetUiVisibleInfo(args['item'], args['slot'])
|
||
|
||
def Create(self):
|
||
self.blueFoxClient.ListenForEvent(
|
||
MOD_NAME, 'BlueFoxServerSystem', 'PlayerInvItemChanged', self, self.PlayerInvItemChanged
|
||
)
|
||
|
||
def Destroy(self):
|
||
self.blueFoxClient.UnListenForEvent(
|
||
MOD_NAME, 'BlueFoxServerSystem', 'PlayerInvItemChanged', self, self.PlayerInvItemChanged
|
||
)
|
||
|
||
playerId = clientApi.GetLocalPlayerId()
|
||
x, y, z = clientCompFactory.CreatePos(playerId).GetFootPos()
|
||
rot = clientCompFactory.CreateRot(playerId).GetRot()
|
||
rx, ry, rz = clientApi.GetDirFromRot(rot)
|
||
self.blueFoxClient.NotifyToServer('RucksackScreenClosed', {
|
||
'posDim': (
|
||
(x + rx * 0.3, y + 1.08, z + rz * 0.3), clientCompFactory.CreateGame(LevelId).GetCurrentDimension()
|
||
), 'playerRot': rot
|
||
})
|
||
for moveControl in self.moveControls: moveControl.Finish() if moveControl else 0
|
||
|
||
def ItemCellGridInit(self, gridPath, collectionName):
|
||
"""
|
||
物品槽网格初始化时触发
|
||
:param gridPath:网格路径
|
||
:param collectionName:集合名称
|
||
:return:
|
||
"""
|
||
pass
|
||
|
||
def BindingAll(self, collectionName):
|
||
bindingFunc = ScreenTools.CollectionViewBinder
|
||
bindingBool = viewBinder.BF_BindBool
|
||
bindingInt = viewBinder.BF_BindInt
|
||
bindingFloat = viewBinder.BF_BindFloat
|
||
bindingString = viewBinder.BF_BindString
|
||
bindingFunc(bindingBool, collectionName, '#item_num_visible', self.ItemsNumVisible) # 是否显示物品数量文字
|
||
bindingFunc(bindingString, collectionName, '#item_num', self.ItemsNum) # 显示物品数量
|
||
bindingFunc(bindingBool, collectionName, '#select_visible', self.SelectVisible) # 是否显示物品槽选择
|
||
bindingFunc(bindingInt, collectionName, '#item_id_aux', self.RenderItems) # 显示物品
|
||
bindingFunc(bindingBool, collectionName, '#item_durability_visible', self.ItemsDurabilityVisible) # 是否显示物品耐久度条
|
||
bindingFunc(
|
||
bindingFloat, collectionName, '#item_durability_total_amount', self.ItemsDurabilityTotal
|
||
) # 物品耐久度条总量
|
||
bindingFunc(
|
||
bindingFloat, collectionName, '#item_durability_current_amount', self.ItemsDurabilityCurrent
|
||
) # 物品耐久度条当前量
|
||
bindingFunc(bindingBool, collectionName, '#item_none_visible', self.ItemsNone) # 是否显示缺失物品背景
|
||
bindingFunc(bindingBool, collectionName, '#item_cell_init', self.ItemCellInit) # 初始化时触发
|
||
|
||
# --------------------- bindings ---------------------
|
||
|
||
def GetGirdPath(self, collectionName):
|
||
return self.gridIndex[collectionName]
|
||
|
||
def ItemCellInit(self, collectionName, index):
|
||
"""
|
||
初始化时触发,无需任何返回值
|
||
:param collectionName:集合名称
|
||
:param index:在网格内的索引值
|
||
:return:
|
||
"""
|
||
if not index: self.ItemCellGridInit(self.GetGirdPath(collectionName), collectionName)
|
||
|
||
def ItemsNumVisible(self, collectionName, index):
|
||
index = index + self.slotOffset.get(collectionName, 0)
|
||
return self.__itemNum[index] > 1 if index < self.__itemNum.__len__() else False
|
||
|
||
def ItemsNum(self, collectionName, index):
|
||
index = index + self.slotOffset.get(collectionName, 0)
|
||
return str(self.__itemNum[index]) if index < self.__itemNum.__len__() else ''
|
||
|
||
def SelectVisible(self, collectionName, index):
|
||
index = index + self.slotOffset.get(collectionName, 0)
|
||
return index == self.selectSlot
|
||
|
||
def RenderItems(self, collectionName, index):
|
||
index = index + self.slotOffset.get(collectionName, 0)
|
||
return self.__itemId[index] if index < self.__itemId.__len__() else 0
|
||
|
||
def ItemsDurabilityVisible(self, collectionName, index):
|
||
index = index + self.slotOffset.get(collectionName, 0)
|
||
if index >= self.__itemD.__len__():
|
||
return False
|
||
info = self.__itemD[index]
|
||
return info[0] != info[1] and info[1] > 0
|
||
|
||
def ItemsDurabilityTotal(self, collectionName, index):
|
||
index = index + self.slotOffset.get(collectionName, 0)
|
||
return self.__itemD[index][1] if index < self.__itemD.__len__() else 0.0
|
||
|
||
def ItemsDurabilityCurrent(self, collectionName, index):
|
||
index = index + self.slotOffset.get(collectionName, 0)
|
||
return self.__itemD[index][0] if index < self.__itemD.__len__() else 0.0
|
||
|
||
def ItemsNone(self, collectionName, index):
|
||
index = index + self.slotOffset.get(collectionName, 0)
|
||
return self.__isItemNone[index] if index < self.__isItemNone.__len__() else False
|
||
|
||
# --------------------- bindings ---------------------
|
||
|
||
def SetNoneItem(self, slot, itemDict):
|
||
"""
|
||
将某个槽位设置为缺少物品
|
||
:param slot:
|
||
:param itemDict:
|
||
:return:
|
||
"""
|
||
itemInfo = GetItemBaseInfoSafely(itemDict)
|
||
self.__itemNum[slot] = itemDict['count']
|
||
self.__itemD[slot] = GetItemDurabilityPercent(itemDict, itemInfo)
|
||
self.__itemId[slot] = itemInfo['id_aux']
|
||
self.__isItemNone[slot] = True
|
||
self.items[slot] = {}
|
||
|
||
def NoticeServerChangeItem(self, slot, itemDict, itemOperate):
|
||
self.blueFoxClient.NotifyToServer(
|
||
'ChangeItem', {
|
||
'slot': slot, 'item': itemDict, 'itemOperate': itemOperate,
|
||
'posDim': None, 'posType': self.GetOffsetNameByIndex(slot),
|
||
'startSlot': self.GetOffsetStartIndex(slot)
|
||
}
|
||
)
|
||
|
||
def NoticeServerSpawnItemEntities(self, itemDict):
|
||
playerId = clientApi.GetLocalPlayerId()
|
||
x, y, z = clientCompFactory.CreatePos(playerId).GetFootPos()
|
||
self.blueFoxClient.NotifyToServer("SpawnItemEntity", {
|
||
'posDim': (
|
||
(x, y + 1.6, z), clientCompFactory.CreateGame(LevelId).GetCurrentDimension()
|
||
), 'item': itemDict,
|
||
'playerRot': clientCompFactory.CreateRot(playerId).GetRot()
|
||
})
|
||
|
||
def SetItem(self, slot, itemDict=None, noticeServer=True):
|
||
"""
|
||
设置某个槽位, 不论是否物品为空, 返回原本物品
|
||
:param noticeServer:
|
||
:param itemDict:
|
||
:param slot:
|
||
:return:
|
||
"""
|
||
return self.SetUiItem(slot, itemDict, noticeServer) if itemDict else self.SetUiItemNone(slot, noticeServer)
|
||
|
||
def SetItemAbs(self, slot, itemDict=None, noticeServer=False):
|
||
"""
|
||
设置某个槽位, 不论是否物品为空
|
||
:param noticeServer:
|
||
:param itemDict:
|
||
:param slot:
|
||
:return:
|
||
"""
|
||
self.SetUiItemAbs(slot, itemDict, noticeServer) if itemDict else self.SetUiItemNone(slot, noticeServer)
|
||
|
||
def SetUiItemNone(self, slot, noticeServer=None):
|
||
"""
|
||
将某个槽位设置为空,返回原本物品
|
||
:param noticeServer:
|
||
:param slot:
|
||
:return:
|
||
"""
|
||
originItem = self.items[slot]
|
||
self.SetUiItemAbs(slot, {}, noticeServer)
|
||
return originItem
|
||
|
||
def SetUiItemAbs(self, slot, destinationItem, noticeServer=True, itemOperate=None):
|
||
"""
|
||
设置某一个槽位的物品, 不返回任何物品及合并
|
||
:param itemOperate: 物品操作,用于服务端操作
|
||
:param noticeServer: 是否通知服务端,默认发送
|
||
:param slot:设置槽位
|
||
:param destinationItem:目标物品字典
|
||
:return:
|
||
"""
|
||
destinationItemInfo = GetItemBaseInfoSafely(destinationItem)
|
||
self.__itemNum[slot] = destinationItem.get('count', 0)
|
||
self.__itemD[slot] = GetItemDurabilityPercent(destinationItem, destinationItemInfo)
|
||
self.__itemId[slot] = destinationItemInfo.get('id_aux', 0)
|
||
self.__isItemNone[slot] = False
|
||
|
||
self.items[slot] = destinationItem
|
||
self.NoticeServerChangeItem(slot, destinationItem, itemOperate) if noticeServer else 0
|
||
|
||
def SetUiItem(self, slot, destinationItem, noticeServer=True):
|
||
"""
|
||
设置某一个槽位的物品,返回原本物品如果不可合并或者合并后多出的物品
|
||
:param noticeServer: 是否通知服务端
|
||
:param slot:设置槽位
|
||
:param destinationItem:目标物品字典
|
||
:return:
|
||
"""
|
||
originItem = self.items[slot]
|
||
originItemInfo = GetItemBaseInfoSafely(destinationItem)
|
||
if IsSameItem(originItem, destinationItem):
|
||
if originItem['count'] + destinationItem['count'] <= originItemInfo['maxStackSize']:
|
||
destinationItem['count'] += originItem['count']
|
||
originItem = {}
|
||
else:
|
||
originItem['count'] += destinationItem['count'] - originItemInfo['maxStackSize']
|
||
destinationItem['count'] = originItemInfo['maxStackSize']
|
||
self.SetUiItemAbs(slot, destinationItem, noticeServer)
|
||
return originItem
|
||
|
||
def SetUiVisibleInfo(self, itemDict, slot):
|
||
"""
|
||
设置物品,通常用于服务端主动设置物品,此接口不会发送ChangeItem事件
|
||
:param itemDict:物品信息字典
|
||
:param slot:设置槽位
|
||
:return:
|
||
"""
|
||
self.SetUiItemAbs(slot, itemDict, False)
|
||
|
||
def GetOffsetNameByIndex(self, index):
|
||
"""
|
||
通过index获取偏移名称
|
||
:param index:
|
||
:return:
|
||
"""
|
||
offsetKey = self.offsetSlot.keys()
|
||
offsetKey.sort()
|
||
offset = offsetKey[-1]
|
||
for _ in range(offsetKey.__len__() - 1):
|
||
if offsetKey[_] <= index < offsetKey[_ + 1]:
|
||
return self.offsetSlot[offsetKey[_]]
|
||
return self.offsetSlot[offset]
|
||
|
||
def GetOffsetStartIndex(self, index):
|
||
"""
|
||
通过index获取偏移起始index
|
||
:param index:
|
||
:return:
|
||
"""
|
||
offsetKey = self.offsetSlot.keys()
|
||
offsetKey.sort()
|
||
offset = offsetKey[-1]
|
||
for _ in range(offsetKey.__len__() - 1):
|
||
if offsetKey[_] <= index < offsetKey[_ + 1]:
|
||
return offsetKey[_]
|
||
return offsetKey[-1]
|
||
|
||
def GetItemCellByIndex(self, index):
|
||
"""
|
||
通过槽位获取itemCell的路径
|
||
:param index:槽位编号
|
||
:return:
|
||
"""
|
||
offset = self.GetOffsetStartIndex(index)
|
||
return self.gridIndex[self.offsetSlot[offset]] + '/item_cell{}'.format(index - offset + 1)
|
||
|
||
# 以下三个方法是pe背包槽位交互模式
|
||
def FlyingMoveFinish(self, slot):
|
||
"""
|
||
pe下槽位发生物品堆叠时, flyRender动画完成时触发
|
||
:return:
|
||
"""
|
||
self.flyingItemRender.SetVisible(False) if self.flyingItemRender else 0
|
||
self.NoticeServerChangeItem(
|
||
slot, self.flyingItem,
|
||
ItemOperate.ExchangeFlying(
|
||
slot - self.GetOffsetStartIndex(slot), self.GetOffsetNameByIndex(slot)
|
||
)
|
||
)
|
||
self.flyingItem = {}
|
||
|
||
def ExchangeFinish(self, slot, destinationSlot):
|
||
"""
|
||
pe下槽位发生物品交换时, 动画完成时触发
|
||
:param destinationSlot: 与其交换的槽位
|
||
:param slot: 槽位
|
||
:return:
|
||
"""
|
||
deSlotName = self.GetOffsetNameByIndex(destinationSlot)
|
||
deSlotOffset = destinationSlot - self.GetOffsetStartIndex(destinationSlot)
|
||
fromSlotName = self.GetOffsetNameByIndex(slot)
|
||
fromSlotOffset = slot - self.GetOffsetStartIndex(slot)
|
||
|
||
originItem = self.items[slot]
|
||
destinationItem = self.items[destinationSlot]
|
||
self.SetUiItemAbs(slot, destinationItem, False)
|
||
deSlot = self.slotOffset[deSlotName] + deSlotOffset
|
||
if deSlotName not in self.slotOffset or deSlot >= len(self.items):
|
||
self.flyingItem = originItem
|
||
else:
|
||
self.SetUiItemAbs(deSlot, originItem, False)
|
||
self.NoticeServerChangeItem(slot, {}, ItemOperate.Exchange(
|
||
fromSlotOffset, fromSlotName,
|
||
deSlotOffset, deSlotName
|
||
))
|
||
self.flyingItem = {}
|
||
|
||
def StackFinish(self, slot, destinationSlot):
|
||
"""
|
||
pe下槽位发生物品堆叠时, slot动画完成时触发
|
||
:param slot: 槽位
|
||
:param destinationSlot: 与其交换的槽位
|
||
:return:
|
||
"""
|
||
orSlotName = self.GetOffsetNameByIndex(slot)
|
||
orSlotOffset = slot - self.GetOffsetStartIndex(slot)
|
||
deSlotName = self.GetOffsetNameByIndex(destinationSlot)
|
||
deSlotOffset = destinationSlot - self.GetOffsetStartIndex(destinationSlot)
|
||
|
||
self.flyingItem = self.SetItem(destinationSlot, self.items[slot], False)
|
||
orSlot = self.slotOffset[orSlotName] + orSlotOffset
|
||
if orSlotName not in self.slotOffset or orSlot >= len(self.items):
|
||
self.flyingItem = {}
|
||
else:
|
||
self.SetItemAbs(slot, self.flyingItem, False)
|
||
self.flyingItem = {}
|
||
self.flyingItemRender.SetVisible(False, False) if self.flyingItemRender else 0
|
||
self.NoticeServerChangeItem(slot, {}, ItemOperate.Merge(
|
||
orSlotOffset, orSlotName, deSlotOffset, deSlotName
|
||
))
|
||
|
||
@staticmethod
|
||
def SetUiItemForItemRender(render, itemDict):
|
||
"""
|
||
使用itemDict设置物品渲染
|
||
:param render:itemRender
|
||
:param itemDict:需要设置的物品字典
|
||
:return:
|
||
"""
|
||
if not itemDict:
|
||
render.SetVisible(False)
|
||
return
|
||
render.SetUiItem(
|
||
itemDict.get('newItemName', 'minecraft:air'), itemDict.get('newAuxValue', 0),
|
||
(itemDict.get('enchantData', []) + itemDict.get('modEnchantData', [])).__len__() > 0,
|
||
itemDict.get('userData', None)
|
||
)
|
||
|
||
def PcDown(self, selectSlot):
|
||
"""
|
||
电脑点击物品槽触发
|
||
:param selectSlot:槽位
|
||
:return:
|
||
"""
|
||
oldItem = self.items[selectSlot]
|
||
if self.flyingItem is None: self.flyingItem = {}
|
||
self.SetUiItemAbs(
|
||
selectSlot, self.flyingItem, True,
|
||
ItemOperate.ExchangeFlying(
|
||
selectSlot - self.GetOffsetStartIndex(selectSlot), self.GetOffsetNameByIndex(selectSlot)
|
||
)
|
||
)
|
||
self.flyingItem = oldItem
|
||
if self.flyingItemRender:
|
||
self.SetUiItemForItemRender(
|
||
self.flyingItemRender, self.flyingItem
|
||
) if self.flyingItem else self.flyingItemRender.SetVisible(False, False)
|
||
|
||
def GetSlotAnimationState(self, originSlot, destinationSlot):
|
||
"""
|
||
pe模式下, 交换物品时根据槽位确认动画形式
|
||
:param originSlot:先前选择槽位
|
||
:param destinationSlot:后选择槽位
|
||
:return:先前, 后选择, flyingItem
|
||
"""
|
||
originItem = self.items[originSlot]
|
||
destinationItem = self.items[destinationSlot]
|
||
itemInfo = GetItemBaseInfoSafely(originItem)
|
||
if IsSameItem(originItem, destinationItem):
|
||
if originItem['count'] + destinationItem['count'] < itemInfo['maxStackSize']:
|
||
return True, False, False
|
||
elif destinationItem['count'] == itemInfo['maxStackSize']:
|
||
return True, True, False
|
||
else:
|
||
return False, False, True
|
||
return True, True, False
|
||
|
||
def GetPeFlyingItem(self, originSlot, destinationSlot):
|
||
"""
|
||
在pe模式下, 获取flyingItem
|
||
:param originSlot: 现物品槽位
|
||
:param destinationSlot: 目标物品槽位
|
||
:return:
|
||
"""
|
||
itemDict1, itemDict2 = DeclareItemAnyNum(self.items[originSlot], 64 - self.items[destinationSlot]['count'])
|
||
self.SetItemAbs(originSlot, itemDict1)
|
||
return itemDict2
|
||
|
||
def DeliverItem(self, originSlot, destinationSlot):
|
||
"""
|
||
以动画形式从origin向destination传递物品
|
||
:param originSlot:起源物品槽位
|
||
:param destinationSlot:目标物品槽位
|
||
:return:
|
||
"""
|
||
ox, oy = self.GetAbsPos(self.GetItemCellByIndex(originSlot) + '/item_cell/item_renderer')
|
||
dx, dy = self.GetAbsPos(self.GetItemCellByIndex(destinationSlot) + '/item_cell/item_renderer')
|
||
_, __, ___ = self.GetSlotAnimationState(originSlot, destinationSlot)
|
||
if _:
|
||
self.moveControls[originSlot].StartMove(
|
||
(dx - ox, dy - oy), self.ExchangeFinish if __ else self.StackFinish, originSlot, destinationSlot
|
||
)
|
||
if __:
|
||
self.moveControls[destinationSlot].StartMove(
|
||
(-dx + ox, -dy + oy), lambda: None
|
||
)
|
||
if ___:
|
||
self.SetUiItemForItemRender(self.flyingItemRender, self.items[originSlot]) if self.flyingItemRender else 0
|
||
self.flyingItemRender.SetVisible(True) if self.flyingItemRender else 0
|
||
self.flyingMoveControl.ResetInitialPos((ox, oy))
|
||
self.flyingMoveControl.StartMove(
|
||
(dx, dy), self.StackFinish, originSlot, destinationSlot
|
||
)
|
||
|
||
def PeDown(self, selectSlot):
|
||
"""
|
||
手机点击物品槽触发
|
||
:param selectSlot:槽位
|
||
:return:
|
||
"""
|
||
if self.selectSlot == selectSlot:
|
||
self.selectSlot = -1
|
||
return
|
||
else:
|
||
if self.selectSlot is not -1:
|
||
if self.items[self.selectSlot]:
|
||
self.DeliverItem(self.selectSlot, selectSlot)
|
||
self.selectSlot = -1
|
||
return
|
||
if self.items[selectSlot]:
|
||
self.selectSlot = selectSlot
|
||
self.flyingItemRender.SetPosition(
|
||
self.GetAbsPos(self.GetItemCellByIndex(selectSlot) + '/item_cell/item_renderer')
|
||
) if self.flyingItemRender else 0
|
||
self.flyingMoveControl.ResetInitialPos()
|
||
|
||
@viewBinder.binding(viewBinder.BF_ButtonClickUp, '#item_cell_touch')
|
||
def ButtonUp(self, args):
|
||
"""
|
||
物品槽被点击会触发无论电脑或者手机
|
||
:param args:与普通的按钮回调参数一致
|
||
:return:
|
||
"""
|
||
touchIndex = args['#collection_index'] + self.slotOffset.get(args['#collection_name'], 0)
|
||
self.CreateItemRenderMoveControl(touchIndex)
|
||
self.PeDown(touchIndex) if Platform else self.PcDown(touchIndex)
|
||
|
||
def CreateItemRenderMoveControl(self, slot):
|
||
"""
|
||
创建物品渲染的移动动画控制器
|
||
:param slot:
|
||
:return:
|
||
"""
|
||
if self.moveControls[slot] is None:
|
||
itemCell = self.GetBaseUIControl(self.GetItemCellByIndex(slot))
|
||
self.moveControls[slot] = MoveToPos(
|
||
itemCell.GetChildByName('item_cell').GetChildByName('item_renderer'), 0.1
|
||
)
|
||
|
||
def GetAbsPos(self, path):
|
||
"""
|
||
获取元素的绝对坐标
|
||
:param path:路径
|
||
:return:绝对坐标, xy
|
||
"""
|
||
control = self.GetBaseUIControl(path)
|
||
return control.GetGlobalPosition() if control else (0, 0)
|
||
|
||
@viewBinder.binding(viewBinder.BF_BindInt, '#main.gametick')
|
||
def GameTick(self):
|
||
if clientCompFactory and not Platform and self.flyingItemRender and self.flyingItem:
|
||
x, y = clientCompFactory.CreateActorMotion(clientApi.GetLocalPlayerId()).GetMousePosition()
|
||
self.flyingItemRender.SetPosition((x - 9, y - 9))
|
||
self.flyingItemRender.SetVisible(self.flyingItem, False)
|
||
for moveControl in self.moveControls:
|
||
moveControl.Refresh() if moveControl else 0
|
||
self.flyingMoveControl.Refresh() if self.flyingMoveControl else 0
|
||
|
||
def CreateItemEntityIfFlyItem(self):
|
||
"""
|
||
创建跟随鼠标的物品
|
||
:return:
|
||
"""
|
||
if self.flyingItem: self.NoticeServerSpawnItemEntities(self.flyingItem)
|