|
@@ -1,1210 +0,0 @@
|
|
-import { UITransform, Vec2, Vec3,Node,screen, _decorator, find, director, Color, UIOpacity, tween, Label } from "cc";
|
|
|
|
-const { ccclass, property } = _decorator;
|
|
|
|
-
|
|
|
|
-@ccclass("utils")
|
|
|
|
-export class utils {
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 验证字符串是否是空的
|
|
|
|
- * @s 字符串
|
|
|
|
- */
|
|
|
|
- public static isNull(s: string) {
|
|
|
|
- if(s == ""
|
|
|
|
- || s == null
|
|
|
|
- || s == undefined){
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- if (typeof s === 'string'){
|
|
|
|
- let re = new RegExp("^[ ]+$");
|
|
|
|
- return re.test(s);
|
|
|
|
- }else{
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 合并多个字典
|
|
|
|
- * @param args
|
|
|
|
- */
|
|
|
|
- public static merge(...args) {
|
|
|
|
- let mergeFn = <T, U> (arg1: T, arg2: U) : (T & U) =>{
|
|
|
|
- let res = {} as (T & U);
|
|
|
|
- res = Object.assign(arg1, arg2);
|
|
|
|
- return res;
|
|
|
|
- };
|
|
|
|
- let nDict = {};
|
|
|
|
- args.forEach(obj => {
|
|
|
|
- nDict = mergeFn(nDict,obj);
|
|
|
|
- });
|
|
|
|
- return nDict;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 深度拷贝
|
|
|
|
- * @param {any} sObj 拷贝的对象
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static clone(sObj: any) {
|
|
|
|
- if (sObj === null || typeof sObj !== "object") {
|
|
|
|
- return sObj;
|
|
|
|
- }
|
|
|
|
- let s: { [key: string]: any } = {};
|
|
|
|
- if (sObj.constructor === Array) {
|
|
|
|
- s = [];
|
|
|
|
- }
|
|
|
|
- for (let i in sObj) {
|
|
|
|
- if (sObj.hasOwnProperty(i)) {
|
|
|
|
- s[i] = this.clone(sObj[i]);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return s;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 将object转化为数组
|
|
|
|
- * @param { any} srcObj
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static objectToArray(srcObj: { [key: string]: any }) {
|
|
|
|
- let resultArr: any[] = [];
|
|
|
|
- // to array
|
|
|
|
- for (let key in srcObj) {
|
|
|
|
- if (!srcObj.hasOwnProperty(key)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- resultArr.push(srcObj[key]);
|
|
|
|
- }
|
|
|
|
- return resultArr;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * !#zh 将数组转化为object。
|
|
|
|
- */
|
|
|
|
- /**
|
|
|
|
- * 将数组转化为object。
|
|
|
|
- * @param { any} srcObj
|
|
|
|
- * @param { string} objectKey
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static arrayToObject(srcObj: any, objectKey: string) {
|
|
|
|
- let resultObj: { [key: string]: any } = {};
|
|
|
|
- // to object
|
|
|
|
- for (var key in srcObj) {
|
|
|
|
- if (!srcObj.hasOwnProperty(key) || !srcObj[key][objectKey]) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- resultObj[srcObj[key][objectKey]] = srcObj[key];
|
|
|
|
- }
|
|
|
|
- return resultObj;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 根据权重,计算随机内容
|
|
|
|
- * @param {arrany} weightArr
|
|
|
|
- * @param {number} totalWeight 权重
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static getWeightRandIndex(weightArr: [], totalWeight: number) {
|
|
|
|
- let randWeight: number = Math.floor(Math.random() * totalWeight);
|
|
|
|
- let sum: number = 0;
|
|
|
|
- for (var weightIndex: number = 0; weightIndex < weightArr.length; weightIndex++) {
|
|
|
|
- sum += weightArr[weightIndex];
|
|
|
|
- if (randWeight < sum) {
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return weightIndex;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 从n个数中获取m个随机数
|
|
|
|
- * @param {Number} n 总数
|
|
|
|
- * @param {Number} m 获取数
|
|
|
|
- * @returns {Array} array 获取数列
|
|
|
|
- */
|
|
|
|
- public static getRandomNFromM(n: number, m: number) {
|
|
|
|
- let array: any[] = [];
|
|
|
|
- let intRd: number = 0;
|
|
|
|
- let count: number = 0;
|
|
|
|
- while (count < m) {
|
|
|
|
- if (count >= n + 1) {
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- intRd = this.getRandomInt(0, n);
|
|
|
|
- var flag = 0;
|
|
|
|
- for (var i = 0; i < count; i++) {
|
|
|
|
- if (array[i] === intRd) {
|
|
|
|
- flag = 1;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (flag === 0) {
|
|
|
|
- array[count] = intRd;
|
|
|
|
- count++;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return array;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 获取随机整数
|
|
|
|
- * @param {Number} min 最小值
|
|
|
|
- * @param {Number} max 最大值
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static getRandomInt(min: number, max: number) {
|
|
|
|
- let r: number = Math.random();
|
|
|
|
- let rr: number = r * (max - min + 1) + min;
|
|
|
|
- return Math.floor(rr);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 获取字符串长度
|
|
|
|
- * @param {string} render
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static getStringLength(render: string) {
|
|
|
|
- let strArr: string = render;
|
|
|
|
- let len: number = 0;
|
|
|
|
- for (let i: number = 0, n = strArr.length; i < n; i++) {
|
|
|
|
- let val: number = strArr.charCodeAt(i);
|
|
|
|
- if (val <= 255) {
|
|
|
|
- len = len + 1;
|
|
|
|
- } else {
|
|
|
|
- len = len + 2;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return Math.ceil(len / 2);
|
|
|
|
- }
|
|
|
|
- /**
|
|
|
|
- * 要从一个数组模型中随机取出 n 个元素
|
|
|
|
- * @param arr
|
|
|
|
- * @param n
|
|
|
|
- * @returns 返回一个新的数组
|
|
|
|
- */
|
|
|
|
- public static getRandomElements<T>(arr: T[], n: number): T[] {
|
|
|
|
- if (n <= 0) return []; // 如果 n 小于等于 0,返回空数组
|
|
|
|
- //复制数组以避免修改原数组
|
|
|
|
- const copy = [...arr];
|
|
|
|
- //Fisher-Yates 洗牌算法
|
|
|
|
- for (let i = copy.length - 1; i > 0; i--) {
|
|
|
|
- const j = Math.floor(Math.random() * (i + 1));
|
|
|
|
- [copy[i], copy[j]] = [copy[j], copy[i]];
|
|
|
|
- }
|
|
|
|
- //如果 n 超过数组长度,返回乱序后的整个数组
|
|
|
|
- if (n >= copy.length) {
|
|
|
|
- return copy;
|
|
|
|
- }
|
|
|
|
- //返回前 n 个元素
|
|
|
|
- return copy.slice(0, n);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 判断传入的参数是否为空的Object。数组或undefined会返回false
|
|
|
|
- * @param obj
|
|
|
|
- */
|
|
|
|
- public static isEmptyObject(obj: any) {
|
|
|
|
- let result: boolean = true;
|
|
|
|
- if (obj && obj.constructor === Object) {
|
|
|
|
- for (var key in obj) {
|
|
|
|
- if (obj.hasOwnProperty(key)) {
|
|
|
|
- result = false;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- result = false;
|
|
|
|
- }
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 判断是否是新的一天
|
|
|
|
- * @param {Object|Number} dateValue 时间对象 todo MessageCenter 与 pve 相关的时间存储建议改为 Date 类型
|
|
|
|
- * @returns {boolean}
|
|
|
|
- */
|
|
|
|
- public static isNewDay(dateValue: any) {
|
|
|
|
- // todo:是否需要判断时区?
|
|
|
|
- var oldDate: any = new Date(dateValue);
|
|
|
|
- var curDate: any = new Date();
|
|
|
|
- var oldYear = oldDate.getYear();
|
|
|
|
- var oldMonth = oldDate.getMonth();
|
|
|
|
- var oldDay = oldDate.getDate();
|
|
|
|
- var curYear = curDate.getYear();
|
|
|
|
- var curMonth = curDate.getMonth();
|
|
|
|
- var curDay = curDate.getDate();
|
|
|
|
- if (curYear > oldYear) {
|
|
|
|
- return true;
|
|
|
|
- } else {
|
|
|
|
- if (curMonth > oldMonth) {
|
|
|
|
- return true;
|
|
|
|
- } else {
|
|
|
|
- if (curDay > oldDay) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 获取对象属性数量
|
|
|
|
- * @param {object}o 对象
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static getPropertyCount(o: Object) {
|
|
|
|
- var n, count = 0;
|
|
|
|
- for (n in o) {
|
|
|
|
- if (o.hasOwnProperty(n)) {
|
|
|
|
- count++;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return count;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 返回一个差异化数组(将array中diff里的值去掉)
|
|
|
|
- * @param array
|
|
|
|
- * @param diff
|
|
|
|
- */
|
|
|
|
- public static difference(array: [], diff: any) {
|
|
|
|
- let result: any[] = [];
|
|
|
|
- if (array.constructor !== Array || diff.constructor !== Array) {
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
- let length = array.length;
|
|
|
|
- for (let i: number = 0; i < length; i++) {
|
|
|
|
- if (diff.indexOf(array[i]) === -1) {
|
|
|
|
- result.push(array[i]);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- public static _stringToArray(string: string) {
|
|
|
|
- // 用于判断emoji的正则们
|
|
|
|
- var rsAstralRange = '\\ud800-\\udfff';
|
|
|
|
- var rsZWJ = '\\u200d';
|
|
|
|
- var rsVarRange = '\\ufe0e\\ufe0f';
|
|
|
|
- var rsComboMarksRange = '\\u0300-\\u036f';
|
|
|
|
- var reComboHalfMarksRange = '\\ufe20-\\ufe2f';
|
|
|
|
- var rsComboSymbolsRange = '\\u20d0-\\u20ff';
|
|
|
|
- var rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange;
|
|
|
|
- var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');
|
|
|
|
- var rsFitz = '\\ud83c[\\udffb-\\udfff]';
|
|
|
|
- var rsOptVar = '[' + rsVarRange + ']?';
|
|
|
|
- var rsCombo = '[' + rsComboRange + ']';
|
|
|
|
- var rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')';
|
|
|
|
- var reOptMod = rsModifier + '?';
|
|
|
|
- var rsAstral = '[' + rsAstralRange + ']';
|
|
|
|
- var rsNonAstral = '[^' + rsAstralRange + ']';
|
|
|
|
- var rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}';
|
|
|
|
- var rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]';
|
|
|
|
- var rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*';
|
|
|
|
- var rsSeq = rsOptVar + reOptMod + rsOptJoin;
|
|
|
|
- var rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
|
|
|
|
- var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
|
|
|
|
- var hasUnicode = function (val: any) {
|
|
|
|
- return reHasUnicode.test(val);
|
|
|
|
- };
|
|
|
|
- var unicodeToArray = function (val: any) {
|
|
|
|
- return val.match(reUnicode) || [];
|
|
|
|
- };
|
|
|
|
- var asciiToArray = function (val: any) {
|
|
|
|
- return val.split('');
|
|
|
|
- };
|
|
|
|
- return hasUnicode(string) ? unicodeToArray(string) : asciiToArray(string);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 模拟传msg的uuid
|
|
|
|
- public static simulationUUID() {
|
|
|
|
- function s4() {
|
|
|
|
- return Math.floor((1 + Math.random()) * 0x10000)
|
|
|
|
- .toString(16)
|
|
|
|
- .substring(1);
|
|
|
|
- }
|
|
|
|
- return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
|
|
|
- s4() + '-' + s4() + s4() + s4();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public static trim(str: string) {
|
|
|
|
- return str.replace(/(^\s*)|(\s*$)/g, "");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 判断当前时间是否在有效时间内
|
|
|
|
- * @param {String|Number} start 起始时间。带有时区信息
|
|
|
|
- * @param {String|Number} end 结束时间。带有时区信息
|
|
|
|
- */
|
|
|
|
- public static isNowValid(start: any, end: any) {
|
|
|
|
- var startTime = new Date(start);
|
|
|
|
- var endTime = new Date(end);
|
|
|
|
- var result = false;
|
|
|
|
- if (startTime.getDate() + '' !== 'NaN' && endTime.getDate() + '' !== 'NaN') {
|
|
|
|
- var curDate = new Date();
|
|
|
|
- result = curDate < endTime && curDate > startTime;
|
|
|
|
- }
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 返回相隔天数
|
|
|
|
- * @param start
|
|
|
|
- * @param end
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static getDeltaDays(start: any, end: any) {
|
|
|
|
- start = new Date(start);
|
|
|
|
- end = new Date(end);
|
|
|
|
- let startYear: number = start.getFullYear();
|
|
|
|
- let startMonth: number = start.getMonth() + 1;
|
|
|
|
- let startDate: number = start.getDate();
|
|
|
|
- let endYear: number = end.getFullYear();
|
|
|
|
- let endMonth: number = end.getMonth() + 1;
|
|
|
|
- let endDate: number = end.getDate();
|
|
|
|
- start = new Date(startYear + '/' + startMonth + '/' + startDate + ' GMT+0800').getTime();
|
|
|
|
- end = new Date(endYear + '/' + endMonth + '/' + endDate + ' GMT+0800').getTime();
|
|
|
|
- let deltaTime = end - start;
|
|
|
|
- return Math.floor(deltaTime / (24 * 60 * 60 * 1000));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 获取数组最小值
|
|
|
|
- * @param array 数组
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static getMin(array: number[]) {
|
|
|
|
- let result: number = null!;
|
|
|
|
- if (array.constructor === Array) {
|
|
|
|
- let length = array.length;
|
|
|
|
- for (let i = 0; i < length; i++) {
|
|
|
|
- if (i === 0) {
|
|
|
|
- result = Number(array[0]);
|
|
|
|
- } else {
|
|
|
|
- result = result > Number(array[i]) ? Number(array[i]) : result;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 格式化两位小数点
|
|
|
|
- * @param time
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static formatTwoDigits(time: number) {
|
|
|
|
- //@ts-ignore
|
|
|
|
- return (Array(2).join(0) + time).slice(-2);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 根据格式返回时间
|
|
|
|
- * @param date 时间
|
|
|
|
- * @param fmt 格式
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static formatDate(date: Date, fmt: string) {
|
|
|
|
- let o: any = {
|
|
|
|
- "M+": date.getMonth() + 1, //月份
|
|
|
|
- "d+": date.getDate(), //日
|
|
|
|
- "h+": date.getHours(), //小时
|
|
|
|
- "m+": date.getMinutes(), //分
|
|
|
|
- "s+": date.getSeconds(), //秒
|
|
|
|
- "q+": Math.floor((date.getMonth() + 3) / 3), //季度
|
|
|
|
- "S": date.getMilliseconds() //毫秒
|
|
|
|
- };
|
|
|
|
- if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
|
|
|
|
- for (let k in o)
|
|
|
|
- if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
|
|
|
|
- return fmt;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 获取格式化后的日期(不含小时分秒)
|
|
|
|
- */
|
|
|
|
- public static getDay() {
|
|
|
|
- let date: Date = new Date();
|
|
|
|
- return date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 格式化名字,XXX...
|
|
|
|
- * @param {string} name 需要格式化的字符串
|
|
|
|
- * @param {number}limit
|
|
|
|
- * @returns {string} 返回格式化后的字符串XXX...
|
|
|
|
- */
|
|
|
|
- public static formatName(name: string, limit: number) {
|
|
|
|
- limit = limit || 6;
|
|
|
|
- var nameArray = this._stringToArray(name);
|
|
|
|
- var str = '';
|
|
|
|
- var length = nameArray.length;
|
|
|
|
- if (length > limit) {
|
|
|
|
- for (var i = 0; i < limit; i++) {
|
|
|
|
- str += nameArray[i];
|
|
|
|
- }
|
|
|
|
- str += '...';
|
|
|
|
- } else {
|
|
|
|
- str = name;
|
|
|
|
- }
|
|
|
|
- return str;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 格式化钱数,超过10000 转换位 10K 10000K 转换为 10M
|
|
|
|
- * @param {number}money 需要被格式化的数值
|
|
|
|
- * @returns {string}返回 被格式化的数值
|
|
|
|
- */
|
|
|
|
- public static formatMoney(money: number) {
|
|
|
|
- let arrUnit: string[] = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'B', 'N', 'D'];
|
|
|
|
-
|
|
|
|
- let strValue: string = '';
|
|
|
|
- for (let idx: number = 0; idx < arrUnit.length; idx++) {
|
|
|
|
- if (money >= 10000) {
|
|
|
|
- money /= 1000;
|
|
|
|
- } else {
|
|
|
|
- strValue = Math.floor(money) + arrUnit[idx];
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (strValue === '') {
|
|
|
|
- strValue = Math.floor(money) + 'U'; //超过最大值就加个U
|
|
|
|
- }
|
|
|
|
- return strValue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 格式化数值
|
|
|
|
- * @param {number}value 需要被格式化的数值
|
|
|
|
- * @returns {string}返回 被格式化的数值
|
|
|
|
- */
|
|
|
|
- public static formatValue(value: number) {
|
|
|
|
- let arrUnit: string[] = [];
|
|
|
|
- let strValue: string = '';
|
|
|
|
- for (let i = 0; i < 26; i++) {
|
|
|
|
- arrUnit.push(String.fromCharCode(97 + i));
|
|
|
|
- }
|
|
|
|
- for (let idx: number = 0; idx < arrUnit.length; idx++) {
|
|
|
|
- if (value >= 10000) {
|
|
|
|
- value /= 1000;
|
|
|
|
- } else {
|
|
|
|
- strValue = Math.floor(value) + arrUnit[idx];
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return strValue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 根据剩余秒数格式化剩余时间 返回 HH:MM:SS
|
|
|
|
- * @param {Number} leftSec
|
|
|
|
- */
|
|
|
|
- public static formatTimeForSecond(leftSec: number, withoutSeconds: boolean = false) {
|
|
|
|
- let timeStr: string = '';
|
|
|
|
- let sec: number = leftSec % 60;
|
|
|
|
- let leftMin: number = Math.floor(leftSec / 60);
|
|
|
|
- leftMin = leftMin < 0 ? 0 : leftMin;
|
|
|
|
- let hour: number = Math.floor(leftMin / 60);
|
|
|
|
- let min: number = leftMin % 60;
|
|
|
|
- if (hour > 0) {
|
|
|
|
- timeStr += hour > 9 ? hour.toString() : '0' + hour;
|
|
|
|
- timeStr += ':';
|
|
|
|
- } else {
|
|
|
|
- timeStr += '00:';
|
|
|
|
- }
|
|
|
|
- timeStr += min > 9 ? min.toString() : '0' + min;
|
|
|
|
- if (!withoutSeconds) {
|
|
|
|
- timeStr += ':';
|
|
|
|
- timeStr += sec > 9 ? sec.toString() : '0' + sec;
|
|
|
|
- }
|
|
|
|
- return timeStr;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 根据剩余毫秒数格式化剩余时间 返回 HH:MM:SS
|
|
|
|
- *
|
|
|
|
- * @param {Number} ms
|
|
|
|
- */
|
|
|
|
- public static formatTimeForMillisecond(ms: number): Object {
|
|
|
|
- let second: number = Math.floor(ms / 1000 % 60);
|
|
|
|
- let minute: number = Math.floor(ms / 1000 / 60 % 60);
|
|
|
|
- let hour: number = Math.floor(ms / 1000 / 60 / 60);
|
|
|
|
- return { 'hour': hour, 'minute': minute, 'second': second };
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 格式化时间戳字符串
|
|
|
|
- * @param timestamp 1740006560000
|
|
|
|
- * @returns 输出2025-02-20 05:09:20
|
|
|
|
- */
|
|
|
|
- public static formatTimestamp(timestamp: number): string {
|
|
|
|
- const date = new Date(timestamp);
|
|
|
|
- //获取年月日时分秒
|
|
|
|
- const year = date.getFullYear();
|
|
|
|
- //月份从 0 开始,需要 +1
|
|
|
|
- const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
|
- const day = String(date.getDate()).padStart(2, '0');
|
|
|
|
- const hours = String(date.getHours()).padStart(2, '0');
|
|
|
|
- const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
|
|
- const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
|
|
- //拼接成 YYYY-MM-DD HH:MM:SS 格式
|
|
|
|
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 随机乱序数组
|
|
|
|
- * @param array
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static randomArray(array) {
|
|
|
|
- // 使用 Fisher-Yates Shuffle 算法
|
|
|
|
- for (let i = array.length - 1; i > 0; i--) {
|
|
|
|
- const j = Math.floor(Math.random() * (i + 1));
|
|
|
|
- // 交换元素
|
|
|
|
- [array[i], array[j]] = [array[j], array[i]];
|
|
|
|
- }
|
|
|
|
- return array;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 获得开始和结束两者之间相隔分钟数
|
|
|
|
- *
|
|
|
|
- * @static
|
|
|
|
- * @param {number} start
|
|
|
|
- * @param {number} end
|
|
|
|
- * @memberof utils
|
|
|
|
- */
|
|
|
|
- public static getOffsetMimutes(start: number, end: number) {
|
|
|
|
- let offSetTime: number = end - start;
|
|
|
|
- let minute: number = Math.floor((offSetTime % (1000 * 60 * 60)) / (1000 * 60));
|
|
|
|
- return minute;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 获取随机小数
|
|
|
|
- * @param {Number} min 最小值
|
|
|
|
- * @param {Number} max 最大值
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static getRandomFloat(min: number, max: number) {
|
|
|
|
- return Math.random() * (max - min) + min;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 返回指定小数位的数值
|
|
|
|
- * @param {number} num
|
|
|
|
- * @param {number} idx
|
|
|
|
- */
|
|
|
|
- public static formatNumToFixed(num: number, idx: number = 0) {
|
|
|
|
- return Number(num.toFixed(idx));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 用于数值到达另外一个目标数值之间进行平滑过渡运动效果
|
|
|
|
- * @param {number} targetValue 目标数值
|
|
|
|
- * @param {number} curValue 当前数值
|
|
|
|
- * @param {number} ratio 过渡比率
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static lerp(targetValue: number, curValue: number, ratio: number = 0.25) {
|
|
|
|
- let v: number = curValue;
|
|
|
|
- if (targetValue > curValue) {
|
|
|
|
- v = curValue + (targetValue - curValue) * ratio;
|
|
|
|
- } else if (targetValue < curValue) {
|
|
|
|
- v = curValue - (curValue - targetValue) * ratio;
|
|
|
|
- }
|
|
|
|
- return v;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 数据解密
|
|
|
|
- * @param {String} str
|
|
|
|
- */
|
|
|
|
- public static decrypt(b64Data: string) {
|
|
|
|
- if(b64Data == null || b64Data == undefined){
|
|
|
|
- return "";
|
|
|
|
- }
|
|
|
|
- let n: number = 6;
|
|
|
|
- if (b64Data.length % 2 === 0) {
|
|
|
|
- n = 7;
|
|
|
|
- }
|
|
|
|
- let decodeData = '';
|
|
|
|
- for (var idx = 0; idx < b64Data.length - n; idx += 2) {
|
|
|
|
- decodeData += b64Data[idx + 1];
|
|
|
|
- decodeData += b64Data[idx];
|
|
|
|
- }
|
|
|
|
- decodeData += b64Data.slice(b64Data.length - n + 1);
|
|
|
|
- decodeData = this._base64Decode(decodeData);
|
|
|
|
- return decodeData;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 数据加密
|
|
|
|
- * @param {String} str
|
|
|
|
- */
|
|
|
|
- public static encrypt(str: string) {
|
|
|
|
- if(str == null || str == undefined){
|
|
|
|
- return "";
|
|
|
|
- }
|
|
|
|
- let b64Data = this._base64encode(str);
|
|
|
|
- let n: number = 6;
|
|
|
|
- if (b64Data.length % 2 === 0) {
|
|
|
|
- n = 7;
|
|
|
|
- }
|
|
|
|
- let encodeData: string = '';
|
|
|
|
- for (let idx = 0; idx < (b64Data.length - n + 1) / 2; idx++) {
|
|
|
|
- encodeData += b64Data[2 * idx + 1];
|
|
|
|
- encodeData += b64Data[2 * idx];
|
|
|
|
- }
|
|
|
|
- encodeData += b64Data.slice(b64Data.length - n + 1);
|
|
|
|
- return encodeData;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- //public method for encoding
|
|
|
|
- /**
|
|
|
|
- * base64加密
|
|
|
|
- * @param {string}input
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- private static _base64encode(input: string) {
|
|
|
|
- let keyStr: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
|
|
- let output: string = "", chr1: number, chr2: number, chr3: number, enc1: number, enc2: number, enc3: number, enc4: number, i: number = 0;
|
|
|
|
- input = this._utf8Encode(input);
|
|
|
|
- while (i < input.length) {
|
|
|
|
- chr1 = input.charCodeAt(i++);
|
|
|
|
- chr2 = input.charCodeAt(i++);
|
|
|
|
- chr3 = input.charCodeAt(i++);
|
|
|
|
- enc1 = chr1 >> 2;
|
|
|
|
- enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
|
|
|
- enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
|
|
|
- enc4 = chr3 & 63;
|
|
|
|
- if (isNaN(chr2)) {
|
|
|
|
- enc3 = enc4 = 64;
|
|
|
|
- } else if (isNaN(chr3)) {
|
|
|
|
- enc4 = 64;
|
|
|
|
- }
|
|
|
|
- output = output +
|
|
|
|
- keyStr.charAt(enc1) + keyStr.charAt(enc2) +
|
|
|
|
- keyStr.charAt(enc3) + keyStr.charAt(enc4);
|
|
|
|
- }
|
|
|
|
- return output;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * utf-8 加密
|
|
|
|
- * @param string
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- private static _utf8Encode(string: string) {
|
|
|
|
- string = string.replace(/\r\n/g, "\n");
|
|
|
|
- let utftext: string = "";
|
|
|
|
- for (let n: number = 0; n < string.length; n++) {
|
|
|
|
- let c: number = string.charCodeAt(n);
|
|
|
|
- if (c < 128) {
|
|
|
|
- utftext += String.fromCharCode(c);
|
|
|
|
- } else if ((c > 127) && (c < 2048)) {
|
|
|
|
- utftext += String.fromCharCode((c >> 6) | 192);
|
|
|
|
- utftext += String.fromCharCode((c & 63) | 128);
|
|
|
|
- } else {
|
|
|
|
- utftext += String.fromCharCode((c >> 12) | 224);
|
|
|
|
- utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
|
|
|
- utftext += String.fromCharCode((c & 63) | 128);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return utftext;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * utf-8解密
|
|
|
|
- * @param utftext
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- private static _utf8Decode(utftext: string) {
|
|
|
|
- let string = "";
|
|
|
|
- let i: number = 0;
|
|
|
|
- let c: number = 0;
|
|
|
|
- let c1: number = 0;
|
|
|
|
- let c2: number = 0;
|
|
|
|
- let c3: number = 0;
|
|
|
|
- while (i < utftext.length) {
|
|
|
|
- c = utftext.charCodeAt(i);
|
|
|
|
- if (c < 128) {
|
|
|
|
- string += String.fromCharCode(c);
|
|
|
|
- i++;
|
|
|
|
- } else if ((c > 191) && (c < 224)) {
|
|
|
|
- c2 = utftext.charCodeAt(i + 1);
|
|
|
|
- string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
|
|
|
- i += 2;
|
|
|
|
- } else {
|
|
|
|
- c2 = utftext.charCodeAt(i + 1);
|
|
|
|
- c3 = utftext.charCodeAt(i + 2);
|
|
|
|
- string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
|
|
|
- i += 3;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return string;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * base64解密
|
|
|
|
- * @param {string}input 解密字符串
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- private static _base64Decode(input: string) {
|
|
|
|
- let keyStr: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
|
|
- let output: string = "";
|
|
|
|
- let chr1: number;
|
|
|
|
- let chr2: number;
|
|
|
|
- let chr3: number;
|
|
|
|
- let enc1: number;
|
|
|
|
- let enc2: number;
|
|
|
|
- let enc3: number;
|
|
|
|
- let enc4: number;
|
|
|
|
- let i: number = 0;
|
|
|
|
- input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
|
|
|
- while (i < input.length) {
|
|
|
|
- enc1 = keyStr.indexOf(input.charAt(i++));
|
|
|
|
- enc2 = keyStr.indexOf(input.charAt(i++));
|
|
|
|
- enc3 = keyStr.indexOf(input.charAt(i++));
|
|
|
|
- enc4 = keyStr.indexOf(input.charAt(i++));
|
|
|
|
- chr1 = (enc1 << 2) | (enc2 >> 4);
|
|
|
|
- chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
|
|
|
- chr3 = ((enc3 & 3) << 6) | enc4;
|
|
|
|
- output = output + String.fromCharCode(chr1);
|
|
|
|
- if (enc3 != 64) {
|
|
|
|
- output = output + String.fromCharCode(chr2);
|
|
|
|
- }
|
|
|
|
- if (enc4 != 64) {
|
|
|
|
- output = output + String.fromCharCode(chr3);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- output = this._utf8Decode(output);
|
|
|
|
- return output;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 开始展示文字
|
|
|
|
- * @param lable 文本
|
|
|
|
- * @param words 播放的文字
|
|
|
|
- * @param cb 播放完成回调
|
|
|
|
- * @param cbbS 回调延迟
|
|
|
|
- * @param delay 延迟逐字播放
|
|
|
|
- * @param s 一个字的播放速度/秒
|
|
|
|
- */
|
|
|
|
- public static verbatim(lable: Label,words: string, cb?: Function,cbbS:number = 0,delay: number = 0,s: number = 0.1,){
|
|
|
|
- if (!words.hasOwnProperty('length')) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- lable.node.active = true;
|
|
|
|
- lable.unscheduleAllCallbacks();
|
|
|
|
- let f = function(){
|
|
|
|
- let arr = words.replace(/ /g,"").split('');
|
|
|
|
- var step = 0;
|
|
|
|
- var allWords: string = "";
|
|
|
|
- let fun: Function = function () {
|
|
|
|
- allWords += arr[step];
|
|
|
|
- lable.string = allWords;
|
|
|
|
- if (++step >= arr.length) {
|
|
|
|
- lable.unschedule(fun);
|
|
|
|
- let cbFun = ()=>{cb?.()};
|
|
|
|
- cbbS > 0 ? (lable.scheduleOnce(cbFun, cbbS)) : cbFun();
|
|
|
|
- }
|
|
|
|
- }.bind(this);
|
|
|
|
- lable.schedule(fun,s,Number.MAX_SAFE_INTEGER);
|
|
|
|
- };
|
|
|
|
- delay > 0 ? (lable.scheduleOnce(f.bind(this),delay)) : f();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 页面渐隐渐显动画
|
|
|
|
- * @param n 节点
|
|
|
|
- * @param isApper 是否是出现
|
|
|
|
- * @param restore 是否恢复255显示的状态
|
|
|
|
- * @param cb 执行完回调
|
|
|
|
- */
|
|
|
|
- public static pageAnim(n: Node,isApper: boolean = true,cb?:Function){
|
|
|
|
- let uiop:UIOpacity = n.getComponent(UIOpacity);
|
|
|
|
- if(!n || !uiop){
|
|
|
|
- cb?.();
|
|
|
|
- }else{
|
|
|
|
- uiop.opacity = isApper ? 25 : 255;
|
|
|
|
- let toOpacity: number = isApper ? 255 : 25;
|
|
|
|
- tween(uiop)
|
|
|
|
- .to(0.4,{opacity:toOpacity})
|
|
|
|
- .call(function(){
|
|
|
|
- cb?.();
|
|
|
|
- }.bind(this))
|
|
|
|
- .start();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 将数组(array)拆分成多个 size 长度的区块,并将这些区块组成一个新数组
|
|
|
|
- * @param {Array}array
|
|
|
|
- * @param {number}size
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static chunk(array: any[], size: number) {
|
|
|
|
- var length = array === null ? 0 : array.length;
|
|
|
|
- if (!length || size < 1) {
|
|
|
|
- return [];
|
|
|
|
- }
|
|
|
|
- let result = [];
|
|
|
|
- while (array.length > size) {
|
|
|
|
- result.push(array.slice(0, size));
|
|
|
|
- array = array.slice(size);
|
|
|
|
- }
|
|
|
|
- result.push(array);
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 查询一个节点下的子节点
|
|
|
|
- */
|
|
|
|
- public static findName(root: Node, name: string) : Node{
|
|
|
|
- let child: Node;
|
|
|
|
- if (name.indexOf("/") != -1) {
|
|
|
|
- child = find(name, root);
|
|
|
|
- } else {
|
|
|
|
- if (!root) {
|
|
|
|
- root = director.getScene();
|
|
|
|
- }
|
|
|
|
- if (root.name === name) {
|
|
|
|
- child = root;
|
|
|
|
- } else {
|
|
|
|
- child = this.findChild(name, root);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (child) {
|
|
|
|
- return child;
|
|
|
|
- } else {
|
|
|
|
- console.log("没有找到指定的Node, node name ==", name);
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private static findChild(name: string, parent: Node): Node {
|
|
|
|
- let child: Node = parent.getChildByName(name);
|
|
|
|
- if (child) {
|
|
|
|
- return child;
|
|
|
|
- } else {
|
|
|
|
- let children: Node[] = parent.children;
|
|
|
|
- for (let i = 0; i < children.length; i++) {
|
|
|
|
- child = this.findChild(name, children[i]);
|
|
|
|
- if (child) {
|
|
|
|
- return child;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 处理万为单位
|
|
|
|
- * @param num 数值
|
|
|
|
- * @param point 保留小数点
|
|
|
|
- * @param s 是否去掉无用的0
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static numUnit(num: number,point: number = 0,f: boolean = true): string {
|
|
|
|
- let n: number = num;
|
|
|
|
- let unit: number = 10000;
|
|
|
|
- if (n > unit) {
|
|
|
|
- if(point == 0){
|
|
|
|
- n = Math.ceil(n / unit);
|
|
|
|
- return n.toString() + "万";
|
|
|
|
- }else{
|
|
|
|
- let s: string = (n / unit).toFixed(point);
|
|
|
|
- if(f){
|
|
|
|
- return this.removeZeros(s) + "万";
|
|
|
|
- }else{
|
|
|
|
- return s + "万";
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }else{
|
|
|
|
- return Math.ceil(num).toString();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 格式化数字:
|
|
|
|
- * * 如果小数部分全是 0(如 38.0 或 38.00),去掉小数部分,返回整数。
|
|
|
|
- * 如果是小数(如 38.1 或 38.01),保留两位小数。
|
|
|
|
- * @param num 输入的数字
|
|
|
|
- * @returns 格式化后的数字
|
|
|
|
- */
|
|
|
|
- public static formatNumber(num: number): number | string {
|
|
|
|
- // 如果 num 是 undefined 或 null,返回 0 或空字符串
|
|
|
|
- if (num == undefined || num == null) return 0;
|
|
|
|
- //将数字转换为字符串
|
|
|
|
- const numStr = num.toString();
|
|
|
|
- //判断小数部分是否全是 0 如果小数部分全是 0,去掉小数部分并返回整数
|
|
|
|
- if (numStr.includes('.') && /\.0+$/.test(numStr)) {
|
|
|
|
- return parseInt(numStr, 10);
|
|
|
|
- } else {
|
|
|
|
- //否则保留两位小数
|
|
|
|
- const fixedNum = num.toFixed(2);
|
|
|
|
- //如果小数部分全是 0,去掉小数部分
|
|
|
|
- if(fixedNum.endsWith(".00")) {
|
|
|
|
- return parseInt(fixedNum, 10);
|
|
|
|
- }
|
|
|
|
- return parseFloat(fixedNum);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 去掉小数点后无用的0
|
|
|
|
- * @param numberString 字符串呢
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static removeZeros(numberString: string): string {
|
|
|
|
- const trimmedString = numberString.trim(); // 去除首尾空格
|
|
|
|
- const decimalIndex = trimmedString.indexOf('.');
|
|
|
|
- if (decimalIndex !== -1) {
|
|
|
|
- let endIndex = trimmedString.length - 1;
|
|
|
|
- while (trimmedString[endIndex] === '0') {
|
|
|
|
- endIndex--;
|
|
|
|
- }
|
|
|
|
- if (trimmedString[endIndex] === '.') {
|
|
|
|
- endIndex--; // 如果小数点后面全是零,也去掉小数点
|
|
|
|
- }
|
|
|
|
- return trimmedString.slice(0, endIndex + 1);
|
|
|
|
- }
|
|
|
|
- return trimmedString;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 数组移除某一个元素
|
|
|
|
- */
|
|
|
|
- public static remove(arr,p){
|
|
|
|
- let index = arr.indexOf(p)
|
|
|
|
- if (index > -1) {
|
|
|
|
- arr.splice(index, 1)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 16进制的颜色
|
|
|
|
- * @param hexColor
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static hexColor(hexColor) {
|
|
|
|
- const hex = hexColor.replace(/^#?/, "0x");
|
|
|
|
- const c = parseInt(hex);
|
|
|
|
- const r = c >> 16;
|
|
|
|
- const g = (65280 & c) >> 8;
|
|
|
|
- const b = 255 & c;
|
|
|
|
- return new Color(r, g, b, 255);
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 计算两点间的距离
|
|
|
|
- */
|
|
|
|
- public static pDistance(localPos: Vec3,tarPos: Vec3): number {
|
|
|
|
- let dx = localPos.x - tarPos.x;
|
|
|
|
- let dy = localPos.y - tarPos.y;
|
|
|
|
- let dis = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
- return dis;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 计算两点之间的绝对距离
|
|
|
|
- */
|
|
|
|
- public static pAbsDistance(a: Vec3,b: Vec3): number {
|
|
|
|
- let p: number = Math.abs(a.x - b.x);
|
|
|
|
- let k: number = Math.abs(a.y - b.y);
|
|
|
|
- return p + k;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 角度转向量
|
|
|
|
- * @param angle
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static angle_to_vector (angle: number): Vec2 {
|
|
|
|
- // tan = sin / cos 将传入的角度转为弧度
|
|
|
|
- let radian = this.angle_to_radian(angle);
|
|
|
|
- // 算出cos,sin和tan
|
|
|
|
- let cos = Math.cos(radian);// 邻边 / 斜边
|
|
|
|
- let sin = Math.sin(radian);// 对边 / 斜边
|
|
|
|
- let tan = sin / cos;// 对边 / 邻边
|
|
|
|
- //结合在一起并归一化
|
|
|
|
- let vec = new Vec2(cos, sin).normalize();
|
|
|
|
- //返回向量
|
|
|
|
- return(vec);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 向量转角度
|
|
|
|
- * @param vector
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static vector_to_angle (vector: Vec2): number {
|
|
|
|
- //将传入的向量归一化
|
|
|
|
- let dir = vector.normalize();
|
|
|
|
- //计算出目标角度的弧度
|
|
|
|
- let radian = dir.signAngle(new Vec2(1, 0));
|
|
|
|
- //把弧度计算成角度
|
|
|
|
- let angle = -this.radian_to_angle(radian);
|
|
|
|
- //返回角度
|
|
|
|
- return(angle);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 角度转弧度
|
|
|
|
- * @param angle
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static angle_to_radian (angle: number): number {
|
|
|
|
- //角度转弧度公式 π / 180 * 角度 计算出弧度
|
|
|
|
- let radian = Math.PI / 180 * angle;
|
|
|
|
- //返回弧度
|
|
|
|
- return(radian);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 弧度转角度
|
|
|
|
- * @param radian
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static radian_to_angle (radian: number): number {
|
|
|
|
- //弧度转角度公式 180 / π * 弧度 计算出角度
|
|
|
|
- let angle = 180 / Math.PI * radian;
|
|
|
|
- //返回角度
|
|
|
|
- return(angle);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 计算弧度
|
|
|
|
- * @param start
|
|
|
|
- * @param end
|
|
|
|
- */
|
|
|
|
- public static getAngle(start: Vec3, end: Vec3) {
|
|
|
|
- //两点的x、y值
|
|
|
|
- var x = end.x - start.x;
|
|
|
|
- var y = end.y - start.y;
|
|
|
|
- var hypotenuse = Math.sqrt(x * x + y * y);
|
|
|
|
- //斜边长度
|
|
|
|
- var cos = x / hypotenuse;
|
|
|
|
- var radian = Math.acos(cos);
|
|
|
|
- //求出弧度
|
|
|
|
- var angle = 180 / (Math.PI / radian);
|
|
|
|
- //用弧度算出角度
|
|
|
|
- if (y < 0) {
|
|
|
|
- angle = 0 - angle;
|
|
|
|
- }else if (y == 0 && x < 0) {
|
|
|
|
- angle = 180;
|
|
|
|
- }
|
|
|
|
- return angle;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 扣血转化成字符串
|
|
|
|
- * @param number
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static numberToString(number:number) {
|
|
|
|
- let str = '';
|
|
|
|
- let data = [
|
|
|
|
- { minnum: 1000000000,maxnum:9999999999, toStr: 'o' },
|
|
|
|
- { minnum: 100000000,maxnum:999999999, toStr: 'p' },
|
|
|
|
- { minnum: 10000000,maxnum:99999999, toStr: 't' },
|
|
|
|
- { minnum: 1000000,maxnum:9999999, toStr: 'g' },
|
|
|
|
- { minnum: 100000,maxnum:999999, toStr: 'm' },
|
|
|
|
- { minnum: 10000,maxnum:99999, toStr: 'b' },
|
|
|
|
- { minnum: 1000,maxnum:9999, toStr: 'K' }
|
|
|
|
- ];
|
|
|
|
- for (let i: number = 0; i < data.length; i++) {
|
|
|
|
- if (number >= data[i].minnum && number <= data[i].maxnum ) {
|
|
|
|
- number /= data[i].minnum;
|
|
|
|
- let m: string = number.toFixed(1);
|
|
|
|
- str = m + data[i].toStr;
|
|
|
|
- return str;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return number.toFixed(0);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 将某个节点下的坐标转移到另外一个节点
|
|
|
|
- * @param fromNode 坐标所在的节点
|
|
|
|
- * @param toNode 目标节点
|
|
|
|
- * @returns 转换后的坐标值
|
|
|
|
- */
|
|
|
|
- public static convertPosition(fromNode: Node, toNode: Node): Vec3 {
|
|
|
|
- let pos: Vec3 = fromNode.position.clone();
|
|
|
|
- // 将 pos 转为世界坐标系下的坐标
|
|
|
|
- const worldPos: Vec3 = fromNode.parent.getComponent(UITransform).convertToWorldSpaceAR(pos);
|
|
|
|
- // 将世界坐标系下的坐标转为目标节点的局部坐标系下的坐标
|
|
|
|
- const localPos: Vec3 = toNode.getComponent(UITransform).convertToNodeSpaceAR(worldPos);
|
|
|
|
- return localPos;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 以敌人的中心点 攻击范围为半径 产生随机坐标
|
|
|
|
- * @param center 中心点
|
|
|
|
- * @param radius 半径
|
|
|
|
- * @returns
|
|
|
|
- */
|
|
|
|
- public static randomPointGenerator(center: Vec3,radius: number){
|
|
|
|
- //随机角度
|
|
|
|
- let angle = Math.random() * Math.PI * 2;
|
|
|
|
- //随机距离
|
|
|
|
- let distance = Math.sqrt(Math.random()) * radius;
|
|
|
|
- //根据极坐标转换成笛卡尔坐标
|
|
|
|
- const x = center.x + distance * Math.cos(angle);
|
|
|
|
- const y = center.y + distance * Math.sin(angle);
|
|
|
|
- return new Vec3(x,y,1);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 将某个节点上的坐标转移到另外一个节点
|
|
|
|
- * @param fromNode 坐标所在的节点
|
|
|
|
- * @param toNode 目标节点
|
|
|
|
- * @returns 转换后的坐标值
|
|
|
|
- */
|
|
|
|
- public static convertPositionPos(fromNode: Node,pos: Vec3, toNode: Node): Vec3 {
|
|
|
|
- let nPos: Vec3 = pos.clone();
|
|
|
|
- // 将 pos 转为世界坐标系下的坐标
|
|
|
|
- const worldPos: Vec3 = fromNode.parent.getComponent(UITransform).convertToWorldSpaceAR(nPos);
|
|
|
|
- // 将世界坐标系下的坐标转为目标节点的局部坐标系下的坐标
|
|
|
|
- const localPos: Vec3 = toNode.getComponent(UITransform).convertToNodeSpaceAR(worldPos);
|
|
|
|
- return localPos;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 根据A,B两个坐标点 和抛物线的弧度 来计算中心点坐标
|
|
|
|
- */
|
|
|
|
- public static calculateParabolaCenter(start: Vec3, end: Vec3){
|
|
|
|
- // 计算两点之间的水平距离
|
|
|
|
- const deltaX = end.x - start.x;
|
|
|
|
- // 将控制点的 x 坐标设置为两点的中点
|
|
|
|
- const controlX = (start.x + end.x) / 2;
|
|
|
|
- // 计算抛物线的最高点,使其位于两点之间的中间位置 可以根据需要调整最高点的位置
|
|
|
|
- const highestY = Math.max(start.y, end.y) + Math.abs(deltaX) / 4;
|
|
|
|
- // 计算控制点的 y 坐标
|
|
|
|
- const controlY = highestY;
|
|
|
|
- //返回抛物线的中心坐标点
|
|
|
|
- return new Vec3(controlX, controlY);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 生成一个随机颜色值的函数
|
|
|
|
- */
|
|
|
|
- public static getRandomColor() {
|
|
|
|
- let r = Math.floor(Math.random() * 256);
|
|
|
|
- let g = Math.floor(Math.random() * 256);
|
|
|
|
- let b = Math.floor(Math.random() * 256);
|
|
|
|
- return new Color(r, g, b);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 获取是否为16:9的常规屏幕尺寸
|
|
|
|
- */
|
|
|
|
- public static isNormalScreen(): boolean {
|
|
|
|
- return screen.windowSize.height /screen.windowSize.width < 1335 / 750;
|
|
|
|
- }
|
|
|
|
-}
|
|
|