local GFunc = {} local EMPTY_TABLE = {} local TEMP_LIST = {} local TEMP_MAP = {} local HASH_SEED = 31 local UINT_RANGE = 4294967296 local byte = string.byte local DESIGN_RESOLUTION_WIDTH = CS.BF.GameConst.DESIGN_RESOLUTION_WIDTH local DESIGN_RESOLUTION_HEIGHT = CS.BF.GameConst.DESIGN_RESOLUTION_HEIGHT local UnityTime = CS.UnityEngine.Time --获取unicode 字符串长度 和utf-8长度 function GFunc.getTextLen(str) local byteLen = #str local strLen = 0 local i = 1 local curByte local byteCount = 1 while i <= byteLen do curByte = byte(str, i) byteCount = 1 if curByte > 0 and curByte <= 127 then byteCount = 1 elseif curByte >= 192 and curByte < 223 then byteCount = 2 elseif curByte >= 224 and curByte < 239 then byteCount = 3 elseif curByte >= 240 and curByte <= 247 then byteCount = 4 end i = i + byteCount strLen = strLen + 1 end return strLen, i - 1 end function GFunc.getTextLen2(str) local byteLen = #str local strLen = 0 local i = 1 local curByte local byteCount = 1 while i <= byteLen do curByte = byte(str, i) byteCount = 1 if curByte > 0 and curByte <= 127 then byteCount = 1 strLen = strLen + 1 elseif curByte >= 192 and curByte < 223 then -- 中文算2个字节 byteCount = 2 strLen = strLen + 1 elseif curByte >= 224 and curByte < 239 then byteCount = 3 strLen = strLen + 2 elseif curByte >= 240 and curByte <= 247 then byteCount = 4 strLen = strLen + 1 end i = i + byteCount end return strLen, i - 1 end -- 判断字符串是不是全部都是空格,32是半角空格,227是全角空格 function GFunc.getIsAllSpaceStr(str) local result = true local byteLen = #str local i = 1 local curByte local byteCount = 1 while i <= byteLen do curByte = byte(str, i) byteCount = 1 if curByte > 0 and curByte <= 127 then byteCount = 1 if curByte ~= 32 then result = false break end elseif curByte >= 192 and curByte < 223 then byteCount = 2 result = false break elseif curByte >= 224 and curByte < 239 then byteCount = 3 if curByte ~= 227 then result = false break end elseif curByte >= 240 and curByte <= 247 then byteCount = 4 result = false break else result = false break end i = i + byteCount end return result end function GFunc.num2Str(count, dec) if count >= 99999999999 then -- 前端限制最大显示99999M if dec then return "99999.99M" else return "99999M" end elseif count >= 10000000 then if dec then count = math.floor((count*10^dec)/1000000)/(10^dec) return count .. "M" else count = count // 1000000 return count .. "M" end elseif count >= 100000 then if dec then count = math.floor((count*10^dec)/1000)/(10^dec) return count .. "K" else count = count // 1000 return count .. "K" end else return GFunc.parseDedundantNumber(count) end end -- 超过千位就缩写,目前只有公会奖励用到 1K-5K function GFunc.num2Str2(count, dec) if count >= 99999999999 then -- 前端限制最大显示99999M if dec then return "99999.99M" else return "99999M" end elseif count >= 1000000 then if dec then count = math.floor((count*10^dec)/1000000)/(10^dec) return count .. "M" else count = count // 1000000 return count .. "M" end elseif count >= 1000 then if dec then count = math.floor((count*10^dec)/1000)/(10^dec) return count .. "K" else count = count // 1000 return count .. "K" end else return GFunc.parseDedundantNumber(count) end end -- 与num2Str类似 但是上限扩大3位至99999B function GFunc.num2Str3(count, dec) if count >= 99999999999999 then -- 前端限制最大显示99999B if dec then return "99999.99B" else return "99999B" end elseif count >= 10000000000 then if dec then count = math.floor((count*10^dec)/1000000000)/(10^dec) return count .. "B" else count = count // 1000000000 return count .. "B" end elseif count >= 10000000 then if dec then count = math.floor((count*10^dec)/1000000)/(10^dec) return count .. "M" else count = count // 1000000 return count .. "M" end elseif count >= 100000 then if dec then count = math.floor((count*10^dec)/1000)/(10^dec) return count .. "K" else count = count // 1000 return count .. "K" end else return GFunc.parseDedundantNumber(count) end end function GFunc.killDOTween(id, complete) if complete == nil then return CS.BF.Utils.KillDOTween(id) else return CS.BF.Utils.KillDOTween(id, complete) end end function GFunc.setDOTweenTimeScale(id, timeScale) CS.BF.Utils.SetDOTweenTimeScale(id, timeScale) end function GFunc.nameToLayer(name) return CS.BF.Utils.NameToLayer(name) end -- BKDRHash function GFunc.hash(str) local h = 0 for i = 1, #str do h = h * HASH_SEED + byte(str, i) end return h%UINT_RANGE end function GFunc.getScreenSize() return CS.UnityEngine.Screen.width, CS.UnityEngine.Screen.height end function GFunc.parseDedundantNumber(num) if num % 1 == 0 then return math.ceil(num) else return num end end function GFunc.openUrl(web) CS.UnityEngine.Application.OpenURL(web) end function GFunc.getShader(shaderName) return CS.UnityEngine.Shader.Find(shaderName) end function GFunc.subStringGetByteCount(str, index) local curByte = byte(str, index) local byteCount = 1 if curByte == nil then byteCount = 0 elseif curByte > 240 then byteCount = 4 elseif curByte > 225 then byteCount = 3 elseif curByte > 192 then byteCount = 2 end return byteCount end function GFunc.subStringByCharCount(str, needCount) local index = 1 local lastIndex = 1 local num = 0 while num < needCount and lastIndex ~= 0 do lastIndex = GFunc.subStringGetByteCount(str, index) index = index + lastIndex num = num + 1 end return string.sub(str,1, index - 1) end function GFunc.setLayer(gameObject, layerName) local trans = gameObject.transform:GetComponentsInChildren(typeof(CS.UnityEngine.Transform)) local layer = GFunc.nameToLayer(layerName) if trans then local len = trans.Length for i = 0, len - 1 do trans[i].gameObject.layer = layer end end end -- 根据当前屏幕分辨率 计算偏差值 function GFunc.calculateFitSizeY() local width, height = GFunc.getScreenSize() local dif = 0 if width / height < DESIGN_RESOLUTION_WIDTH / DESIGN_RESOLUTION_HEIGHT then dif = height / (width / DESIGN_RESOLUTION_WIDTH) - DESIGN_RESOLUTION_HEIGHT end return dif end -- 获得Expand模式下UI分辨率 function GFunc.getUIExpandScreenSize() local width, height = GFunc.getScreenSize() if width / height <= DESIGN_RESOLUTION_WIDTH / DESIGN_RESOLUTION_HEIGHT then height = height * (DESIGN_RESOLUTION_WIDTH / width) width = DESIGN_RESOLUTION_WIDTH else width = width * (DESIGN_RESOLUTION_HEIGHT / height) height = DESIGN_RESOLUTION_HEIGHT end return width, height end function GFunc.checkNameValid(str, min, max) local result = nil if str == nil or str == "" then --输入不能为空 return false else result = string.match(str, "/u{0020}") or string.match(str, "/u{3000}") or string.match(str, "/u{00A0}") end if result then --非法字符 return false end local k, length = GFunc.getTextLen(str) if length < min then return false elseif length > max then return false end return true end function GFunc.showMessageBox(params) local MessageBox = require "app/ui/common/message_box" MessageBox:showMessageBox(params) end function GFunc.showCheatingBox(params) local CheatMessageBox = require "app/ui/common/cheat_message_box" CheatMessageBox:showCheatMessageBox(params) end function GFunc.hideCheatingBox() local CheatMessageBox = require "app/ui/common/cheat_message_box" CheatMessageBox:hideCheatMessageBox() end function GFunc.showToast(params) ModuleManager.ToastManager:showToast(params) end function GFunc.UiRectTransformScreenPointToLocalPointInRectangle(go, x, y) local uiCamera = UIManager:getUICameraComponent() local anchoredPosition = CS.BF.Utils.RectTransformScreenPointToLocalPointInRectangle(go:getTransform(), x, y, uiCamera) return anchoredPosition end function GFunc.UiRectangleContainsScreenPoint(go, x, y) local uiCamera = UIManager:getUICameraComponent() return CS.BF.Utils.RectangleContainsScreenPoint(go:getTransform(), x, y, uiCamera) end function GFunc.getPerByW(ratio) if ratio < 0 then return math.ceil(ratio*0.01) else return math.floor(ratio*0.01) end end function GFunc.getPerByW2(ratio) if ratio < 0 then return math.ceil(ratio*0.0001) else return math.floor(ratio*0.0001) end end function GFunc.getPerByW3(ratio) return ratio*0.0001 end function GFunc.getPerStr(key, str) if key == GConst.BattleConst.BUFF_NAME.ATKP_ADD or key == GConst.BattleConst.BUFF_NAME.ATKP_COLOR_ADD or key == GConst.BattleConst.BUFF_NAME.ATKP_RED_ADD or key == GConst.BattleConst.BUFF_NAME.ATKP_YELLOW_ADD or key == GConst.BattleConst.BUFF_NAME.ATKP_GREEN_ADD or key == GConst.BattleConst.BUFF_NAME.ATKP_BLUE_ADD or key == GConst.BattleConst.BUFF_NAME.ATKP_PURPLE_ADD or key == GConst.BattleConst.BUFF_NAME.DEC_DMG_RED_ADD or key == GConst.BattleConst.BUFF_NAME.DEC_DMG_YELLOW_ADD or key == GConst.BattleConst.BUFF_NAME.DEC_DMG_GREEN_ADD or key == GConst.BattleConst.BUFF_NAME.DEC_DMG_BLUE_ADD or key == GConst.BattleConst.BUFF_NAME.DEC_DMG_PURPLE_ADD or key == GConst.BattleConst.BUFF_NAME.DEC_DMG_ALL_ADD or key == GConst.BattleConst.BUFF_NAME.WEAKNESS_RED_ADD or key == GConst.BattleConst.BUFF_NAME.WEAKNESS_YELLOW_ADD or key == GConst.BattleConst.BUFF_NAME.WEAKNESS_GREEN_ADD or key == GConst.BattleConst.BUFF_NAME.WEAKNESS_BLUE_ADD or key == GConst.BattleConst.BUFF_NAME.WEAKNESS_PURPLE_ADD or key == GConst.BattleConst.BUFF_NAME.WEAKNESS_ALL_ADD or key == GConst.BattleConst.BUFF_NAME.DMG_ADDITION_RED_ADD or key == GConst.BattleConst.BUFF_NAME.DMG_ADDITION_YELLOW_ADD or key == GConst.BattleConst.BUFF_NAME.DMG_ADDITION_GREEN_ADD or key == GConst.BattleConst.BUFF_NAME.DMG_ADDITION_BLUE_ADD or key == GConst.BattleConst.BUFF_NAME.DMG_ADDITION_PURPLE_ADD or key == GConst.BattleConst.BUFF_NAME.DMG_ADDITION_ALL_ADD or key == GConst.BattleConst.BUFF_NAME.HPP_ADD or key == GConst.BattleConst.BUFF_NAME.CRIT_TIME_ADD or key == GConst.BattleConst.BUFF_NAME.EXP_TIME_ADD or key == GConst.BattleConst.BUFF_NAME.CURED_ADD then str = str // 100 .. "%" end return str end function GFunc.getBuffDesc(buffName, effectNum) effectNum = GFunc.getPerStr(buffName, effectNum) return I18N:getTextWithOtherKey("buff", "name", buffName, "desc", effectNum) end function GFunc.getAttrName(key) return I18N:getText("attr", key, "name") end function GFunc.getTimeStrWithMS(time) local m = math.floor(time/60) local s = time%60 return I18N:getGlobalText(I18N.GlobalConst.TIME_MS, string.format("%02d", m), string.format("%02d", s)) end function GFunc.getTimeStrWithMS2(time) local m = math.floor(time/60) local s = time%60 return I18N:getGlobalText(I18N.GlobalConst.TIME_STR_MS, string.format("%02d", m), string.format("%02d", s)) end function GFunc.getTimeStrWithHMS(time) local h = math.floor(time/3600) local m = math.floor((time%3600)/60) local s = time%60 return I18N:getGlobalText(I18N.GlobalConst.TIME_HMS, string.format("%02d", h), string.format("%02d", m), string.format("%02d", s)) end function GFunc.getTimeStrWithM2(time) local m = time // 60 return I18N:getGlobalText(I18N.GlobalConst.TIME_STR_M, m) end function GFunc.getTimeStrWithHMS2(time) local h = math.floor(time/3600) local m = math.floor((time%3600)/60) local s = time%60 return I18N:getGlobalText(I18N.GlobalConst.TIME_STR_HMS, h, m, s) end function GFunc.getTimeStrWithDH2(time) local d = math.floor(time/86400) local h = math.floor((time%86400)/3600) return I18N:getGlobalText(I18N.GlobalConst.TIME_STR_DH, d, h) end function GFunc.getTimeStrWithD2(time) local d = math.floor(time/86400) return I18N:getGlobalText(I18N.GlobalConst.TIME_STR_D, d) end function GFunc.getTimeStrWithHM(time) local h = math.floor(time/3600) local m = math.floor((time%3600)/60) return I18N:getGlobalText(I18N.GlobalConst.TIME_STR_HM, string.format("%02d", h), string.format("%02d", m)) end function GFunc.getTimeStrWithHM2(time) local h = math.floor(time/3600) local m = math.floor((time%3600)/60) return I18N:getGlobalText(I18N.GlobalConst.TIME_STR_HM, h, m) end function GFunc.getTimeStr(time) if time > 86400 then return GFunc.getTimeStrWithDH2(time) else return GFunc.getTimeStrWithHMS2(time) end end function GFunc.getTimeStr2(time) if time > 86400 then return GFunc.getTimeStrWithD2(time) else return GFunc.getTimeStrWithHM2(time) end end function GFunc.getTimeStr3(time) if time >= 3600 then return GFunc.getTimeStrWithHM(time) else return GFunc.getTimeStrWithMS2(time) end end function GFunc.getAdaptScale(basePixel) basePixel = basePixel or 0 local DESIGN_WIDTH = 720 local DESIGN_HEIGHT = 1280 local safeHeight = SafeAreaManager:getNotchScreenHeight() local winSizeWidth, winSizeHeight = GFunc.getScreenSize() local maxScale = math.max(DESIGN_WIDTH/winSizeWidth, DESIGN_HEIGHT/winSizeHeight) local height = maxScale*winSizeHeight - basePixel - safeHeight local scale = height/(DESIGN_HEIGHT - basePixel) return scale end function GFunc.getConstIntValue(key) local ConstCfg = ConfigManager:getConfig("const") return math.floor(ConstCfg[key].value) end function GFunc.getConstValue(key) local ConstCfg = ConfigManager:getConfig("const") return ConstCfg[key] and ConstCfg[key].value or 0 end function GFunc.getConstReward(key) local ConstCfg = ConfigManager:getConfig("const") return ConstCfg[key] and ConstCfg[key].reward end function GFunc.getTargetAnchoredPosition(targetGo, parent) local rectTransform = targetGo:getComponent(GConst.TYPEOF_UNITY_CLASS.RECTTRANSFORM) local rect = rectTransform.rect local localToWorldMatrix = rectTransform.localToWorldMatrix local tarCornerMid = localToWorldMatrix:MultiplyPoint3x4(BF.Vector3((rect.xMax + rect.x) / 2, (rect.yMax + rect.y) / 2, 0)) local screenPos = UIManager:getUICameraComponent():WorldToScreenPoint(tarCornerMid) local anchoredPosition = CS.BF.Utils.RectTransformScreenPointToLocalPointInRectangle(parent:getTransform(), screenPos.x, screenPos.y, UIManager:getUICameraComponent()) return anchoredPosition end function GFunc.getFormatPrice(rechargeId) local cfg = ConfigManager:getConfig("recharge")[rechargeId] if cfg == nil then return GConst.EMPTY_STRING end -- 优先读取通过sdk获取的商品价格 local price = SDKManager:getProductPrice(cfg.payId) if price and price ~= "" then return price end -- sdk里查不到就读表 return cfg.price_str end function GFunc.setGrey(component, isGrey) if isGrey then component.color = GConst.COMPONENT_GREY_COLOR else component.color = GConst.COLOR.WHITE end end function GFunc.checkBit(value, nbit) if not value then return false end local ret = value >> (nbit - 1) if ret %2 == 1 then return true else return false end end function GFunc.showItemNotEnough(itemId) local gemTextInfo = I18N:getConfig("item")[itemId] if gemTextInfo then GFunc.showToast(I18N:getGlobalText(I18N.GlobalConst.ITEM_NOT_ENOUGH, gemTextInfo.name)) end end function GFunc.checkCost(id, num, showToast) if num <= 0 then return true end local count = DataManager.BagData.ItemData:getItemNumById(id) if count < num then if showToast then GFunc.showItemNotEnough(id) end return false else return true end end ---- 获得奖励的统一接口 function GFunc.addRewards(rewards, itemGetType) if rewards == nil then return end if EDITOR_MODE then if not itemGetType then local params = { content = "GFunc addRewards has no itemGetType", boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), } GFunc.showMessageBox(params) Logger.log("GFunc addRewards has no itemGetType") end end -- 用元表来判断此奖励是否领过了,避免重复领取 if getmetatable(rewards) then return end setmetatable(rewards, EMPTY_TABLE) -- 合并奖励 local newRewards = {} GFunc.mergeRewards2(rewards, newRewards) -- 根据类型type来添加奖励 for k, v in ipairs(newRewards) do if v.type == GConst.REWARD_TYPE.ITEM then DataManager.BagData.ItemData:addItem(v.item, itemGetType) elseif v.type == GConst.REWARD_TYPE.EQUIP then DataManager.BagData.EquipData:addEquipCountById(v.equip.id, v.equip.count, itemGetType) end end end function GFunc.addCosts(costs, itemGetType) if costs == nil then return end -- 用元表来判断此消耗是否领过了,避免重复扣除 if getmetatable(costs) then return end setmetatable(costs, EMPTY_TABLE) for _, unitCost in ipairs(costs) do if unitCost.type == GConst.REWARD_TYPE.ITEM then DataManager.BagData.ItemData:addItemCost(unitCost.item, itemGetType) end end end -- 奖励排序 结构为后端结构 function GFunc.sortRewards(rewards) rewards = rewards or {} local maxType = 10 for i,v in ipairs(rewards) do if v.type == GConst.REWARD_TYPE.ITEM then rewards[i].sort = (maxType - v.type) * 1000000000 + v.item.id elseif v.type == GConst.REWARD_TYPE.EQUIP then local cfg = ConfigManager:getConfig("equip")[v.equip.id] rewards[i].sort = (maxType - v.type) * 1000000000 + cfg.qlt*100000000 + v.equip.id end end table.sort(rewards, function (a, b) return a.sort > b.sort end) end ---- 奖励展示接口 function GFunc.showRewardBox(rewards, extParams, callback) rewards = rewards or {} local params = extParams or {} local newRewards = {} if not params.noMerge then GFunc.mergeRewards2(rewards, newRewards) else newRewards = rewards end params.rewards = newRewards params.callback = callback ModuleManager.TipsManager:showRewardsBox(params) end function GFunc.mergeRewards2(rewards, newRewards, needSort) local items = {} for i,v in ipairs(rewards) do if v.type == GConst.REWARD_TYPE.ITEM then items[v.item.id] = (items[v.item.id] or 0) + v.item.count elseif v.type == GConst.REWARD_TYPE.EQUIP then table.insert(newRewards, v) end end for k,v in pairs(items) do table.insert(newRewards, {type = GConst.REWARD_TYPE.ITEM, item = {id = k, count = v}}) end if needSort then GFunc.sortRewards(newRewards) end end -- reward 结构为 type id num 配置中结构 function GFunc.mergeRewards(rewards) local items = {} local newRewards = {} for i,v in ipairs(rewards) do if v.type == GConst.REWARD_TYPE.ITEM then items[v.id] = (items[v.id] or 0) + v.num elseif v.type == GConst.REWARD_TYPE.EQUIP then table.insert(newRewards, v) elseif v.type == GConst.REWARD_TYPE.LEGACY then table.insert(newRewards, v) end end for k,v in pairs(items) do table.insert(newRewards, {type = GConst.REWARD_TYPE.ITEM, id = k, num = v}) end return newRewards end function GFunc.getRandomIndex(weightArr) if #weightArr <= 0 then return end local maxWeight = 0 for i, v in ipairs(weightArr) do maxWeight = maxWeight + v end local randomWeight = math.random(1, maxWeight) local idx for i, v in ipairs(weightArr) do if randomWeight <= v then idx = i break else randomWeight = randomWeight - v end end return idx end function GFunc.getRewardsStr(rewards) if rewards == nil then return end local itemStr = "" for k, v in ipairs(rewards) do if v.type == GConst.REWARD_TYPE.ITEM then itemStr = itemStr .. v.type .. "." .. v.item.id .. "." .. v.item.count end if k ~= #rewards then itemStr = itemStr.. "|" end end return itemStr end function GFunc.copyStr(str) CS.UnityEngine.GUIUtility.systemCopyBuffer = str end function GFunc.getShakeSeq(obj, onlyKill, originScale, notForcerefresh) originScale = originScale or 1 if obj.shakeSeq then if notForcerefresh then return obj.shakeSeq end obj.shakeSeq:Kill() obj.shakeSeq = nil end obj:setLocalScale(originScale, originScale, originScale) if onlyKill then return end obj.shakeSeq = obj:createBindTweenSequence() obj.shakeSeq:AppendInterval(2) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 1.12, 0.1)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 0.9, 0.11)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 1.1, 0.15)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 0.9, 0.2)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 1.05, 0.25)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 0.9, 0.3)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 1, 0.3)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale, 0.3)) obj.shakeSeq:SetLoops(-1) return obj.shakeSeq end function GFunc.getShakeSeq2(obj, onlyKill, originScale, notForcerefresh) originScale = originScale or 1 if obj.shakeSeq then if not notForcerefresh then return obj.shakeSeq end obj.shakeSeq:Kill() obj.shakeSeq = nil end obj:setLocalScale(originScale, originScale, originScale) if onlyKill then return end obj.shakeSeq = obj:createBindTweenSequence() obj.shakeSeq:AppendInterval(1) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 1.12, 0.1)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 0.9, 0.11)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 1.1, 0.15)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 0.9, 0.2)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 1.05, 0.25)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 0.9, 0.3)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale * 1, 0.3)) obj.shakeSeq:Append(obj:getTransform():DOScale(originScale, 0.3)) obj.shakeSeq:SetLoops(-1) return obj.shakeSeq end function GFunc.getShakeSeqRotate(obj, onlyKill, notForcerefresh) if obj.shakeSeq then if notForcerefresh then return obj.shakeSeq end obj.shakeSeq:Kill() obj.shakeSeq = nil obj:setLocalEulerAngles(0,0,0) end if onlyKill then return end local objTrans = obj:getTransform() obj.shakeSeq = obj:createBindTweenSequence() obj.shakeSeq:AppendInterval(2) local angle = 12 obj.shakeSeq:Append(objTrans:DORotate({x=0,y=0,z=angle},0.2)) obj.shakeSeq:Append(objTrans:DORotate({x=0,y=0,z=-angle},0.1)) obj.shakeSeq:Append(objTrans:DORotate({x=0,y=0,z=angle},0.1)) obj.shakeSeq:Append(objTrans:DORotate({x=0,y=0,z=-angle},0.07)) obj.shakeSeq:Append(objTrans:DORotate({x=0,y=0,z=angle},0.07)) obj.shakeSeq:Append(objTrans:DORotate({x=0,y=0,z=-angle},0.05)) obj.shakeSeq:SetLoops(-1) return obj.shakeSeq end function GFunc.getScaleQueueAni(root, rewardList, listCell, callBack) if root.aniSeq then root.aniSeq:Kill() root.aniSeq = nil end root.aniSeq = root:createBindTweenSequence() local seq = root.aniSeq local groupCell = {} local index = 1 table.foreach(listCell, function(k, cell) if groupCell[index] and #groupCell[index] >= 5 then index = index + 1 end if not groupCell[index] then groupCell[index] = {} end table.insert(groupCell[index], cell) end) local rewardListTrans = rewardList:getTransform() -- ani table.foreach(groupCell, function(row, cells) table.foreach(cells, function(k, cell) local summonRewardCell = cell local rewardType, id = summonRewardCell:getReward() summonRewardCell:showMask() local isNew = summonRewardCell:getIsFirstGet() local rewardQlt = GFunc.getQuality(rewardType, id) if rewardQlt and rewardQlt >= 4 and isNew then -- 紫色以上 seq:AppendInterval(0.4) seq:AppendCallback(function() summonRewardCell:showReward() end) --seq:Append(rewardListTrans:DOShakePosition(0.4, 14, 18, 90,true)) -- 轻幅度震动 seq:Append(rewardListTrans:DOShakePosition(1, 20, 18, 90,true)) -- 大力震动 else seq:AppendCallback(function() summonRewardCell:showReward() end) end end) seq:AppendInterval(0.1) end) seq:AppendCallback(function() if callBack then callBack() end end) return seq end function GFunc.miningTipsMovePosY(obj, delay,callBack) if obj.seq then obj.seq:Kill() obj.seq = nil end obj.seq = obj:createBindTweenSequence() local trans = obj:getTransform() local localPosY = trans.localPosition.y local seq = obj.seq seq:AppendInterval(delay) seq:Append(trans:DOLocalMoveY(localPosY + 200, 1.2)) seq:AppendCallback(function() obj:setActive(false) if callBack then callBack() end end) end function GFunc.dataEncrypt(data) local numStr = CS.Security.XXTEA.Encrypt(tostring(data), GConst.SECRET_KEY) return numStr end function GFunc.dataDecrypt(data) local numStr = CS.Security.XXTEA.Decrypt(data, GConst.SECRET_KEY) return tonumber(numStr) end function GFunc.getTickCount() return math.floor(UnityTime.realtimeSinceStartup) end ---得到展示奖励的图集名称,图片资源id function GFunc.getFrameRes(type, id) if type == GConst.REWARD_TYPE.REWARD_NONE then return end local qlt = 1 local atlasPath = "" if type == GConst.REWARD_TYPE.ITEM then local ItemCfg = ConfigManager:getConfig("item") local config = ItemCfg[id] if not config then return end qlt = config.qlt atlasPath = GConst.ATLAS_PATH.ICON_EQUIP end if type == GConst.REWARD_TYPE.EQUIP then local equipCfg = ConfigManager:getConfig("equip") local config = equipCfg[id] if not config then return end qlt = config.qlt atlasPath = GConst.ATLAS_PATH.ICON_EQUIP end if type == GConst.REWARD_TYPE.RUNES then local runeCfg = ConfigManager:getConfig("runes") local config = runeCfg[id] if not config then return end qlt = config.qlt atlasPath = GConst.ATLAS_PATH.ICON_RUNE end return atlasPath, GConst.HERO_FRAME[ GConst.QUALITY[qlt] ] or "frame_1", qlt end ---得到展示奖励的图集名称,图片资源id function GFunc.getQuality(type, id) if type == GConst.REWARD_TYPE.REWARD_NONE then return end local qlt = 1 if type == GConst.REWARD_TYPE.ITEM then local ItemCfg = ConfigManager:getConfig("item") local config = ItemCfg[id] if not config then return end qlt = config.qlt end if type == GConst.REWARD_TYPE.EQUIP then local equipCfg = ConfigManager:getConfig("equip") local config = equipCfg[id] if not config then return end qlt = config.qlt end if type == GConst.REWARD_TYPE.LEGACY then local equipCfg = ConfigManager:getConfig("legacy") local config = equipCfg[id] if not config then return end qlt = config.qlt end if type == GConst.REWARD_TYPE.RUNES then local runeCfg = ConfigManager:getConfig("runes") local config = runeCfg[id] if not config then return end qlt = config.qlt end return qlt end ---得到展示奖励的图集名称,图片资源id function GFunc.getRewardIconRes(type, id) if type == GConst.REWARD_TYPE.REWARD_NONE then return end if type == GConst.REWARD_TYPE.ITEM then return GFunc.getIconRes(id) end if type == GConst.REWARD_TYPE.EQUIP then return GFunc.getEquipIconRes(id) end if type == GConst.REWARD_TYPE.RUNES then return GFunc.getRuneIconRes(id) end if type == GConst.REWARD_TYPE.LEGACY then return GFunc.getLegacyIconRes(id) end end function GFunc.getIconRes(itemId) local ItemCfg = ConfigManager:getConfig("item") local config = ItemCfg[itemId] if not config then return end return GConst.ATLAS_PATH.ICON_ITEM, tostring(config.icon) end function GFunc.getEquipIconRes(equipId) local EquipCfg = ConfigManager:getConfig("equip") local config = EquipCfg[equipId] if not config then return end return GConst.ATLAS_PATH.ICON_EQUIP, tostring(config.icon) end function GFunc.getRuneIconRes(runeId) local runeCfg = ConfigManager:getConfig("runes") local config = runeCfg[runeId] if not config then return end return GConst.ATLAS_PATH.ICON_RUNE, tostring(config.icon) end function GFunc.getLegacyIconRes(legacyId) local legacyCfg = ConfigManager:getConfig("legacy") local config = legacyCfg[legacyId] if not config then return end return GConst.ATLAS_PATH.ICON_LEGACY, tostring(config.icon) end ---得到展示奖励的图集名称,图片资源id function GFunc.getRewardName(type, id) if type == GConst.REWARD_TYPE.REWARD_NONE then return end if type == GConst.REWARD_TYPE.ITEM then return I18N:getText("item", id, "name") end if type == GConst.REWARD_TYPE.EQUIP then return I18N:getText("equip", id, "desc") end if type == GConst.REWARD_TYPE.RUNES then return I18N:getText("rune", id, "desc") end end function GFunc.compareVersionThan(version1, version2, include) if not version1 or not version2 then return false end local versionStrs = string.split(version1, ".") local versionNum1 = tonumber(versionStrs[1]) local versionNum2 = tonumber(versionStrs[2]) local versionNum3 = tonumber(versionStrs[3]) local versionStrs2 = string.split(version2, ".") local versionNum21 = tonumber(versionStrs2[1]) local versionNum22 = tonumber(versionStrs2[2]) local versionNum23 = tonumber(versionStrs2[3]) if not versionNum1 or not versionNum2 or not versionNum3 or not versionNum21 or not versionNum22 or not versionNum23 then return false end if versionNum1 > versionNum21 then return true, true elseif versionNum1 < versionNum21 then return false end if versionNum2 > versionNum22 then return true, true elseif versionNum2 < versionNum22 then return false end if versionNum3 > versionNum23 then return true elseif versionNum3 < versionNum23 then return false end if include then return true end return false end function GFunc.getFormatCfgRewards(rewards, onlyOne) local cfgRewards = GFunc.getArray() for _, reward in ipairs(rewards) do local cfgReward = { type = reward.type, id = reward.id, count = { value = reward.count.value, unit = reward.count.unit, }, } if onlyOne then return cfgReward else table.insert(cfgRewards, reward) end end return cfgRewards end function GFunc.getUpdateDataMap(fnName, dataName, dataMap, costs, rewards, fnArgs) local params = { fnName = fnName, dataType = dataName, data = dataMap, costs = costs or GFunc.getArray(), rewards = rewards or GFunc.getArray(), fnArgs = fnArgs } return params end function GFunc.isShenhe() return CS.BF.BFMain.IsShenhe end function GFunc.getArray() local array = {} setmetatable(array, {__jsontype = "array"}) return array end function GFunc.getTable(struct) local t = {} if struct then for k, v in pairs(struct) do if type(v) == "table" then t[k] = GFunc.getTable(v) else t[k] = v end end end return t end function GFunc.formatTimeStep(timestep) if timestep and timestep > 10000000000 then timestep = timestep // 1000 end return timestep end function GFunc.randomPos(idx, pos) local posX, posY if idx == 1 then posX = math.random(-50, 0) posY = math.random(0, 50) elseif idx == 2 then posX = math.random(0, 50) posY = math.random(0, 50) elseif idx == 3 then posX = math.random(-50, 0) posY = math.random(-50, 0) elseif idx == 4 then posX = math.random(0, 50) posY = math.random(-50, 0) else posX = math.random(-50, 50) posY = math.random(-50, 50) end return posX + pos.x, posY + pos.y end function GFunc.imgFly(flyImg, beginPos, endPos, callback) if flyImg.aniSeq then flyImg.aniSeq:Kill() end local scale = 0.5 flyImg:setAnchoredPosition(beginPos.x, beginPos.y) flyImg:setVisible(true, 0.1) local maxDis = 2000 local dis = BF.Vector2Distance(beginPos, endPos) local time = dis/maxDis local aniSeq = flyImg:createBindTweenSequence() -- aniSeq:Append(flyImg:getTransform():DOScale(BF.Vector3(scale + 0.2, scale + 0.2, scale + 0.2), 0.1):SetEase(CS.DG.Tweening.Ease.InCubic)) aniSeq:Append(flyImg:getTransform():DOScale(BF.Vector3(scale, scale, scale), 0.04):SetEase(CS.DG.Tweening.Ease.InCubic)) -- aniSeq:AppendInterval(0.3) aniSeq:Append(flyImg:getTransform():DOAnchorPos(endPos, time):SetEase(CS.DG.Tweening.Ease.InCubic)) aniSeq:Join(flyImg:getTransform():DOScale(BF.Vector3(0.1, 0.1, 0.1), time):SetEase(CS.DG.Tweening.Ease.InCubic)) aniSeq:AppendCallback(function() flyImg:setVisible(false) if callback then callback() end end) flyImg.aniSeq = aniSeq end function GFunc.doScaleFlyImg(img, callback) if img.aniSeq then img.aniSeq:Kill() img:setLocalScale(1, 1, 1) end local transform = img:getTransform() local localScale = transform.localScale local scale = localScale.x local aniSeq = img:createBindTweenSequence() aniSeq:Append(img:getTransform():DOScale(BF.Vector3(scale + 0.1, scale + 0.1, scale + 0.1), 0.08):SetEase(CS.DG.Tweening.Ease.InCubic)) aniSeq:Append(img:getTransform():DOScale(BF.Vector3(scale - 0.08, scale - 0.08, scale - 0.08), 0.08):SetEase(CS.DG.Tweening.Ease.InCubic)) aniSeq:Append(img:getTransform():DOScale(BF.Vector3(scale, scale, scale), 0.08):SetEase(CS.DG.Tweening.Ease.InCubic)) aniSeq:AppendCallback(function() if callback then callback() end end) img.aniSeq = aniSeq end function GFunc.doScaleQuickZoom(img,callback) if img.aniSeq then img.aniSeq:Kill() end local transform = img:getTransform() local aniSeq = img:createBindTweenSequence() aniSeq:Append(transform:DOScale(1.4, 0.1)) aniSeq:Append(transform:DOScale(1, 0.06)) aniSeq:AppendCallback(function() if callback then callback() end end) img.aniSeq = aniSeq end -- colorType 1 白色, 2 黑色 function GFunc.setAdsSprite(img, isGrey) if not img then return end -- local skip = DataManager.MallActData:skipAd() local skip = false local icon = nil if isGrey then icon = skip and "common_ad_6" or "common_ad_5" else icon = skip and "common_ad_4" or "common_ad_3" end img:setSprite(GConst.ATLAS_PATH.COMMON, icon) end function GFunc.getAdSprite() local skip = DataManager.MallActData:skipAd() return skip and "common_ad_4" or "common_ad_3" end function GFunc.centerImgAndTx(imgObj, txObj, spacing, offset) spacing = spacing or 0 offset = offset or 0 local imgW = imgObj:getSizeDelta().x local txW = txObj:getComponent(GConst.TYPEOF_UNITY_CLASS.UI_TEXT_MESH_PRO).preferredWidth txObj:setSizeDeltaX(txW) local w = (imgW + txW + spacing) / 2 imgObj:setAnchoredPositionX(imgW / 2 - w + offset) txObj:setAnchoredPositionX(w - txW / 2 + offset) end function GFunc.centerTxAndTx(txObj1, txObj2, spacing) spacing = spacing or 0 local txW = txObj1:getComponent(GConst.TYPEOF_UNITY_CLASS.UI_TEXT_MESH_PRO).preferredWidth txObj1:setSizeDeltaX(txW) local txW2 = txObj2:getComponent(GConst.TYPEOF_UNITY_CLASS.UI_TEXT_MESH_PRO).preferredWidth txObj2:setSizeDeltaX(txW2) local w = (txW2 + txW + spacing) / 2 txObj1:setAnchoredPositionX(txW / 2 - w) txObj2:setAnchoredPositionX(w - txW2 / 2) end function GFunc.expandImgToFitTx(imgObj, txObj, spacing) spacing = spacing or 0 local txW = txObj:getComponent(GConst.TYPEOF_UNITY_CLASS.UI_TEXT_MESH_PRO).preferredWidth txObj:setSizeDeltaX(txW) imgObj:setSizeDeltaX(txW + spacing * 2) end function GFunc.formatAdImg(adImg) if DataManager.MonthlyData:skipAd() then adImg:setSprite(GConst.ATLAS_PATH.COMMON, "common_ad_1") else adImg:setSprite(GConst.ATLAS_PATH.COMMON, "common_ad") end end function GFunc.organizeCfg(cfgId, cfg) local result = {} result.cfgId = cfgId result.cfg = cfg return result end function GFunc.gemEnough(needNum,showToast) -- 钻石是否足够 return GFunc.checkCost(GConst.ItemConst.ITEM_ID_GEM, needNum, showToast) --判断不提示,点击才提示 end ---设置图片和文本居中, 文本需要左右居中对齐 function GFunc.setMiddlePosX(txtObj, icon, bgImg) local txtRectWidth = txtObj:getTransform().rect.width local iconRectWidth = icon:getTransform().rect.width local bgImgRectWidth = bgImg:getTransform().rect.width local halfBgWidth = bgImgRectWidth * 0.5 -- 文本的宽度 local meshPro = txtObj:getComponent(GConst.TYPEOF_UNITY_CLASS.UI_TEXT_MESH_PRO) local width = meshPro.preferredWidth local txtMinWidth = math.max(width, txtRectWidth) -- 以bg中心点为锚点时 -- 文本距离边界的距离 local txtPadding = halfBgWidth - txtMinWidth txtPadding = txtPadding > 0 and txtPadding or 0 -- 图片距离边界距离 local iconPadding = halfBgWidth - iconRectWidth iconPadding = iconPadding > 0 and iconPadding or 0 local maxPadding = math.max(txtPadding, iconPadding) local minPadding = math.min(txtPadding, iconPadding) local offset = (maxPadding - minPadding) * 0.5 if txtPadding > iconPadding then txtObj:setAnchoredPositionX(txtMinWidth * 0.5 + offset) icon:setAnchoredPositionX(-iconRectWidth * 0.5 + offset) else txtObj:setAnchoredPositionX(txtMinWidth * 0.5 - offset) icon:setAnchoredPositionX(-iconRectWidth * 0.5 - offset) end end ---计算最小值 function GFunc.getCalcMinVal(arr) local min = arr[1] for i, v in ipairs(arr) do if min > v then min = v end end return min end ---计算最大值 function GFunc.getCalcMaxVal(arr) local max = arr[1] or 0 for i, v in ipairs(arr) do if max < v then max = v end end return max end function GFunc.getRewardTableByRewardList(rewardList) local newRewards = {} for _, reward in ipairs(rewardList) do table.insert(newRewards, reward) end return newRewards end function GFunc.getRewardTableByReward(reward) return GFunc.getRewardTable(reward.type, reward.id, reward.count) end function GFunc.getRewardTable(type, id, count) if type == GConst.REWARD_TYPE.EQUIP then return GFunc.getServerEquipRewardTable(id, count) end return { type = type, id = id, count = count } end function GFunc.formatRewardsToServerStruct(rewardList) local rewards = {} for _, reward in ipairs(rewardList) do local serverReward = GFunc.getServerRewardTable(reward.type, reward.id, reward.count) table.insert(rewards, serverReward) end return rewards end function GFunc.getServerRewardTable(type, id, count) if type == GConst.REWARD_TYPE.ITEM then return GFunc.getServerItemRewardTable(id, count) end end function GFunc.getServerItemRewardTable(id, count) local reward = { type = GConst.REWARD_TYPE.ITEM, item = { id = id, count = count }, } return reward end function GFunc.getServerRuneRewardTable(id, level) return { type = GConst.REWARD_TYPE.RUNES, rune = { id = id, level = level, }, } end function GFunc.getServerEquipRewardTable(id, level, count) local reward = { type = GConst.REWARD_TYPE.EQUIP, equip = { id = id, level = level, count = count }, } return reward end function GFunc.checkTableValueSame(standardTable, compareTable, debug) if type(standardTable) ~= "table" or type(compareTable) ~= "table" then if debug and standardTable ~= compareTable then Logger.logHighlight(standardTable) end return standardTable == compareTable end for k, v in pairs(standardTable) do local v2 = compareTable[k] if v2 == nil then if debug then Logger.logHighlight(k) end return false end if not GFunc.checkTableValueSame(v, v2, debug) then return false end end return true end function GFunc.showCurrencyFlyAction(rewards, pos) local flyPos = {} if not pos then pos = {x = 0, y = 0} else local sPoint = UIManager:getUICameraComponent():WorldToScreenPoint(pos) pos = CS.BF.Utils.RectTransformScreenPointToLocalPointInRectangle(UIManager:getMainCanvasTransform(), sPoint.x, sPoint.y, UIManager:getUICameraComponent()) end for i, reward in ipairs(rewards) do if reward.type == GConst.REWARD_TYPE.ITEM then local allPos = {} for i = 1, 4 do local posX, posY = GFunc.randomPos(i, pos) allPos[i] = {x = posX, y = posY} end flyPos[reward.item.id] = allPos end end UIManager:showCurrencyAction(flyPos) end function GFunc.getSkillEffectStr(id, lv) local str = I18N:getText("skill", id, "desc") local cfg = ConfigManager:getConfig("skill")[id] local baseNum = cfg.string_num_base local growNum = cfg.string_num_grow local tab = {} for i,v in ipairs(baseNum) do table.insert(tab, baseNum[i] + (lv - 1)*growNum[i]) end local idx = 0 str = string.gsub(str, '{%d+}', function (s) idx = idx + 1 return tostring(tab[idx]) end) return str end function GFunc.goTargetElasticityY(obj, onlyKill, offset, punchY, callBack) if obj.shakeSeq then obj.shakeSeq:Kill() obj.shakeSeq = nil end if onlyKill then return end local curPosY = obj:getAnchoredPositionY() local objTrans = obj:getTransform() obj.shakeSeq = obj:createBindTweenSequence() obj.shakeSeq:Append(objTrans:DOLocalMoveY(curPosY - offset / 2,0.1)) obj.shakeSeq:Append(objTrans:DOLocalMoveY(curPosY + offset * 2 ,0.1)) obj.shakeSeq:Join(objTrans:DOPunchScale({x=0,y=punchY,z = 0},0.2, 6)) obj.shakeSeq:AppendCallback(function() if callBack then callBack() end end) return obj.shakeSeq end function GFunc.goTargetPosXShake(obj, onlyKill, targetX, offset, callBack) if obj.shakeSeq then obj.shakeSeq:Kill() obj.shakeSeq = nil end if onlyKill then return end obj.shakeSeq = obj:createBindTweenSequence() local objTrans = obj:getTransform() local seq = obj.shakeSeq seq:Append(objTrans:DOLocalMoveX(targetX,0.12)) seq:Append(objTrans:DOLocalMoveX(targetX + offset,0.1)) seq:Append(objTrans:DOLocalMoveX(targetX - offset / 3,0.05)) seq:Append(objTrans:DOLocalMoveX(targetX, 0.1)) seq:AppendCallback(function() if callBack then callBack() end end) return obj.shakeSeq end function GFunc.getRewardId(reward) if reward.id_for_nothing then return CS.BF.Utils.GetRewardNumber(reward.id_for_nothing) else return reward.id end end function GFunc.getRewardNum(reward) if reward.num_for_nothing then return CS.BF.Utils.GetRewardNumber(reward.num_for_nothing) else return reward.num or reward.count end end function GFunc.getRewardType(reward) if reward.type_for_nothing then return CS.BF.Utils.GetRewardNumber(reward.type_for_nothing) else return reward.type end end function GFunc.DOBFSliderValue(slider, endValue, duration, snapping) return CS.BF.Utils.DOBFSliderValue(slider, endValue, duration, snapping) end function GFunc.intToString(int) return GConst.INT_TO_STRING[int] or tostring(int) end function GFunc.getTempList() for i = 1, #TEMP_LIST do table.remove(TEMP_LIST) end return TEMP_LIST end function GFunc.recycleTempList() for i = 1, #TEMP_LIST do table.remove(TEMP_LIST) end end function GFunc.getTempMap() for k, v in pairs(TEMP_MAP) do TEMP_MAP[k] = nil end return TEMP_MAP end function GFunc.recycleTempMap() for k, v in pairs(TEMP_MAP) do TEMP_MAP[k] = nil end end --[[ 设置tabLe只速 出现改写会抛出Lua error 用法locaL readOnlyCfg = GFunc.readOnlyTab(cfg) return readOnlyCfg 增加了防重置设置read_onLy的机制 Lua5.3支持 1) table库支持调用元方法,所以table.remove table.insert也会抛出错误, 2)不用定义_ipairs 5.3 ipairs迭代器支持访问元方法__index,pairs迭代器next不支持故需要元方法_pairs 低版本Lua此网数不能完全按照预期工作 ]] function GFunc.readOnlyTab(inputTable) local travelled_tables = {} local function _read_only(tbl) if not travelled_tables[tbl] then local tbl_mt = getmetatable(tbl) if not tbl_mt then tbl_mt = {} setmetatable(tbl, tbl_mt) end local proxy = tbl_mt._read_only__proxy if not proxy then proxy = {} tbl_mt.__read_only_proxy = proxy local proxy_mt = { __index = tbl, __newindex = function (t, k, v) error( "error write to a read-only table with key = " .. tostring(k)) end, __pairs = function (t) return pairs(tbl) end, -- __ipairs = function (t) return ipairs(tbl) end, 5.3版本不需要此方法 _len = function (t) return #tbl end, __read_only_proxy = proxy } setmetatable(proxy, proxy_mt) end travelled_tables[tbl] = proxy for k, v in pairs(tbl) do if type(v) == "table" then tbl[k] = _read_only(v) end end end return travelled_tables[tbl] end return _read_only(inputTable) end return GFunc