local UIStratagemDisk = UIViewClass() local ROTATE_RATE = 0.2 local Ceil = math.ceil local Abs = math.abs local Max = math.max local Min = math.min local RANGE_NODE_NUM = 7 --视野内显示的节点数量 local MIDDLE_NODE_NUM = 4 local TOTAL_NODE_NUM = 12 local ANGLE_UNIT = 30 local ANGLE_ALL = 360 local DRAG_DIRECTION_RIGHT = 1 local DRAG_DIRECTION_LEFT = -1 local OFFSET_TO_ACTIVE_NUM = 3 local ATTR_OFFSET = 80 local EFFECT_ROTATE_TIME = 0.2 local ANIM_INTERVAL = 0.02 local EFFECT_ROTATE_ANGLE = (ANGLE_UNIT / EFFECT_ROTATE_TIME) * ANIM_INTERVAL local resonance_info = require 'Proto/resonance_info_pb' function UIStratagemDisk:OnOpened(context) self.isDragging = false self.attrTrans = self.template_attr.gameObject.transform.parent UIUtils.SetActive(self.template_attr.gameObject, false) self:RegistSystemEvent(EventID.UI_Stratagem_LearnRefresh, self.OnStratagemLearnLv) self:RegistSystemEvent(EventID.UI_ResonanceChange_Refresh, self.RefreshResonanceLv) self:RefreshResonanceLv() self.rangeNodeList = {} self.rangeNodeDataMap = {} self.dragEventData = {} --转盘角度与视野内的初始节点索引的映射 local startIndex = 1 self.angle2NodeInRangeIndex = {} for i = 0, ANGLE_ALL, ANGLE_UNIT do table.insert(self.angle2NodeInRangeIndex, { angle = i, nodeStartIndex = startIndex }) startIndex = startIndex - 1 if startIndex == 0 then startIndex = TOTAL_NODE_NUM end end self.rotTrans = self.group_Lines.gameObject.transform self:RegistTriggerEvent(self.obj_Drag, UIEventTriggerType.Drag) self:RegistTriggerEvent(self.obj_Drag, UIEventTriggerType.EndDrag) --只能注册component for i, v in ipairs(self.group_Lines) do self:RegistTriggerEvent(v.img_BgNormal, UIEventTriggerType.PointerDown) self:RegistTriggerEvent(v.img_BgNormal, UIEventTriggerType.PointerUp) self:RegistTriggerEvent(v.img_BgNormal, UIEventTriggerType.Drag) self:RegistTriggerEvent(v.img_BgNormal, UIEventTriggerType.EndDrag) end self:RegistSystemEvent(EventID.BagItem_Update, self.RefreshCost) self:RegistSystemEvent(EventID.UI_RefreshCurrency, self.RefreshCost) end function UIStratagemDisk:RefreshResonanceLv() if MDL.Unlock.IsUnlock(MDL.Unlock.FunctionType.Resonance) then UIUtils.SetActive(self.btn_Resonance, true) else UIUtils.SetActive(self.btn_Resonance, false) end UIUtils.SetLabel(self.txt_ResonanceLv, string.FormatByIdsId(Const_IDS["IDS_Resonance_Level"], MDL.FormationResonance.GetSubResonanceLv(resonance_info.Stratagem_Resonance))) end --获取视野内第一个节点的索引 function UIStratagemDisk:GetRangeNodeIndex(targetAngle) local nodeStartIndex for i, v in ipairs(self.angle2NodeInRangeIndex) do --找到最接近的角度 if v.angle >= targetAngle then local last = self.angle2NodeInRangeIndex[i - 1] if last then if self:IsNearestToLeft(targetAngle, v.angle, last.angle) then nodeStartIndex = v.nodeStartIndex else nodeStartIndex = last.nodeStartIndex end else nodeStartIndex = v.nodeStartIndex end break end end return nodeStartIndex end --是否视野内不为空 function UIStratagemDisk:CheckIfRangeHasEmpty() local nodeIndex = self.curRangeNodeIndex for i = 1, RANGE_NODE_NUM do local index = nodeIndex + i - 1 if index > TOTAL_NODE_NUM then index = index % TOTAL_NODE_NUM end local node = self.group_Lines[index] if self.rangeNodeDataMap[node] == nil then return true end end return false end function UIStratagemDisk:GetRangeEmptyNum() local nodeIndex = self.curRangeNodeIndex local emptyNum = 0 for i = 1, RANGE_NODE_NUM do local index = nodeIndex + i - 1 if index > TOTAL_NODE_NUM then index = index % TOTAL_NODE_NUM end local node = self.group_Lines[index] if self.rangeNodeDataMap[node] == nil then emptyNum = emptyNum + 1 end end return emptyNum end function UIStratagemDisk:GetAngleByRangeNodeIndex(rangeNodeIndex) for i, v in ipairs(self.angle2NodeInRangeIndex) do --找到最接近的角度 if v.nodeStartIndex == rangeNodeIndex then return v.angle end end return 0 end --获取拖拽前后两个节点索引的变化 function UIStratagemDisk:GetNodeIndexOffset(newNodeIndex, lastNodeIndex, direction) local offset local lastIndex = lastNodeIndex or 1 if direction == DRAG_DIRECTION_RIGHT then if newNodeIndex > lastIndex then offset = TOTAL_NODE_NUM - (newNodeIndex - lastIndex) else offset = lastIndex - newNodeIndex end else if newNodeIndex >= lastIndex then offset = newNodeIndex - lastIndex else offset = TOTAL_NODE_NUM - (lastIndex - newNodeIndex) end end return offset end --通过视野内的节点变化获取新的数据索引 function UIStratagemDisk:GetDataIndexByRangeNodeChanged(nodeIndex, direction) local lastIndex = self.curRangeNodeIndex local lastDataIndex = self.curDataIndex if lastIndex == nil then return lastDataIndex else local index local offset = self:GetNodeIndexOffset(nodeIndex, lastIndex, direction) if direction == DRAG_DIRECTION_RIGHT then index = Max(lastDataIndex - offset, 1) else if lastDataIndex == 1 then if self:CheckIfRangeHasEmpty() then index = 1 else index = lastDataIndex + offset end else index = lastDataIndex + offset end end return index end end function UIStratagemDisk:GetStartIndexOffset(activeNum) if activeNum < OFFSET_TO_ACTIVE_NUM then return Min(OFFSET_TO_ACTIVE_NUM - activeNum, OFFSET_TO_ACTIVE_NUM) else return 0 end end --selectIndex居中显示的数据索引 --activeNum激活的数量,不够铺满视野内需要特殊处理 function UIStratagemDisk:ResetRotateParam(selectIndex, playEffect, isMax) if isMax then self.activeNum = selectIndex else self.activeNum = selectIndex - 1 end local dataStartIndex = selectIndex or 1 if playEffect then if isMax then self:RotateToIndex(dataStartIndex) else local node = self:GetNodeByDataIndex(selectIndex - 1) if node and self:CheckIfNodeInMiddle(node) then self:PlayNodeAnim(node) else self:RotateToIndex(dataStartIndex - 1) local node = self:GetNodeByDataIndex(selectIndex - 1) if node then self:PlayNodeAnim(node) else self:RotateToIndex(dataStartIndex) end end end else self:RotateToIndex(dataStartIndex) end end function UIStratagemDisk:CheckIfNodeInMiddle(node) local rootAngle = self:GetCurAngle() local _, _, nodeAngle = node.gameObject.transform:GetLocalEulerAngles() local offset = Abs(nodeAngle - rootAngle) if offset <= 1 then return true end offset = Abs(rootAngle + nodeAngle - ANGLE_ALL) if offset <= 1 then return true end return false end function UIStratagemDisk:PlayNodeAnim(node) node.effect_Available:StopUIEffect() node.effect_Activate:PlayUIEffect() CTL.Sound.PlayGameSound("UI_breakout_01") self.isPlayingEffect = true self.angleOffset = 0 self:StartRepeatFunc(self.AnimToTarget, ANIM_INTERVAL, 0) end function UIStratagemDisk:AnimToTarget() if self.angleOffset >= ANGLE_UNIT then self:StopRepeatFunc(self.AnimToTarget) self:UpdateNodeShow() return end local lastAngle = self:GetCurAngle() self.angleOffset = self.angleOffset + EFFECT_ROTATE_ANGLE local targetAngle = lastAngle - EFFECT_ROTATE_ANGLE self:LoadTargetAngleData(targetAngle, DRAG_DIRECTION_LEFT) self.rotTrans:SetLocalEulerAngles(0, 0, targetAngle) end --强制旋转到数据在中间节点的位置 function UIStratagemDisk:RotateToIndex(dataStartIndex) self.curRangeNodeIndex = 1 self.isDragToRightEnd = false self.isDragToLeftEnd = false local offset = 0 if dataStartIndex <= OFFSET_TO_ACTIVE_NUM then --由于转盘初始位置是在中间,需要加个offset offset = OFFSET_TO_ACTIVE_NUM - dataStartIndex + 1 self.curDataIndex = 1 else self.curDataIndex = dataStartIndex - OFFSET_TO_ACTIVE_NUM end self:UpdateRangeNodeShow(1, self.curDataIndex, offset) self.rotTrans:SetLocalEulerAngles(0, 0, 0) self:UpdateNodeShow() end function UIStratagemDisk:LoadTargetAngleData(targetAngle, direction) local nodeStartIndex = self:GetRangeNodeIndex(targetAngle) if direction == DRAG_DIRECTION_RIGHT and self.isDragToRightEnd then return end if direction == DRAG_DIRECTION_LEFT and self.isDragToLeftEnd then return end if self.curRangeNodeIndex and self.curRangeNodeIndex == nodeStartIndex then return end local dataIndex = self:GetDataIndexByRangeNodeChanged(nodeStartIndex, direction) self:UpdateRangeNodeData(nodeStartIndex, dataIndex, direction) self.curDataIndex = dataIndex self.curRangeNodeIndex = nodeStartIndex end --根据节点变化以及数据索引做表现 function UIStratagemDisk:UpdateRangeNodeData(newNodeIndex, newDataIndex, direction) --计算转盘转到左尽头的差值 local offset = 0 self.isDragToRightEnd = false self.isDragToLeftEnd = false local nodeIndexOffset = self:GetNodeIndexOffset(newNodeIndex, self.curRangeNodeIndex, direction) local emptyNum = self:GetRangeEmptyNum() if newDataIndex == 1 then if direction == DRAG_DIRECTION_RIGHT then if emptyNum == MIDDLE_NODE_NUM - 1 then offset = emptyNum self.isDragToRightEnd = true elseif emptyNum == 0 then offset = nodeIndexOffset else offset = emptyNum + nodeIndexOffset end else if emptyNum > 0 then offset = emptyNum - nodeIndexOffset end end elseif self:GetIfLastDataRange() then if direction == DRAG_DIRECTION_LEFT then self.isDragToLeftEnd = true end end if self.isDragToRightEnd then return end if self.isDragToLeftEnd then return end self:UpdateRangeNodeShow(newNodeIndex, newDataIndex, offset) end function UIStratagemDisk:UpdateRangeNodeShow(newNodeIndex, newDataIndex, offset) for i = 1, RANGE_NODE_NUM do local index = newNodeIndex + i - 1 if index > TOTAL_NODE_NUM then index = index % TOTAL_NODE_NUM end self.rangeNodeList[i] = self.group_Lines[index] end local dataIndex = 0 table.clear(self.rangeNodeDataMap) for i, v in ipairs(self.rangeNodeList) do if offset > 0 then self:SetNodeData(v, nil) offset = offset - 1 else local data = self.configDataList[newDataIndex + dataIndex] dataIndex = dataIndex + 1 self:SetNodeData(v, data) end end for i, v in ipairs(self.group_Lines) do if self.rangeNodeDataMap[v] == nil then UIUtils.SetActive(v.gameObject, false) end end end function UIStratagemDisk:SetNodeData(node, data) if data == nil then UIUtils.SetActive(node.gameObject, false) else UIUtils.SetActive(node.gameObject, true) end self.rangeNodeDataMap[node] = data end function UIStratagemDisk:GetDragDirection() return self.dragEventData[1] > 0 and DRAG_DIRECTION_RIGHT or DRAG_DIRECTION_LEFT end function UIStratagemDisk:OnDrag(comp, eventData) self:OnPointerUp() self.isDragging = true self.dragEventData = { eventData.delta.x, eventData.delta.y } local direction = self:GetDragDirection() local lastAngle = self:GetCurAngle() local value = Ceil(self.dragEventData[1] * ROTATE_RATE + lastAngle) % ANGLE_ALL local targetAngle if value > 0 then targetAngle = value else targetAngle = ANGLE_ALL + value end --算出视野内的节点以及对应的数据 self:LoadTargetAngleData(targetAngle, direction) self.rotTrans:SetLocalEulerAngles(0, 0, targetAngle) self:UpdateNodeShow() end function UIStratagemDisk:OnEndDrag(comp, eventData) self.isDragging = false if self:IsRotateToFinal() == false then local targetAngle = self:GetAngleByRangeNodeIndex(self.curRangeNodeIndex) self.rotTrans:SetLocalEulerAngles(0, 0, targetAngle) self:UpdateNodeShow() end end function UIStratagemDisk:GetNodeByDataIndex(dataIndex) local curNodeIndex = self.curRangeNodeIndex local curDataIndex = self.curDataIndex for i = 1, RANGE_NODE_NUM do local index = curNodeIndex + i - 1 if index > TOTAL_NODE_NUM then index = index % TOTAL_NODE_NUM end local node = self.group_Lines[index] local data = self.rangeNodeDataMap[node] if data then if curDataIndex == dataIndex then return node end curDataIndex = curDataIndex + 1 end end return nil end function UIStratagemDisk:UpdateNodeShow() self.isPlayingEffect = false local nodeIndex = self.curRangeNodeIndex local dataIndex = self.curDataIndex local middleData for i = 1, RANGE_NODE_NUM do local index = nodeIndex + i - 1 if index > TOTAL_NODE_NUM then index = index % TOTAL_NODE_NUM end local node = self.group_Lines[index] local data = self.rangeNodeDataMap[node] if data then node.effect_Activate:StopUIEffect() if dataIndex <= self.activeNum then UIUtils.SetActive(node.img_icon_UnActivated, false) UIUtils.SetActive(node.img_icon_Activated, true) else UIUtils.SetActive(node.img_icon_UnActivated, true) UIUtils.SetActive(node.img_icon_Activated, false) end if dataIndex == self.activeNum + 1 then node.effect_Available:PlayUIEffect() else node.effect_Available:StopUIEffect() end dataIndex = dataIndex + 1 end if i == MIDDLE_NODE_NUM then middleData = data end end if middleData then if middleData.Attr_Table[2] then self.txt_Content.text = self:GetAttr(middleData.Attr_Table[1]) .. "\n" .. self:GetAttr(middleData.Attr_Table[2]) else self.txt_Content.text = self:GetAttr(middleData.Attr_Table[1]) end end end --当前数据索引是否在最末端范围内 function UIStratagemDisk:GetIfLastDataRange() local offset = #self.configDataList - self.curDataIndex if offset <= OFFSET_TO_ACTIVE_NUM then return true end return false end function UIStratagemDisk:IsRotateToFinal() if self.isDragToRightEnd then self:RotateToIndex(1) self.isDragToRightEnd = true return true end if self.isDragToLeftEnd then self:RotateToIndex(#self.configDataList) self.isDragToLeftEnd = true return true end return false end function UIStratagemDisk:GetCurAngle() local x, y, z = self.rotTrans:GetLocalEulerAngles() return z end --判断source是否比较接近left function UIStratagemDisk:IsNearestToLeft(source, left, right) local offsetLeft = Abs(source - left) local offsetRight = Abs(source - right) if offsetLeft <= offsetRight then return true end return false end function UIStratagemDisk:OnPointerDown(comp, eventData) if self.isDragging == true then return end for node, v in pairs(self.rangeNodeDataMap) do if node.img_BgNormal == comp then local data = self.rangeNodeDataMap[node] if data then UIUtils.SetActive(self.template_attr.gameObject, true) --设置节点位置 local x, y, angle = node.gameObject.transform:GetLocalEulerAngles() UIUtils.SetParent(self.attrTrans, node.img_icon_Activated) self.attrTrans:SetLocalPosition(0, 0, 0) self.attrTrans:SetLocalEulerAngles(0, 0, -angle) UIUtils.SetParent(self.attrTrans, self.node_attrShow) local posX, posY = self.attrTrans:GetLocalPosition() self.attrTrans:SetLocalPosition(nil, posY + ATTR_OFFSET) self.attrTrans:SetLocalEulerAngles(0, 0, 0) local content = self:GetAttrStr(data) self.template_attr.txt_Attr.text = content end break end end end function UIStratagemDisk:OnPointerUp(comp, eventData) UIUtils.SetActive(self.template_attr.gameObject, false) end ------------------------------------------------ function UIStratagemDisk:SetConfigCount(id, levelId) self.configDataList = {} for i, v in DataSheetManager.StratagemLearn:GetDataByID_LevelID_PointId(id, levelId) do self.configDataList[i] = v end end function UIStratagemDisk:ChangeStratagem(data, playEffect) self:InitBaseInfo(data) self:SetLearnInfo(data, playEffect) self.showData = data end function UIStratagemDisk:InitBaseInfo(data) self.lab_StratagemName.text = UTL.Color.FormatQualityText(UIUtils.GetLocalizedTxt(Const_IDS[data.StratagemName]), data.StratagemQuality) self.txt_TreasureTalent.text = data.StratagemTalent local stratagemInfo = MDL.Stratagem.GetStratagemInfo(data.ID) self.txt_CE.text = stratagemInfo.StratagemGS end function UIStratagemDisk:SetLearnInfo(data, playEffect) local stratagemInfo = MDL.Stratagem.GetStratagemInfo(data.ID) local levelId = stratagemInfo.Learn.CurrLvID local pointId = stratagemInfo.Learn.CurrPointID local maxCount = DataSheetManager.StratagemLearn:GetDataLengthByID_LevelID_PointId(data.ID, levelId) local maxLevel = 0 local isMax = false for i, v in DataSheetManager.StratagemLearn:GetDataByID_LevelID_PointId(data.ID) do maxLevel = v.LevelID end if maxLevel == levelId and pointId >= maxCount then isMax = true elseif maxCount <= pointId then levelId = levelId + 1 pointId = 1 else pointId = pointId + 1 end self.itemNotEnough = nil local learnData = DataSheetManager.StratagemLearn:GetDataByID_LevelID_PointId(data.ID, levelId, pointId) if not isMax then self.curLearnData = learnData self:InitCost(learnData) end self.btn_Active:SetRedPoint(not self.itemNotEnough) local curIndex = pointId self:SetConfigCount(data.ID, levelId) self:ResetRotateParam(curIndex, playEffect, isMax) self.txt_Content.text = self:GetAttrStr(learnData) if maxLevel == levelId then UIUtils.SetActive(self.img_Arrow, false) UIUtils.SetLabelText(self.txt_max, Const_IDS["IDS_Type_EquipShow_" .. levelId]) else UIUtils.SetActive(self.img_Arrow, true) UIUtils.SetLabelText(self.txt_Tier1, Const_IDS["IDS_Type_EquipShow_" .. levelId]) UIUtils.SetLabelText(self.txt_Tier2, Const_IDS["IDS_Type_EquipShow_" .. (levelId + 1)]) end local talentPoint = 0 for i, v in DataSheetManager.StratagemLearn:GetDataByID_LevelID_PointId(data.ID, levelId) do talentPoint = talentPoint + v.TalentPoint end self.txt_Tip.text = string.FormatByIdsId(Const_IDS.IDS_Stratagem_LearnDesc, talentPoint) self.txt_Num.text = "+" .. talentPoint if isMax then local node = self:GetNodeByDataIndex(curIndex) UIUtils.SetActive(node.img_icon_UnActivated, false) UIUtils.SetActive(node.img_icon_Activated, true) UIUtils.SetActive(self.img_Arrow, false) UIUtils.SetActive(self.group_Active, false) UIUtils.SetActive(self.group_Full, true) local count = MDL.Bag.GetItemCount(data.PieceItem) or 0 UTL.Item.SetItemCell(self.obj_fullItem, data.PieceItem, count) UIUtils.SetImageByAssetBundle(self.img_Fill, ConstAssetPathConfig.AssetPath165) self.effect_Full:PlayUIEffect() else UIUtils.SetActive(self.group_Full, false) UIUtils.SetImageByAssetBundle(self.img_Fill, ConstAssetPathConfig.Path38) end self.img_Fill.fillAmount = curIndex / maxCount self.img_Fill.material:SetFloat("_MusouValue", curIndex / maxCount); self.txt_Advanced.text = "Lv."..levelId end function UIStratagemDisk:GetAttr(attrInfo) local attrData = DataSheetManager.AttrData:GetDataByID(attrInfo.AttrType) if attrData then return UIUtils.GetLocalizedTxt(Const_IDS[attrData.Name]) .. UTL.Color.FormatGreenColor("+" .. attrInfo.AttrNum) end end function UIStratagemDisk:GetAttrStr(learnData) local str = nil for i, v in ipairs(learnData.Attr_Table) do if str then str = str .. "\n" .. self:GetAttr(v) else str = self:GetAttr(v) end end return str end function UIStratagemDisk:GetItemStr(id, needCount) local haveCount = CTL.Bag.GetHasCountByItemCfgID(id) if needCount <= haveCount then return UTL.Color.FormatQualityText(UTL.String.GetCountStr(haveCount), 1) .. "/" .. needCount else self.itemNotEnough = id return UTL.Color.FormatRedColor(UTL.String.GetCountStr(haveCount)) .. "/" .. needCount end end function UIStratagemDisk:OnButtonClicked(comp) if comp == self.btn_Active then if self.itemNotEnough then local itemData = DataSheetManager.ItemData:GetDataByID(self.itemNotEnough) CTL.Tips.AddTipsMsgAndPlaySound(Const_IDS.IDS_Guild_CommonFail1, UIUtils.GetLocalizedTxt(Const_IDS[itemData.Name])) else if self.isPlayingEffect == true then return end MDL.Stratagem.StratagemLearnLvReq(self.showData.ID) end elseif comp == self.obj_fullItem.event_Click then UTL.ItemTips.ShowCommonTipsById(self.showData.PieceItem) elseif comp == self.btn_FullBreak then CTL.Reborn.OpenRecycleFragmentView() elseif comp == self.btn_Resonance then UIManager.OpenView(Const_UI_Lua.UIEnum.UIResonanceInfo, {subResonanceID = resonance_info.Stratagem_Resonance, isShowGoto = false}) else for i, v in ipairs(self.group_NeedItem) do if v.event_Click == comp then UTL.ItemTips.ShowCommonTipsById(self.costItemId) end end end end function UIStratagemDisk:OnStratagemLearnLv() self.lvEffect_Activate:PlayUIEffect() CTL.Sound.PlayGameSound("UI_breakout_02") self:ChangeStratagem(self.showData, true) end function UIStratagemDisk:InitCost(learnData) self.costItemId = learnData.Item_Table[1].ItemID UTL.Item.SetItemCell(self.group_NeedItem[1], self.costItemId, self:GetItemStr(self.costItemId, learnData.Item_Table[1].ItemNum)) local count = CTL.Bag.GetHasCountByItemCfgID(learnData.Item_Table[2].ItemID) or 0 local itemNum = learnData.Item_Table[2].ItemNum if itemNum > count then self.itemNotEnough = learnData.Item_Table[2].ItemID itemNum = UTL.Color.FormatRedColor(itemNum) end UTL.Item.ItemIconWithoutBg(self.icon_Cost, learnData.Item_Table[2].ItemID) self.txt_Cost.text = itemNum end function UIStratagemDisk:RefreshCost() self.itemNotEnough = nil self:InitCost(self.curLearnData) self.btn_Active:SetRedPoint(not self.itemNotEnough) end return UIStratagemDisk