1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315 |
- import Gamecfg from "../common/gameCfg";
- import { gameMethod } from "../common/gameMethod";
- import { KindItem, OrderList } from "../common/Xys";
- import Config from "../Config";
- import { ChatEvent } from "../data/const/EventConst";
- import { AudioConst } from "../data/const/TypeConst";
- import GameDataCenter from "../data/GameDataCenter";
- import RollLabel, { RollLabelParam } from "../frameWork/compment/RollLabel";
- import UIHelp from "../logic/ui/UIHelp";
- import { FormulaCom } from "./Formula";
- import GameMath from "./GameMath";
- import { I18n } from "./I18nUtil";
- import ColorAssembler2D from "./LabelColor";
- import Load from "./Load";
- export class BezierData {
- startPos: cc.Vec2;
- c1: cc.Vec2; // 起点的控制点
- c2: cc.Vec2; //终点的控制点
- endPos: cc.Vec2;
- }
- class UICommon {
- // 初始化
- init() { }
- setIconByKindItem(node: cc.Node, item: number[], cb?: (isSucc: boolean) => void) {
- }
- // 给特定的节点加新增一个图片节点
- setNodeChild(node: cc.Node, url: string, x: number = 0, y: number = 0, scale: number = 1) {
- if (node.getChildByName("newImgTemp")) {
- node.getChildByName("newImgTemp").active = true
- return
- }
- let child = new cc.Node()
- child.parent = node
- child.name = "newImgTemp"
- child.x = x
- child.y = y
- child.scale = scale
- Load.loadTexture(child, url)
- }
- /**设置label或富文本的文字 */
- setLabel(node: cc.Node, value: string | number) {
- if (typeof value === 'number') {
- value = value.toString();
- } else if (value == undefined) {
- value = "";
- }
- // 文本和富文本只能二选一
- if (node.getComponent(cc.RichText)) {
- let defaultColor = "#9F90A9"//node.color.toHEX('#rrggbb');
- node.getComponent(cc.RichText).string = `<color=${defaultColor}>${value}</c>`;
- } else {
- node.getComponent(cc.Label).string = value;
- }
- }
- setLibaoLabel(node: cc.Node, orderinfo: OrderList) {
- this.setLabel(node, orderinfo?.desc)
- }
- //获取价格标题
- getLibaoLabel(orderinfo: OrderList) {
- return orderinfo?.desc
- }
- setI18nLangLabel(node: cc.Node, key: string, ...args) {
- let str = I18n.getI18nLang(key, ...args)
- this.setLabel(node, str)
- }
- setI18nTextLabel(node: cc.Node, key: string, ...args: any[]) {
- let str = I18n.getI18nText(key, ...args)
- this.setLabel(node, str)
- }
- /**设置图片富文本,仅支持道具,传入itemList为道具ID,如 [1,2] */
- getImageStr(str: string, itemList: KindItem[] | any[][]): string {
- if (itemList.length == 0) {
- return str
- }
- // itemList.forEach((element, itemIndex) => {
- // let itemCfg = GameDataCenter.item.getItemCfgBase(element)
- // if (itemCfg) {
- // str = str.replace(`{${itemIndex}}`, `<img src='${itemCfg.icon}'/>`)
- // }
- // });
- return str
- }
- // /**设置图片富文本,仅支持道具,传入imageList为图片资源ID,如 [1,2] @TODO 是否能够修改图片尺寸*/
- // setImageRt(node: cc.Node, str: string, imageList: number[] | string[]) {
- // if (imageList.length == 0) {
- // this.setLabel(node, str)
- // return
- // }
- // let index = 0
- // imageList.forEach(element => {
- // Load.getTexture(`item/${element}`, (succ: boolean, asset: cc.SpriteFrame) => {
- // index++
- // console.log("erqasdasasdasd", index, asset)
- // if (succ) {
- // node.getComponent(cc.RichText).imageAtlas["_spriteFrames"][element] = asset
- // }
- // if (index == imageList.length) {
- // console.log("erqasdasasdasd33")
- // imageList.forEach((element, imgIndex) => {
- // // <img src='emoji1'/>
- // str = str.replace(`{${imgIndex}}`, `<img src='${element}'/>`)
- // });
- // node.getComponent(cc.RichText).string = str
- // }
- // })
- // });
- // }
- /**图片、文字 去色,0原色 1去色,递归 */
- setState(node: cc.Node, state: 0 | 1, all: boolean = false) {
- let url = state == 0 ? "2d-sprite" : "2d-gray-sprite"
- if (all) {
- let sprites = node.getComponentsInChildren(cc.Sprite)
- let labels = node.getComponentsInChildren(cc.Label)
- sprites.forEach(sprite => {
- sprite.setMaterial(0, cc.Material.getBuiltinMaterial(url))
- })
- labels.forEach(label => {
- label.setMaterial(0, cc.Material.getBuiltinMaterial(url))
- })
- } else {
- if (node.getComponent(cc.Sprite) != null) {
- node.getComponent(cc.Sprite).setMaterial(0, cc.Material.getBuiltinMaterial(url))
- }
- if (node.getComponent(cc.Label) != null) {
- node.getComponent(cc.Label).setMaterial(0, cc.Material.getBuiltinMaterial(url))
- }
- }
- }
- /** spine动画置灰 */
- setSpineState(node: cc.Node, isGrayed: boolean) {
- if (node.getComponent(sp.Skeleton) != null) {
- if (isGrayed) {
- cc.assetManager.loadBundle('materials', (err, bundle: cc.AssetManager.Bundle) => {
- bundle.load('gray-spine', cc.Material, (err, asset) => {
- node.getComponent(sp.Skeleton).setMaterial(0, asset);
- });
- });
- } else {
- node.getComponent(sp.Skeleton).setMaterial(0, cc.Material.getBuiltinMaterial("2d-spine"));
- }
- };
- }
- /**按钮灰化,只有注册click事件,才会真正被禁用 */
- setBtnGrayState(node: cc.Node, isGray: boolean) {
- let button = node.getComponent(cc.Button);
- if (!button) {
- return;
- }
- button.interactable = !isGray;
- button.enableAutoGrayEffect = isGray;
- }
- /**判断按钮是否为失效状态 */
- isBtnGray(node: cc.Node): boolean {
- let button = node.getComponent(cc.Button);
- if (!button) {
- return false;
- }
- return !button.interactable;
- }
- /**节点注册事件 */
- onRegisterEvent(node: cc.Node, callback, target, params: any = [], audio: AudioConst = AudioConst.effect_click) {
- if (!node) {
- return;
- }
- let cb = callback
- if (callback == null) { return }
- callback = function (event: cc.Event.EventTouch) {
- // 判断下是否有按钮组件,有的话,如果按钮是未激活状态,则不执行回调方法
- let btn = node.getComponent(cc.Button)
- if (btn && btn.interactable == false) {
- return
- }
- cb.bind(target)(event, params)
- GameDataCenter.audio.playEffect(audio)
- event.stopPropagation()
- }
- node.on(cc.Node.EventType.TOUCH_END, callback, target)
- }
- /**节点取消注册事件 */
- unRegisterEvent(node: cc.Node) {
- if (!node) { return }
- node.off(cc.Node.EventType.TOUCH_END);
- }
- /**获取节点的世界坐标 */
- getWorldPos(node: cc.Node): cc.Vec2 {
- return node.convertToWorldSpaceAR(cc.Vec2.ZERO)
- }
- getWorldPosCenter(node: cc.Node): cc.Vec2 {
- let vec = new cc.Vec2(node.width * (0.5 - node.anchorX), node.height * (0.5 - node.anchorY))
- return node.convertToWorldSpaceAR(vec)
- }
- /**设置节点在世界坐标系下的相对坐标 */
- setWorldPos(node: cc.Node, pos: cc.Vec2) {
- let _pos = node.parent.convertToNodeSpaceAR(pos)
- node.x = _pos.x
- node.y = _pos.y
- }
- /**获取node位于target的坐标相对坐标 */
- getPositionInView(node: cc.Node, target: cc.Node): { x: number, y: number } {
- let worldPos = node.parent.convertToWorldSpaceAR(node.position);
- let viewPos = target.convertToNodeSpaceAR(worldPos);
- return viewPos;
- }
- /**通过name从根节点递归获取node */
- getTargetNodeByName(root: cc.Node, name: string) {
- if (root.name == name) {
- return root
- }
- for (let i = 0; i < root.children.length; i++) {
- const child = root.children[i];
- let targetNode = this.getTargetNodeByName(child, name)
- if (targetNode != null) {
- return targetNode
- }
- }
- return null
- }
- // 递归所有子节点并且更新节点分组
- setNodeAllGroups(node: cc.Node, group: string) {
- // 定义一个回调函数,这个函数将对每个节点执行操作
- let myCallback = function (node) {
- // 在这里处理节点
- node.group = group
- };
- // 开始递归遍历
- this.recursiveTraverseChildren(node, myCallback);
- }
- // 递归遍历所有子节点
- recursiveTraverseChildren(node: cc.Node, callback: Function) {
- // 对当前节点执行回调函数
- callback(node);
- // 遍历当前节点的所有子节点
- for (let i = 0; i < node.children.length; i++) {
- // 递归遍历子节点
- this.recursiveTraverseChildren(node.children[i], callback);
- }
- }
- // 安卓设备的适配在主activity中执行
- // ios设备,需要在游戏中修改widget
- // 返回是否为刘海,以及刘海高度
- isLiuhai(): [boolean, number] {
- let isLiuhai = false
- let height = this.getLiuhaiHeight()
- if (cc.sys.os == cc.sys.OS_IOS) {
- let _isLiuhai = jsb.reflection.callStaticMethod('SDKWrapper', 'isLiuhai:', '')
- isLiuhai = _isLiuhai == "1"
- } else if (cc.sys.os == cc.sys.OS_ANDROID) {
- let _isLiuhai = jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "getIsLiuhai", "()Ljava/lang/String;");
- isLiuhai = _isLiuhai == "1"
- }
- return [isLiuhai, height]
- }
- /**获取屏幕高度 */
- getWinHeight() {
- return cc.winSize.height //- this.getLiuhaiHeight()
- }
- getLiuhaiHeight(): number {
- let height = 0
- try {
- if (cc.sys.os == cc.sys.OS_IOS) {
- let _height = jsb.reflection.callStaticMethod('SDKWrapper', 'getLiuhaiHeight:', '');
- height = Number(_height)
- } else if (cc.sys.os == cc.sys.OS_ANDROID) {
- height = jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "getLiuhaiHeight", "()I");
- }
- // return height
- } catch (error) {
- // return height
- }
- return height
- }
- /**获取适配scale */
- getWidghtScale(height: number = cc.winSize.height): number {
- let defaultBili = 1920 / 1080
- let realBili = height / cc.winSize.width //高宽比
- return 1 + (realBili - defaultBili)
- }
- // //将字符转为表情
- // TransformationStr(text) {
- // let richText = "";
- // var arr = text.split("#");
- // for (var i = 0; i < arr.length; i++) {
- // if (i >= 1) {
- // let str = arr[i].slice(0, 5)
- // let str1 = arr[i].slice(5)
- // if (gameMethod.isEmpty(Load.getEmoji(str))) {
- // richText += `#${str + str1}`
- // } else {
- // richText += `<img src='${str}'/>${str1}`
- // }
- // } else {
- // richText += arr[i]
- // }
- // }
- // return richText
- // }
- /**原表富文本模式转换成前端富文本模式*/
- getConversionStr(text: string) {
- let tempStr = ''
- let str = ''
- let arr = text.split('');
- let isColor: boolean = false
- let isValue: boolean = true
- for (let i = 0; i < arr.length; i++) {
- if (arr[i] == '<') {
- tempStr = ''
- isColor = true
- isValue = false
- }
- if (isColor) {
- tempStr += arr[i]
- }
- if (isValue) {
- str += arr[i]
- }
- if (tempStr == '<div fontcolor=') {
- tempStr = '<color=#'
- str += tempStr
- isColor = false
- isValue = true
- }
- if (tempStr == '</div>') {
- tempStr = '</color>'
- str += tempStr
- isColor = false
- isValue = true
- }
- }
- return str
- }
- /**原表成前端*/
- getTypeStr(text: string) {
- let str = text.replace(/<div fontcolor=#/g, '<color=#')
- .replace(/<div fontcolor=/g, '<color=#')
- .replace(/<\/div>/g, '</color>')
- return str
- }
- // getEpsStrArr(eps: XyS.Eps | EpsPet) {
- // let bak: {
- // ek: string,
- // num: number,
- // ekShow: string, //名称
- // numShow: number, //展示数值
- // suffix: string, //后缀
- // }[] = []
- // //遍历配置
- // for (const key in eps) {
- // let arrt = gameCfg.attr.pool[`${key}_`]
- // if (!gameMethod.isEmpty(arrt)) {
- // switch (arrt.tip) {
- // case 'atk'://攻击 角色的物理攻击能力
- // case 'def_p'://物防 角色抵抗物理攻击的能力
- // case 'def_s'://法防 角色抵抗法术攻击的能力
- // case 'hp_max'://生命 角色的生命上限值
- // case 'hp'://生命 角色当前的生命值
- // case 'speed'://速度 决定单位在战斗中的出手频率
- // case 'def'://防御 角色抵抗物理和法术攻击的能力
- // //数值直接展示
- // bak.push({
- // ek: arrt.tip,
- // num: eps[arrt.tip],
- // ekShow: arrt.name, //名称
- // numShow: eps[arrt.tip], //展示数值
- // suffix: '%', //后缀
- // })
- // break;
- // case 'hit_rate'://命中 成功造成伤害的概率
- // case 'dodge_rate'://闪躲 躲避伤害的概率
- // case 'crit_rate'://暴击率 攻击方产生暴击的概率
- // case 'crit_ratio'://暴伤 暴击产生时,伤害的变化比例
- // case 'hit_magic'://控制 增强技能效果命中的比例
- // case 'dodge_magic'://抗控 抵抗技能效果命中的比例
- // case 'tenacity'://抗暴 受击方被暴击概率降低
- // case 'atk_per'://攻击 百分比增加单位的攻击力
- // case 'def_per'://防御 百分比增加单位的物理防御和法术防御
- // case 'hp_max_per'://生命 百分比增加单位的生命上限
- // case 'dam'://伤害加成 千分比增加造成的伤害
- // case 'res'://免伤 千分比减少受到的伤害
- // case 'cure'://治疗 千分比增减治疗别人的效果
- // case 'be_cure'://受疗 千分比增减受到的治疗效果
- // case 'dam_p'://物伤 千分比增加造成的物理伤害
- // case 'dam_s'://法伤 千分比增加造成的法术伤害
- // case 'res_p'://物免 千分比减少受到的物理伤害
- // case 'res_s'://法免 千分比减少受到的法术伤害
- // case 'speed_per'://速度 决定单位在战斗中的出手频率
- // case 'def_p_per'://物防 千分比增加单位的物理防御
- // case 'def_s_per'://法防 千分比增加单位的法术防御
- // case 'toughness'://韧性 千分比减免持续伤害类负面效果带来的伤害
- // //数值百分比加成
- // bak.push({
- // ek: arrt.tip,
- // num: eps[arrt.tip],
- // ekShow: arrt.name, //名称
- // numShow: eps[arrt.tip] / 10, //展示数值
- // suffix: '%', //后缀
- // })
- // break;
- // }
- // }
- // }
- // return bak
- // }
- /** 打字效果 */
- typingAni(label: cc.Label | cc.RichText, text: string, time: number = 1 / 60, cb: Function = () => { }) {
- if (!text || text.length <= 0) {
- cb()
- return
- }
- let html = '';
- let tempStr = ''
- let tempColorStr = ''
- let str: string[] = []
- let arr = text.split('');
- let len = arr.length;
- let step = 0;
- let isColor: boolean = false
- let isValue: boolean = false
- if (label instanceof cc.RichText) {
- for (let i = 0; i < len; i++) {
- if (arr[i] == '<') {
- tempColorStr = ''
- isValue = false
- }
- if (isValue) {
- tempStr = `${tempColorStr}${arr[i]}</color>`
- str.push(tempStr)
- tempStr = ''
- }
- if (arr[i] == '#') {
- isColor = true
- }
- if (arr[i] == '>' && tempColorStr != '') {
- isColor = false
- isValue = true
- tempColorStr = `<color=${tempColorStr}>`
- }
- if (isColor) {
- tempColorStr += arr[i]
- }
- }
- arr = str
- len = str.length
- }
- let typingFunc = () => {
- if (step >= len) {
- label.unschedule(typingFunc);
- cb && cb();
- } else {
- html += arr[step];
- label.string = html
- }
- step++
- }
- label.schedule(typingFunc, time, len)
- }
- /** 富文本打字效果 */
- typingRich(label: cc.RichText, text: string, wordsNum: number, time: number = 1 / 60, cb: Function = () => { }) {
- if (!text || text.length <= 0) {
- cb()
- return
- }
- let str = text;
- let charArr = str.replace(/<.+?\/?>/g, '').split('');
- let tempStrArr = [str],
- curstr = str;
- for (let i = charArr.length; i > 1; i--) {
- let lastIdx = curstr.lastIndexOf(charArr[i - 1]);
- let prevstr = curstr.slice(0, lastIdx);
- let nextstr = curstr.slice(lastIdx + 1, curstr.length);
- if ((i - 1) % wordsNum == 0) tempStrArr.push(prevstr + nextstr);
- curstr = prevstr + nextstr
- }
- let step = 0,
- len = tempStrArr.length;
- let typingFunc = () => {
- if (step >= len) {
- label.unschedule(typingFunc);
- cb && cb();
- } else {
- label.string = tempStrArr.pop()
- }
- step++
- }
- label.schedule(typingFunc, time, len)
- typingFunc()
- }
- // /**
- // * @description:给需要点击回调的RichText添加回调脚本
- // * @param {type} node 包含RichText组件的Node
- // * @param {type} component 需要处理点击事件的脚本
- // * @return {type}
- // */
- // createRichTextCallback(node, component) {
- // if (gameMethod.isEmpty(node)) {
- // console.log("node must be cc.Node!!!");
- // return;
- // }
- // let richText = node.getComponent(cc.RichText);
- // if (gameMethod.isEmpty(richText)) {
- // console.log("node must have RichText component!!!");
- // return;
- // }
- // let st = node.addComponent(RichTextEvent);
- // st.setObject(component);
- // }
- // /**
- // * @description:获取技能buff描述
- // * @param {type} buffId 需要处理点击事件的脚本
- // * @return {type}
- // */
- // getBuffDesc(buffId: string, withTitle: boolean = true): string {
- // let conf = gameCfg.skill_all_buff.getItem(buffId)
- // if (conf == null) {
- // console.log(" buff info is not exist!!!");
- // return ""
- // }
- // if (withTitle) {
- // return `<color=#24B6CB>[${conf.name}]</c>\n${conf.desc}`
- // }
- // return conf.desc
- // }
- //给 spine 重新拷贝一份 skeletonData 数据,让他们不重复
- public copySpine(skeleton: sp.Skeleton) {
- let date = new Date();
- // 记录当前播放的动画
- const animation = skeleton.animation
- const spdata = skeleton.skeletonData;
- let copy = new sp.SkeletonData();
- cc.js.mixin(copy, spdata);
- // @ts-ignore
- copy._uuid = spdata._uuid + "_" + date.getTime() + "_copy";
- let old = copy.name;
- let newName = copy.name + "_copy";
- copy.name = newName;
- copy.atlasText = copy.atlasText.replace(old, newName);
- // @ts-ignore
- copy.textureNames[0] = newName + ".png";
- // @ts-ignore
- copy.init && copy.init();
- skeleton.skeletonData = copy;
- // 继续播放的动画,不然会停止
- skeleton.setAnimation(0, animation, true);
- }
- /**
- * 用外部图片局部换装
- * @param skeleton 骨骼动画
- * @param slotName 需要替换的插槽名称
- * @param texture 外部图片
- */
- public changeSlot(skeleton: sp.Skeleton, slotName: string, texture: cc.Texture2D) {
- if (cc.sys.isBrowser) {
- const slot: sp.spine.Slot = skeleton.findSlot(slotName);
- const attachment: sp.spine.RegionAttachment = slot.getAttachment() as sp.spine.RegionAttachment;
- if (!slot || !attachment) {
- cc.error('updatePartialSkin')
- return;
- }
- // @ts-ignore
- const skeletonTexture = new sp.SkeletonTexture({});
- skeletonTexture.setRealTexture(texture);
- let region: sp.spine.TextureAtlasRegion = attachment.region as sp.spine.TextureAtlasRegion;
- region.u = 0;
- region.v = 0;
- region.u2 = 1;
- region.v2 = 1;
- region.width = texture.width * 5;
- region.height = texture.height * 5;
- region.originalWidth = texture.width * 5;
- region.originalHeight = texture.height * 5;
- region.rotate = false;
- region.texture = skeletonTexture;
- attachment.width = texture.width * 5;
- attachment.height = texture.height * 5;
- attachment.region = region;
- attachment.setRegion && attachment.setRegion(region)
- attachment.updateOffset && attachment.updateOffset();
- // attachment.updateUVs && attachment.updateUVs(attachment);
- slot.setAttachment(attachment);
- } else {
- // @ts-ignore
- const jsbTex = new middleware.Texture2D();
- jsbTex.setPixelsHigh(texture.height * 5);
- jsbTex.setPixelsWide(texture.width * 5);
- jsbTex.setNativeTexture(texture.getImpl());
- // @ts-ignore
- skeleton.updateRegion(slotName, jsbTex);
- }
- // skeleton 如果使用了缓存模式则需要刷新缓存
- skeleton.invalidAnimationCache();
- }
- // 移除所有子节点
- destoryAllChildren(node: cc.Node) {
- node.children.forEach(child => {
- child.destroy()
- })
- }
- // 根据品质获取颜色
- getColorByPz(pinzhi: number | string) {
- // 品质1·8的,9瑶光的自己拼
- switch (Number(pinzhi)) {
- case 1:
- return '#B3B3B3'
- case 2:
- return '#81B58B'
- case 3:
- return '#7CACCF'
- case 4:
- return '#A77CC5'
- case 5:
- return '#E6A76A'
- case 6:
- return '#E7C45A'
- case 7:
- return '#D45F59'
- case 8:
- return '#76DEE4'
- case 9:
- return '#EB91F0'
- case 10:
- return '#FF66D9'
- case 11:
- return '#98F22E'
- case 12:
- return '#FFCC19'
- default:
- return '#FFFFFF'
- }
- }
- // // 根据品质获取颜色
- // setColorTxtByPz(txt:string,pinzhi: number | string) {
- // let color = this.getColorByPz(pinzhi);
- // let str = `[color=${color}]`
- // }
- // 根据品质获取名称
- getNameByPz(pinzhi: number | string) {
- return I18n.getI18nLang(`zhenfa_pinzhi_name_${pinzhi}`);
- }
- getEnoughColor(isenough: boolean) {
- return isenough ? "6fdf89" : "E45849"
- }
- // 修正文字布局
- fixName(msg: string): string {
- // if (msg.length >= 4) {
- // return msg
- // }
- // let out = ""
- // for (let index = 0; index < msg.length; index++) {
- // out += msg[index]
- // // 添加空格
- // if (index + 1 == msg.length) {
- // break
- // }
- // if (msg.length == 2) {
- // out += " "
- // } else if (msg.length == 3) {
- // out += " "
- // }
- // }
- // return out;
- return msg;
- }
- // cocos画布的节点位置信息转化为微信画布位置信息
- getWxBtnPos(node: fgui.GObject): { left: number, top: number, width: number, height: number } {
- let visibleSize = cc.view.getVisibleSize();
- // console.log("==visibleSize==", visibleSize.width, visibleSize.height)
- // console.log("==position==", node.node.position)
- // let worldPos = FormulaCom.getWorldPos(node.node)
- let worldPos = fgui.GRoot.inst.localToGlobal(node.x, node.y)
- // console.log("==fgui worldPos==", fgui.GRoot.inst.localToGlobal(node.x, node.y))
- // console.log("==cc worldPos==", FormulaCom.getWorldPos(node.node))
- //获取系统信息
- let wx_size = wx?.getSystemInfoSync();
- // console.log("==wx_size==", wx_size.screenWidth, wx_size.screenHeight)
- //计算实际大小和可见区域尺寸的比例(这里以宽度为准)
- let size_scale_width = wx_size.screenWidth / visibleSize.width;
- let size_scale_height = wx_size.screenHeight / Config.realHeight;
- //计算创建用户信息按钮需要的属性,考虑锚点
- let offsetX = node.width * node.scaleX * (node.node.anchorX / 1)
- let offsetY = node.height * node.scaleY * ((1 - node.node.anchorY) / 1)
- // console.log("==anchorX==", node.node.anchorX)
- // console.log("==anchorY==", node.node.anchorY)
- // console.log("==offsetX==", offsetX)
- // console.log("==offsetY==", offsetY)
- let left = (worldPos.x - offsetX) * size_scale_width // (this.ui.btnUser.x + visibleSize.width / 2 - this.ui.btnUser.width / 2) * size_scale_width;
- let top = (worldPos.y + node.height / 2) * size_scale_height //fgui
- // let top = wx_size.screenHeight - (worldPos.y - offsetY - Config.safeAreaRect.y / 2 - node.height / 2) * size_scale_height //cc
- let width = node.width * size_scale_width * node.scaleX
- let height = node.height * size_scale_height * node.scaleY
- // let y = (Math.abs(this.ui.btnUser.y) - this.ui.btnUser.height / 2) * size_scale_width;
- // let width = this.ui.btnUser.width * size_scale_width;
- // let height = this.ui.btnUser.height * size_scale_width;
- // console.log("==left==", left)
- // console.log("==top==", top)
- // console.log("==width==", width)
- // console.log("==height==", height)
- return { left: left, top: top, width: width, height: height }
- }
- btnShake(node: cc.Node) {
- let tween = cc.tween(node)
- .delay(2)
- .to(0.05, { angle: -15 })
- .to(0.1, { angle: 15 })
- .to(0.1, { angle: -15 })
- .to(0.1, { angle: 15 })
- .to(0.05, { angle: 0 })
- cc.tween(node).repeatForever(tween).start()
- }
- /**
- * 抛物线飞行 //开始坐标 //中间坐标(高度) //结束坐标
- * p0是起始点
- * p1是中点
- * p2是终点
- * p1通过p2和p0的Xaxis相减获得
- * height是p0加上的高度
- * t 的取值范围是0-1(整个过程的归一化
- */
- paowuxian(parm: {
- node: cc.Node;
- s: { x: number; y: number };
- e: { x: number; y: number };
- h: number;
- tadd?: number; //时间加减速比例 默认100
- cbk?: Function;
- }) {
- //中间点
- let mv2 = cc.v2(parm.s.x + (parm.e.x - parm.s.x) / 2, (parm.s.y + parm.e.y) / 2 + parm.h);
- //设置时间
- let time = Math.sqrt(Math.abs(mv2.y - parm.s.y)) + Math.sqrt(Math.abs(mv2.y - parm.e.y));
- time /= 50;
- if (parm.tadd != null) {
- time = (time * parm.tadd) / 100;
- }
- //起始点
- parm.node.x = parm.s.x;
- parm.node.y = parm.s.y;
- cc.tween(parm.node)
- .bezierTo(time, mv2, mv2, cc.v2(parm.e.x, parm.e.y))
- .call(() => {
- if (parm.cbk != null) {
- parm.cbk();
- }
- })
- .start();
- }
- //抛物线 + 落地弹弹弹
- paowuxian_tan(
- parm: {
- node: cc.Node;
- s: { x: number; y: number };
- e: { x: number; y: number };
- h: number;
- jian: number; //弹的衰减比例 100 不衰减
- tadd?: number; //时间加减速比例 默认100
- cbk?: Function;
- },
- t?: number //当前第几次弹 初次是0 不算弹的
- ) {
- //跳
- this.paowuxian({
- node: parm.node,
- s: parm.s,
- e: parm.e,
- h: parm.h,
- tadd: parm.tadd,
- cbk: () => {
- //第几次弹
- if (t == null) {
- t = 0;
- }
- t += 1;
- //当前衰减比例
- let pers = Math.pow(parm.jian / 100, t);
- if (pers < 0.1) {
- //不再弹了
- if (parm.cbk != null) {
- parm.cbk();
- return;
- }
- }
- //目标
- let _h = parm.h * pers; //跳的高度 衰减
- let _e = {
- x: parm.e.x + (parm.e.x - parm.s.x) * pers, //跳的宽度 衰减
- y: parm.e.y, //水平坐标不变
- };
- //调用自己
- this.paowuxian_tan(
- {
- node: parm.node,
- s: parm.e, //开始 = 上一次的结束
- e: _e,
- h: _h,
- jian: parm.jian,
- tadd: parm.tadd,
- cbk: parm.cbk,
- },
- t
- );
- },
- });
- }
- // 引擎自带的贝塞尔曲线运动
- runBezierAct(actNode: cc.Node, duration: number, bezierDatas: BezierData[]) {
- if (bezierDatas.length <= 0) return
- let tw = cc.tween()
- for (let i = 0; i < bezierDatas.length; ++i) {
- tw.bezierTo(duration, bezierDatas[i].c1, bezierDatas[i].c2, bezierDatas[i].endPos)
- }
- actNode.setPosition(bezierDatas[0].startPos)
- tw.clone(actNode).start()
- }
- // 匀速贝塞尔曲线运动
- runUniformBezierAct(actNode: cc.Node, duration: number, bezierDatas: BezierData[], onComplete?: Function) {
- if (bezierDatas.length <= 0) return
- let tw = cc.tween()
- let allBezierPos: cc.Vec2[] = []
- for (let i = 0; i < bezierDatas.length; ++i) {
- let posArr = [bezierDatas[i].startPos, bezierDatas[i].c1, bezierDatas[i].c2, bezierDatas[i].endPos]
- allBezierPos = allBezierPos.concat(this._caculateBezierPoint(posArr))
- }
- let totalLineLen = this._caculateBezierLength(allBezierPos)
- let speed = totalLineLen / duration
- let isCanBezier = false
- for (let i = 1; i < allBezierPos.length; ++i) {
- let dis = cc.v2(allBezierPos[i].x - allBezierPos[i - 1].x, allBezierPos[i].y - allBezierPos[i - 1].y).len()
- if (dis > 0) {
- // 这里过滤掉两段贝塞尔曲线首位连接的点
- let t = dis / speed
- tw.to(t, { position: allBezierPos[i] })
- .call(() => {
- let angle = FormulaCom.getAngleByPos(allBezierPos[i - 1].x, allBezierPos[i - 1].y, allBezierPos[i].x, allBezierPos[i].y)
- // let angle = FormulaCom.getAngle(allBezierPos[i - 1],allBezierPos[i])
- // console.log("angle = ",angle)
- actNode.angle = angle
- })
- isCanBezier = true
- }
- }
- if (!isCanBezier) {
- console.error("allBezierPos.length == 0")
- return
- }
- actNode.setPosition(allBezierPos[0])
- tw.clone(actNode).call(() => {
- onComplete && onComplete();
- }).start()
- }
- // 计算所有贝塞尔曲线的点
- private _caculateBezierPoint(posArr: cc.Vec2[]) {
- let allBezierPos = []
- let allDis = cc.Vec2.distance(posArr[0], posArr[3])
- let gapCount = Math.ceil(allDis / 10)//距离5像素为一点
- let gap = 1 / gapCount // 每次迭代步长,这个值越小越精细,但是效率越低,这里迭代300次已经够了
- for (let i = 0; i <= 1; i += gap) {
- let pos = this._caculateBezierP(posArr, i)
- allBezierPos.push(pos)
- }
- return allBezierPos
- }
- // 计算贝塞尔曲线的长度
- private _caculateBezierLength(allBezierPos: cc.Vec2[]) {
- let totalLineLen = 0
- for (let i = 1; i < allBezierPos.length; ++i) {
- let dis = cc.v2(allBezierPos[i].x - allBezierPos[i - 1].x, allBezierPos[i].y - allBezierPos[i - 1].y).len()
- totalLineLen += dis
- }
- return totalLineLen
- }
- /**
- * 计算三阶贝塞尔在 t时刻 的位置
- * @param p 三阶贝塞尔的四个点,数组对应为 0起点,1起点控制点,2终点控制点,3终点
- * @param t 传入0-1的值,一个时间的迭代过程
- * @returns
- */
- private _caculateBezierP(p: cc.Vec2[], t: number): cc.Vec2 {
- // 三阶贝塞尔运算
- let bezierP: cc.Vec2 = cc.v2()
- bezierP.x = Math.floor(Math.pow(1 - t, 3) * p[0].x + 3 * t * Math.pow(1 - t, 2) * p[1].x + 3 * Math.pow(t, 2) * (1 - t) * p[2].x + Math.pow(t, 3) * p[3].x);
- bezierP.y = Math.floor(Math.pow(1 - t, 3) * p[0].y + 3 * t * Math.pow(1 - t, 2) * p[1].y + 3 * Math.pow(t, 2) * (1 - t) * p[2].y + Math.pow(t, 3) * p[3].y);
- return bezierP;
- }
- /** 判断隐藏礼包是否开启
- * @param ycgift 隐藏礼包数据
- * @param dc 档次
- * @param buyNum 购买次数
- * @param buyCons 购买金额
- */
- checkYcGiftOpen(tiaojian: number[], buyNum: number, buyCons: number) {
- if (gameMethod.isEmpty(tiaojian)) return false;
- //有配置全局充值金额并且全局充值大于固定金额显示
- if (!gameMethod.isEmpty(tiaojian[2]) && GameDataCenter.sevBack?.userInfo?.a?.iscz >= tiaojian[2]) { return true; }
- // 隐藏礼包条件判断
- if (tiaojian[0] > 0 && tiaojian[1] <= 0) {
- // 第一种 只判断次数
- if (buyNum >= tiaojian[0]) { return true; }
- } else if (tiaojian[0] <= 0 && tiaojian[1] > 0) {
- // 第二种 只判断金额
- if (buyCons >= tiaojian[1]) { return true; }
- } else if (tiaojian[0] > 0 && tiaojian[1] > 0) {
- // 第三种 判断次数和金额 满足一种
- if (buyNum >= tiaojian[0] || buyCons >= tiaojian[1]) { return true; }
- }
- return false;
- }
- // 获取属性名跟值 *传入值 "atk":10 返回 [攻击, 10]
- getEpsNameValue(key: string, value: number): string[] {
- let epsCfg = Gamecfg.userEp.getItem(key);
- value = value ? value : 0;
- if (gameMethod.isEmpty(epsCfg)) {
- // console.log('配置错误===', key)
- return [key, value + ""];
- }
- // return [this.fixName(epsCfg.name), (epsCfg.isPer ? `${value / 100}%` : value + "") || "0"];
- return [this.fixName(I18n.getUserEpName(epsCfg.key)), epsCfg.isPer ? `${value / 100}%` : value + ""]
- }
- /**
- * UI节点转换到目标节点下的坐标
- * @param node 节点
- * @param targetNode 目标节点
- * @returns {转换后的坐标的点|Point}
- */
- transPos(node: cc.Node, targetNode: cc.Node): cc.Vec2 {
- //转世界坐标
- var endGlobalPos = this.getWorldPos(node);
- if (!endGlobalPos) return null;
- //再转局部坐标
- var endPos = targetNode.convertToNodeSpaceAR(endGlobalPos);
- return endPos;
- }
- // 剪贴板复制功能
- public webCopyString(str: string) {
- // console.log('复制ing');
- var input = str + '';
- const el = document.createElement('textarea');
- el.value = input;
- el.setAttribute('readonly', '');
- // el.style.contain = 'strict';
- el.style.position = 'absolute';
- el.style.left = '-9999px';
- el.style.fontSize = '12pt'; // Prevent zooming on iOS
- const selection = getSelection();
- var originalRange = null;
- if (selection.rangeCount > 0) {
- originalRange = selection.getRangeAt(0);
- }
- document.body.appendChild(el);
- el.select();
- el.selectionStart = 0;
- el.selectionEnd = input.length;
- var success = false;
- try {
- success = document.execCommand('copy');
- } catch (err) { }
- document.body.removeChild(el);
- if (originalRange) {
- selection.removeAllRanges();
- selection.addRange(originalRange);
- }
- if (success) {
- UIHelp.ShowTips(I18n.getI18nText('common_copy_sucess'));
- } else {
- UIHelp.ShowTips(I18n.getI18nText('common_copy_fail'));
- }
- return success;
- }
- /**
- * 设置滚动变化的数字文本,不要再任何虚拟列表内使用
- * @param obj 需要控制的文本组件
- * @param num 变化的目标数字
- * @param cb 实时变化的数字值,自己在内部写需要执行和改变的文本(如果不传则直接对obj.text或这obj.title赋值
- * @param param 参数
- */
- SetLabelRoll(obj: fairygui.GTextField | fairygui.GLabel | fairygui.GRichTextField, num: number, cb: (val: number) => void = null, param: RollLabelParam = null) {
- let rolllabel = obj.node.getComponent(RollLabel)
- if (rolllabel == null) {
- rolllabel = obj.node.addComponent(RollLabel)
- rolllabel.obj = obj
- }
- rolllabel.setData(num, cb, param)
- }
- /**
- * 上漂文本
- * @param func 改变文本图标的方法
- * @param node 位置节点定位用
- * @param view 挂载上漂节点用的页面
- * @param cache 缓存
- * @param randomX
- * @param randomY
- * @param pac
- * @param popItem
- */
- PopTips(func: (obj: fairygui.GLabel) => void, node: fairygui.GComponent, view: fairygui.GComponent, cache: PopTipsCache[], randomX: number[] | number = null, randomY: number[] | number = null, pac: string = "Common", popItem: string = "PopTips") {
- let data: PopTipsCache = null
- for (let i of cache) {
- if (i.obj.visible == false) {
- data = i
- break
- }
- }
- if (data == null) {
- let obj = fgui.UIPackage.createObject(pac, popItem) as fairygui.GLabel
- view.addChild(obj)
- data = new PopTipsCache(obj)
- cache.push(data)
- }
- if (typeof randomX == "number") {
- data.obj.x = node.x + randomX
- } else if (randomX) {
- let left = randomX[0]
- let right = randomX[1]
- let randomposx = GameMath.getRandomNum(left, right)
- data.obj.x = node.x + randomposx
- } else {
- data.obj.x = node.x
- }
- if (typeof randomY == "number") {
- data.obj.y = node.y + randomY
- } else if (randomY) {
- let left = randomY[0]
- let right = randomY[1]
- let randomposy = GameMath.getRandomNum(left, right)
- data.obj.y = node.y + randomposy
- } else {
- data.obj.y = node.y
- }
- func(data.obj)
- data.startTween()
- }
- /** 数字转中文 */
- NumToChinese(num) {
- if (num < 0 || num > 100) {
- return "输入的数字必须在0到100之间";
- }
- const units = ['', '十', '百', '千']; // 可以根据需要扩展
- const chineseNums = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
- let str = '';
- let digit;
- // 处理个位数
- digit = num % 10;
- if (digit !== 0) {
- str = chineseNums[digit];
- }
- // 处理十位数
- num = Math.floor(num / 10);
- if (num !== 0) {
- if (num == 1) {
- str = '十' + str;
- } else {
- str = chineseNums[num] + '十' + str;
- }
- }
- // 如果需要处理更大的数字,可以继续添加逻辑
- // 移除开头的'零'
- str = str.replace(/^零+/, '');
- if (str === '') {
- str = '零';
- }
- return str;
- }
- /** 圆上指定角度一点 */
- GetPointOnCircle(radius: number, degree: number, center: cc.Vec2): cc.Vec2 {
- let angle = this.DegreeToAngle(degree);
- // 使用三角函数计算圆上该角度对应的点的x和y坐标
- const x = center.x + radius * Math.cos(angle);
- const y = center.y + radius * Math.sin(angle);
- // 返回该点的坐标
- return cc.v2(x, y);
- }
- /** 圆上任意一点 */
- GetRandomPointOnCircle(radius: number, centerX = 0, centerY = 0): cc.Vec2 {
- // 生成一个0到2π之间的随机角度(弧度)
- const angle = Math.random() * 2 * Math.PI;
- // 使用三角函数计算圆上该角度对应的点的x和y坐标
- const x = centerX + radius * Math.cos(angle);
- const y = centerY + radius * Math.sin(angle);
- // 返回该点的坐标
- return cc.v2(x, y);
- }
- /** 圆上角度范围一点 */
- GetRandomPointOnAngle(radius: number, rangeAngle: number, center: cc.Vec2, point: cc.Vec2): cc.Vec2 {
- // 生成一个0到2π之间的随机角度(弧度)
- // const angle = Math.random() * 2 * Math.PI;
- const dx = point.x - center.x;
- const dy = point.y - center.y;
- const angleRadians = Math.atan2(dy, dx);
- let angle = this.AngleToDegree(angleRadians);
- let newAngle = GameMath.getRandomNum(rangeAngle, rangeAngle * 2) - rangeAngle;
- angle += newAngle;
- let degree = this.DegreeToAngle(angle);
- // 使用三角函数计算圆上该角度对应的点的x和y坐标
- const x = center.x + radius * Math.cos(degree);
- const y = center.y + radius * Math.sin(degree);
- // 返回该点的坐标
- return cc.v2(x, y);
- }
- /** 圆上指定角度一点 */
- GetCirclePointOnAngle(radius: number, diffAngle: number, center: cc.Vec2, point: cc.Vec2): cc.Vec2 {
- // 生成一个0到2π之间的随机角度(弧度)
- // const angle = Math.random() * 2 * Math.PI;
- const dx = point.x - center.x;
- const dy = point.y - center.y;
- const angleRadians = Math.atan2(dy, dx);
- let angle = this.AngleToDegree(angleRadians);
- let degree = angle + diffAngle;
- let newAngle = this.DegreeToAngle(degree);
- // 使用三角函数计算圆上该角度对应的点的x和y坐标
- const x = center.x + radius * Math.cos(newAngle);
- const y = center.y + radius * Math.sin(newAngle);
- // 返回该点的坐标
- return cc.v2(x, y);
- }
- /** 圆上分割角度后的坐标点 */
- GetCirclePointDivideAngle(radius: number, divideCount: number, center: cc.Vec2): cc.Vec2[] {
- // 生成一个0到2π之间的随机角度(弧度)
- let per = divideCount / divideCount;
- let posArr = [];
- for (let i = 0; i < divideCount; i++) {
- let degree = per * i;
- // 使用三角函数计算圆上该角度对应的点的x和y坐标
- const x = center.x + radius * Math.cos(degree);
- const y = center.y + radius * Math.sin(degree);
- posArr.push(cc.v2(x, y))
- }
- return posArr;
- }
- /** 圆上指定弧长的点 */
- GetCircleAngleLenPoint(radius: number, len: number, center: cc.Vec2, point: cc.Vec2, index: number): cc.Vec2 {
- const dx = point.x - center.x;
- const dy = point.y - center.y;
- const angleRadians = Math.atan2(dy, dx);
- let degree = this.AngleToDegree(angleRadians);
- let totalLen = 2 * Math.PI * radius;
- let needDegree = len / totalLen * 360;//弧长对应角度
- let newDegree = degree + index * needDegree;
- let newAngle = this.DegreeToAngle(newDegree);
- // 使用三角函数计算圆上该角度对应的点的x和y坐标
- const x = center.x + radius * Math.cos(newAngle);
- const y = center.y + radius * Math.sin(newAngle);
- // 返回该点的坐标
- return cc.v2(x, y);
- }
- /** 弧度转角度 */
- public AngleToDegree(angleRadians) {
- const angleDegrees = angleRadians * (180 / Math.PI);
- return angleDegrees
- }
- /** 角度转弧度 */
- public DegreeToAngle(degree: number) {
- const angle = degree / (180 / Math.PI);
- return angle;
- }
- /** 获取两点角度 */
- public GetTwoPointAngle(center: cc.Vec2, point: cc.Vec2) {
- const dx = point.x - center.x;
- const dy = point.y - center.y;
- const angleRadians = Math.atan2(dy, dx);
- let angle = this.AngleToDegree(angleRadians);
- return angle;
- }
- /** 求多个点的中心点 */
- public CalculateCentroid(points: cc.Vec2[]): cc.Vec2 {
- // 初始化x和y的总和
- let sumX = 0;
- let sumY = 0;
- // 遍历所有点,累加x和y的坐标
- points.forEach(point => {
- sumX += point.x;
- sumY += point.y;
- });
- // 计算平均x和y坐标
- let centroidX = sumX / points.length;
- let centroidY = sumY / points.length;
- // 返回中心点坐标
- return cc.v2(centroidX, centroidY);
- }
- }
- export class PopTipsCache {
- obj: fairygui.GLabel
- tween1: cc.Tween;
- tween2: cc.Tween;
- constructor(obj: fairygui.GLabel) {
- this.obj = obj
- }
- startTween() {
- this.obj.alpha = 0
- this.obj.visible = true
- let y = this.obj.y - 120;
- this.tween1 = cc.tween(this.obj).to(1, {
- y: y,
- }).call(() => {
- this.obj.visible = false
- })
- this.tween2 = cc.tween(this.obj).to(0.2, {
- alpha: 1,
- }).delay(0.6).to(0.2, {
- alpha: 0,
- })
- this.tween1.start()
- this.tween2.start()
- }
- clearTween() {
- this.tween1?.stop()
- this.tween2?.stop()
- this.obj.visible = false;
- }
- }
- export let uiCommon = new UICommon()
|