123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752 |
- import {
- Prefab,
- resources,
- Node,
- find,
- instantiate,
- Vec3,
- log,
- Component,
- Button,
- warn,
- Asset,
- error,
- v2,
- UITransform,
- tween,
- v3,
- Vec2,
- director,
- ImageAsset,
- assetManager,
- } from "cc";
- import BigNumber from "./BigNumber";
- import { EDITOR } from "cc/env";
- import { LanguageManager } from "./LanguageManager";
- import PoolMgr from "./PoolMgr";
- import BaseUI from "../base/BaseUI";
- import { Tips } from "../mgr/Tips";
- import DisplayNumber from "./DisplayNumber";
- export enum EFLY_TYPE {
- 金币,
- 体力,
- 钻石,
- }
- export default class Utils {
- public static copyText(text: string) {
- navigator.clipboard.writeText(text).then(
- (res) => {
- console.log(" writeText success: ", res);
- // Tips.show(Utils.setI18nLabel("Share.LinkCopied"));
- },
- (err) => {
- console.log(" writeText error: ", err);
- this.copyTextFallback(text);
- }
- );
- }
- private static copyTextFallback(text) {
- const textArea = document.createElement("textarea");
- textArea.value = text;
- document.body.appendChild(textArea);
- textArea.select();
- try {
- document.execCommand("copy");
- Tips.show(Utils.setI18nLabel("Share.LinkCopied")); //"Link copied!");
- } catch (err) {
- Tips.show(Utils.setI18nLabel("Share.Title1"));
- }
- document.body.removeChild(textArea);
- }
- static sleep(ms: number) {
- return new Promise((resolve) => setTimeout(resolve, ms));
- }
- static padNumber(num, length): string {
- let str = num.toString();
- while (str.length < length) {
- str = "0" + str;
- }
- return str;
- }
- static log(o: any) {
- if ("1" == this.getQueryString("log")) {
- console.log(o);
- }
- }
- // 创建UI
- static createUI(
- filepath: string,
- parent: Node = null,
- callback: Function = null
- ): Promise<Node> {
- return new Promise((resolve, reject) => {
- resources.load(filepath, Prefab, (err, ret) => {
- log("加载UI:" + filepath);
- if (err) {
- console.error(err);
- reject();
- return;
- }
- if (parent == null) {
- parent = find("Canvas/popupNode");
- }
- let index = filepath.lastIndexOf("/");
- let name = filepath.substr(index + 1, filepath.length - index);
- if (parent.getComponentInChildren(name)) {
- console.log("重复UI跳过");
- return;
- }
- var tmp: Node = instantiate(ret);
- tmp.parent = parent;
- if (callback) callback(tmp);
- resolve(tmp);
- });
- });
- }
- // 创建预制体
- static createPrefab(
- filepath: string,
- parent: Node = null,
- callback: Function = null,
- pos: Vec3 = null
- ) {
- return new Promise((resolve, reject) => {
- resources.load(filepath, Prefab, (err, ret) => {
- if (err) {
- console.error(err);
- reject();
- return;
- }
- if (parent == null) {
- parent = find("Canvas");
- }
- var tmp: Node = instantiate(ret);
- // tmp.opacity = 0;
- // tmp.runAction(
- // sequence(
- // delayTime(0.01),
- // callFunc(() => {
- // tmp.opacity = 255;
- // })
- // )
- // );
- tmp.parent = parent;
- if (pos) {
- tmp.position = pos;
- }
- if (callback) callback(tmp);
- resolve(tmp);
- });
- });
- }
- // 获取随机数
- public static getRandom(lower, upper): number {
- return Math.random() * (upper - lower) + lower;
- }
- // 获取随机整数
- public static getRandomInt(lower, upper): number {
- return Math.floor(Math.random() * (upper - lower)) + lower;
- }
- // 获取随机整数
- public static seedRandomInt(lower, upper): number {
- return Utils.getRandomInt(lower, upper);
- }
- // 格式化数字
- public static formatNumber(num: number, afterdot: number = 2): string {
- num = Number(num);
- num = Number(num.toFixed(afterdot));
- if (num < 1000) {
- return num.toString();
- }
- return DisplayNumber.displayNumber(num,afterdot);
-
- // return BigNumber.getLargeString(num);
- }
- public static getPowNum(p) {
- return Math.pow(10, p);
- }
- // 设置服务器时间
- public static setServerTime(time: number) {
- Utils.timeOffset = time - new Date().getTime();
- }
- // 获取服务器时间
- public static timeOffset: number = 0;
- public static getServerTime() {
- return new Date().getTime() + Utils.timeOffset;
- }
- // 添加点击事件
- public static addClickEvent(
- node,
- target,
- component,
- handler,
- customEventData
- ) {
- var eventHandler = new Component.EventHandler();
- eventHandler.target = target;
- eventHandler.component = component;
- eventHandler.handler = handler;
- if (customEventData) eventHandler.customEventData = customEventData;
- var clickEvents = node.getComponent(Button).clickEvents;
- if (clickEvents.length > 0) {
- // if (!EDITOR) warn("按钮已经存在绑定,跳过自动绑定", node.name);
- return;
- }
- console.log(node.name, target.name, component);
- clickEvents.push(eventHandler);
- }
- public static secondsToDHMS(seconds) {
- if (seconds <= 0) {
- return `00d 00h:00m:00s`;
- }
- const days = Math.floor(seconds / (24 * 3600));
- let d = days < 9 ? "0" + days : days;
- const hours = Math.floor((seconds % (24 * 3600)) / 3600);
- let h = hours < 9 ? "0" + hours : hours;
- const minutes = Math.floor((seconds % 3600) / 60);
- let min = minutes < 9 ? "0" + minutes : minutes;
- const second = Math.floor(seconds % 60);
- let s = second < 9 ? "0" + second : second;
- let str = days > 0 ? `${d}d ${h}h:${min}m:${s}s` : `${h}h:${min}m:${s}s`;
- return str;
- }
- public static formatTimestamp(timestamp) {}
- // 秒转换为时分秒
- public static getToTimeByS(second: number) {
- const totalSeconds = Math.floor(second);
- const hours = Math.floor(totalSeconds / 3600) % 24;
- const minutes = Math.floor((totalSeconds % 3600) / 60);
- const seconds = totalSeconds % 60;
- return [hours, minutes, seconds]
- .map((unit) => (unit < 10 ? "0" + unit : unit.toString())) // 确保每个部分都是两位数
- .join(":"); // 拼接为字符串
- }
- private static padStartCustom(str, targetLength, padString) {
- str = String(str);
- padString = String(padString);
- if (str.length >= targetLength) {
- return str;
- }
- targetLength -= str.length;
- if (targetLength > padString.length) {
- padString = padString.repeat(Math.ceil(targetLength / padString.length));
- }
- return padString.slice(0, targetLength) + str;
- }
- public static formateDateRemaining(targetTimestamp: number) {
- const now = Utils.getServerTime();
- const remainingTime = targetTimestamp - now;
- const days = Math.floor(remainingTime / (1000 * 60 * 60 * 24));
- const hours = Math.floor(
- (remainingTime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
- );
- const minutes = Math.floor(
- (remainingTime % (1000 * 60 * 60)) / (1000 * 60)
- );
- const seconds = Math.floor((remainingTime % (1000 * 60)) / 1000);
- const dStr = days < 10 ? "0" + days : days;
- const hStr = hours < 10 ? "0" + hours : hours;
- const mStr = minutes < 10 ? "0" + minutes : minutes;
- const sStr = seconds < 10 ? "0" + seconds : seconds;
- return `${dStr}d ${hStr}h:${mStr}m:${sStr}s`;
- }
- public static formatTimeRemaining(targetTimestamp) {
- // 获取当前时间戳
- const now = Date.now();
- // 计算剩余时间的毫秒数
- let remainingTime = targetTimestamp - now;
- // 如果剩余时间小于等于 0,表示目标时间已经过去
- if (remainingTime <= 0) {
- return "00:00:00";
- }
- // 计算小时、分钟、秒
- const hours = Math.floor(remainingTime / (1000 * 60 * 60));
- remainingTime -= hours * 1000 * 60 * 60;
- const minutes = Math.floor(remainingTime / (1000 * 60));
- remainingTime -= minutes * 1000 * 60;
- const seconds = Math.floor(remainingTime / 1000);
- // 格式化为两位数的字符串
- const formattedHours = Utils.padStartCustom(hours, 2, "0");
- const formattedMinutes = Utils.padStartCustom(minutes, 2, "0");
- const formattedSeconds = Utils.padStartCustom(seconds, 2, "0");
- return `${formattedHours}:${formattedMinutes}:${formattedSeconds}`;
- }
- // 秒转换为时分秒
- public static getTimeStrByS(second: number) {
- second = Math.floor(second);
- if (second < 0) second = 0;
- var d = Math.floor(second / 3600 / 24);
- second -= d * 3600 * 24;
- var h = Math.floor(second / 3600);
- second -= h * 3600;
- var m = Math.floor(second / 60);
- second -= m * 60;
- var front = "00";
- if (h > 9) {
- front = "" + h;
- } else {
- front = "0" + h;
- }
- var mid = "00";
- if (m > 9) {
- mid = "" + m;
- } else {
- mid = "0" + m;
- }
- var back = "00";
- if (second > 9) {
- back = "" + second;
- } else {
- back = "0" + second;
- }
- if (d > 0) {
- return d + ":" + h + ":" + m;
- } else {
- var longTime = h > 0;
- if (longTime) {
- return front + ":" + mid;
- } else {
- return mid + ":" + back; //+ '秒';
- }
- }
- }
- public static formattedDate(timestamp) {
- const date = new Date(Number(timestamp));
- // 获取年月日
- const year = date.getFullYear();
- let month = date.getMonth() + 1;
- let monthS = month < 9 ? "0" + month : month;
- let day = date.getDate();
- let dayS = day < 9 ? "0" + day : day;
- const hours = date.getHours();
- let hoursS = hours < 9 ? "0" + hours : hours;
- const minutes = date.getMinutes();
- let minutesS = minutes < 9 ? "0" + minutes : minutes;
- const seconds = date.getSeconds();
- let secondsS = seconds < 9 ? "0" + seconds : seconds;
- const formattedDate = `${year}-${monthS}-${dayS} ${hoursS}:${minutesS}:${secondsS}`;
- return formattedDate;
- }
- public static formattedOnlyDate(timestamp) {
- const date = new Date(Number(timestamp));
- // 获取年月日
- const year = date.getFullYear();
- let month = date.getMonth() + 1;
- let monthS = month < 9 ? "0" + month : month;
- let day = date.getDate();
- let dayS = day < 9 ? "0" + day : day;
-
- const formattedDate = `${year}-${monthS}-${dayS}`;
- return formattedDate;
- }
- // 格式化金币
- public static formatCoin(num: number) {
- num = Math.floor(num);
- return BigNumber.getLargeString(num);
- }
- // 加载资源
- public static loadRes(path: string, type: typeof Asset): Promise<Asset> {
- return new Promise((resolve, reject) => {
- resources.load(path, type, (err, ret) => {
- if (err) {
- error(path, err);
- reject(null);
- } else {
- resolve(ret);
- }
- });
- });
- }
- public static loadRemote(path: string, type: typeof ImageAsset) {
- return new Promise((resolve, reject) => {
- assetManager.loadRemote(path, type, (err, ret) => {
- if (err) {
- error(path, err);
- reject(null);
- } else {
- resolve(ret);
- }
- });
- });
- }
- // 权重
- public static weight(v: number[]): number {
- var mTotalWeight = 0;
- for (var i = 0; i < v.length; ++i) {
- mTotalWeight += v[i];
- }
- if (mTotalWeight <= 0) return -1;
- var randnum = Math.round(Math.random() * Number.MAX_VALUE) % mTotalWeight;
- for (var i = 0; i < v.length; ++i) {
- if (randnum < v[i]) {
- return i;
- } else {
- randnum -= v[i];
- }
- }
- return -1;
- }
- //定点数
- public static fixFloat(val: number, count: number = 2) {
- var a = count * 100;
- return Math.floor(val * a) / a;
- }
- // 在子节点中查找
- private static _findInChildren(node: Node, name: string): Node {
- var x = node.getChildByName(name);
- if (x) return x;
- if (node.children.length == 0) return null;
- for (var i = 0; i < node.children.length; ++i) {
- var tmp = this._findInChildren(node.children[i], name);
- if (tmp) return tmp;
- }
- return null;
- }
- // 飞动动画
- public static flyAnim(
- type: number,
- startNode: Node,
- targetNodeName: string,
- count: number,
- radius: number,
- callback: Function
- ) {
- let srcNode = this._findInChildren(director.getScene(), targetNodeName);
- if (!srcNode) {
- notPlay = false;
- callback();
- return;
- }
- let getPoint = (r, ox, oy, count) => {
- var point = []; //结果
- var radians = (Math.PI / 180) * Math.round(360 / count), //弧度
- i = 0;
- for (; i < count; i++) {
- var x = ox + r * Math.sin(radians * i),
- y = oy + r * Math.cos(radians * i);
- point.unshift(v2(x, y)); //为保持数据顺时针
- }
- return point;
- };
- let createNode = (type) => {
- if (type == 0) return PoolMgr.Instance().get("Coin");
- if (type == 1) return PoolMgr.Instance().get("Gem");
- if (type == 2) return PoolMgr.Instance().get("Zp");
- if (type == 3) return PoolMgr.Instance().get("ZpGold");
- };
- let start = startNode.parent
- .getComponent(UITransform)
- .convertToWorldSpaceAR(startNode.position);
- start = find("Canvas/flyNode")
- .getComponent(UITransform)
- .convertToNodeSpaceAR(start);
- var array = getPoint(radius, start.x, start.y, count);
- var nodeArray = new Array();
- for (var i = 0; i < array.length; i++) {
- var gold = createNode(type);
- gold.parent = find("Canvas/flyNode");
- var randPos = v2(
- array[i].x + Utils.getRandomInt(0, 50),
- array[i].y + Utils.getRandomInt(0, 50)
- );
- gold.setPosition(start);
- nodeArray.push({ gold, randPos });
- }
- var notPlay = false;
- let dstPos = srcNode.parent
- .getComponent(UITransform)
- .convertToWorldSpaceAR(srcNode.position);
- dstPos = find("Canvas/flyNode")
- .getComponent(UITransform)
- .convertToNodeSpaceAR(dstPos);
- var targetGoldNode = srcNode;
- for (var i = 0; i < nodeArray.length; i++) {
- var pos = nodeArray[i].randPos;
- var node = nodeArray[i].gold;
- nodeArray[i].gold.id = i;
- tween(node)
- .to(0.2, { position: pos })
- .delay(i * 0.03)
- .to(0.5, { position: v2(dstPos.x, dstPos.y) })
- .call(() => {
- if (!notPlay) {
- targetGoldNode.scale = v3(1, 1, 1);
- notPlay = true;
- tween(targetGoldNode)
- .to(0.1, { scale: v3(2, 2, 2) })
- .to(0.1, { scale: v3(1, 1, 1) })
- .call(() => {
- notPlay = false;
- });
- }
- callback(node._id == nodeArray.length - 1);
- PoolMgr.Instance().put(node.name, node);
- if (node._id == nodeArray.length - 1) {
- find("Canvas/flyNode").removeAllChildren();
- }
- })
- .start();
- }
- }
- /**
- * 深度复制
- * @param value
- */
- public static deepClone(value: any) {
- // 处理基本数据类型和特殊情况
- if (value === null || typeof value !== "object") {
- return value; // 基本数据类型和 null
- }
- // 处理数组
- if (Array.isArray(value)) {
- return value.map((item) => Utils.deepClone(item)); // 递归拷贝每个元素
- }
- // 处理对象
- const copy = {};
- for (const key in value) {
- if (value.hasOwnProperty(key)) {
- copy[key] = Utils.deepClone(value[key]); // 递归拷贝每个属性
- }
- }
- return copy;
- }
- /**
- * 获取url参数
- * @param name
- * @returns
- */
- public static getQueryString(name: any) {
- var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
- var r = window.location.search.substr(1).match(reg);
- if (r != null) return unescape(r[2]);
- return null;
- }
- /**
- * 贝塞尔曲线计算
- * @param points
- * @param t
- */
- public static calculateBezier(points: Vec2[], t: number) {
- const n = points.length;
- if (n === 0) return v2(0, 0); // 如果没有控制点,返回 (0,0)
- if (n === 1) return points[0]; // 如果只有一个控制点,返回该点
- let tempPoints = points.slice(); // 创建控制点的副本
- // De Casteljau's algorithm
- for (let r = 1; r < n; r++) {
- for (let i = 0; i < n - r; i++) {
- tempPoints[i] = v2(
- (1 - t) * tempPoints[i].x + t * tempPoints[i + 1].x,
- (1 - t) * tempPoints[i].y + t * tempPoints[i + 1].y
- );
- }
- }
- return tempPoints[0]; // 返回计算得到的点
- }
- /**
- * 是否为某个链接
- * @param url
- * @param hostname
- * @returns
- */
- static isNameLink(url: string | URL, hostname: string) {
- try {
- const parsedUrl = new URL(url);
- return parsedUrl.hostname === hostname;
- } catch (e) {
- console.error("Invalid URL");
- return false;
- }
- }
- // 将用户 ID 转换为 26 进制字符串
- public static convertTo26(userId) {
- let sb = "";
- while (userId > 0) {
- userId--;
- let ch = String.fromCharCode((userId % 26) + "A".charCodeAt(0));
- sb = ch + sb;
- userId = Math.floor(userId / 26);
- }
- return sb;
- }
- // 生成邀请代码
- public static generateInviteCode(channelId, userId) {
- return channelId + this.convertTo26(userId);
- }
- // 取后缀
- public static getSuffix(idx) {
- idx = Math.floor(idx);
- if (idx <= 0) {
- return "";
- }
- idx = idx - 1;
- let result = "";
- while (idx >= 0) {
- result = String.fromCharCode((idx % 26) + 97) + result;
- idx = Math.floor(idx / 26) - 1;
- }
- result = "";
- return result;
- }
- // max: 10 ==> 1->1,2->2,..10->10,11->1
- public static getMappedValue(idx, max) {
- let result;
- result = idx % max == 0 ? max : idx % max;
- return result;
- }
- //
- public static getStarValue(idx, max) {
- let result = Math.floor((idx - 1) / max);
- return result;
- }
- // 格式化地址
- static formAddress(address: string) {
- if (
- address == null ||
- address == "" ||
- address == undefined ||
- address.length < 10
- ) {
- return " ";
- }
- return (
- address.substring(0, 8) +
- "..." +
- address.substring(address.length - 8, address.length)
- );
- }
- //
- public static updateLabelText(fullText, maxWidth, fontSize) {
- let str = "";
- // 计算文本的实际宽度
- let textWidth = this.getTextWidth(fullText, fontSize);
- if (textWidth > maxWidth) {
- // 超过最大宽度,显示截断后的文本并加上省略号
- let truncatedText = this.truncateText(fullText, maxWidth, fontSize);
- str = truncatedText + "...";
- } else {
- // 显示完整文本
- str = fullText;
- }
- return str;
- }
- // 获取文本的宽度
- private static getTextWidth(text, fontSize) {
- let canvas = document.createElement("canvas");
- let ctx = canvas.getContext("2d");
- ctx.font = fontSize + "px Arial"; // 设置字体大小
- return ctx.measureText(text).width;
- }
- // 截断文本并返回适合的文本
- private static truncateText(text, maxWidth, fontSize) {
- let i = 0;
- let truncatedText = text;
- // 循环截取字符直到文本超出最大宽度
- while (
- this.getTextWidth(truncatedText, fontSize) > maxWidth &&
- i < text.length
- ) {
- i++;
- truncatedText = text.slice(0, text.length - i);
- }
- return truncatedText;
- }
- // 多语言
- static setI18nLabel(str: string, value?: string, value2?: string) {
- let i18nStr = str;
- i18nStr = LanguageManager.getText(str);
- if (value) {
- i18nStr = i18nStr.replace("{value}", value);
- }
- if (value2) {
- i18nStr = i18nStr.replace("{value2}", value2);
- }
- return i18nStr;
- }
- }
|