/**
* 观察者方法
*
* @export
* @param {*} obj
* @param {Function} callback
* @param {*} pointer
* @return {*} {ProxyConstructor}
*/
export function observer(
obj: any,
callback: Function,
pointer: any
): ProxyConstructor {
return new Proxy<ProxyConstructor>(obj, {
set(target, property, value, reciever): boolean {
if (target[property] !== value) callback.call(pointer, value);
Reflect.set(target, property, value, reciever);
return true;
},
});
}
/**
* 加载远程url资源方法
*
* @export
* @param {string} path
* @return {*} {Promise<any>}
*/
export function loadRemote(path: string): Promise<any> {
return new Promise<any>((resolve, reject) => {
cc.assetManager.loadRemote(path, (error, asset) => {
if (error) reject(error);
resolve(asset);
});
});
}
/**
* 加载本地resources资源方法
*
* @export
* @param {string} path
* @return {*} {Promise<any>}
*/
export function loadRes(path: string): Promise<any> {
return new Promise<any>((resolve, reject) => {
cc.resources.load(path, (error, asset) => {
if (error) reject(error);
resolve(asset);
});
});
}
/**
* 延时执行方法
*
* @export
* @param {number} time
* @return {*} {Promise<boolean>}
*/
export function delay(time: number): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
setTimeout(() => {
resolve(true);
}, time);
});
}
/**
* 生成随机数方法
* @param Min 最小数
* @param Max 最大数
* @returns min ≤ r ≤ max
*/
export function randomNumBoth(Min: number, Max: number): number {
let Range: number = Max - Min;
let Rand: number = Math.random();
let num: number = Min + Math.round(Rand * Range); //四舍五入
return num;
}
/**
* 多选一方法
* @param arr 数组
* @returns 数组中任意的一个元素
*/
export function manyToOne(arr: Array<any>): any {
let key = Math.floor(Math.random() * arr.length);
let val = arr[key];
// return [key, val];
return val;
}
/**
* 深拷贝
*
* @param {*} obj
* @return {*}
*/
export function deepClone(obj: any): any {
// 判断是否是对象,不是对象,返回结果(返回值类型)
// obj == null判断了null和undefined两种情况 null==undefined
if (typeof obj !== "object" || obj == null) {
return obj;
}
// 初始化结果数据,如果是数组赋值为[],否则为{}
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
// 判断是否是自己的属性方法,而不是原型属性方法
// 如果是递归复制
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key]);
}
}
return result;
}
/**
* 一天剩余时间(毫秒)
* @returns 剩余时间
*/
export const timeRemainingToday = (): number => {
const today = new Date();
const tomorrowNow = new Date(today);
tomorrowNow.setDate(today.getDate() + 1);
const tomorrow = new Date(
tomorrowNow.getFullYear(),
tomorrowNow.getMonth(),
tomorrowNow.getDate()
);
return tomorrow.getTime() - today.getTime();
};
/**
* 编码方法
*/
export const encode = (data) =>
window.btoa(encodeURIComponent(JSON.stringify(data)));
/**
* 解码方法
*/
export const decode = (data) =>
JSON.parse(decodeURIComponent(window.atob(data)));
/**
* 获取网址的值
* @param 网址
* @returns 值
*/
export function getQueryVariable(variable: string): string {
const query = window.location.search.substring(1);
const vars = query.split("&");
for (let i = 0; i < vars.length; i++) {
const pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
return "";
}
/**
* storage
*/
export const storage = {
//存储
set(key, value) {
localStorage.setItem(key, encode(value));
},
//取出数据
get(key) {
let data = localStorage.getItem(key);
if (data != null && data != "") {
data = decode(data);
return data;
} else {
return null;
}
},
// 删除数据
remove(key) {
localStorage.removeItem(key);
},
};
/**
* 判断是否是手机的方法
* @returns 是否手机
*/
export function isMobile() {
return !!navigator.userAgent.match(
/(iPhone|iPod|Android|ios|iOS|iPad|Backerry|WebOS|Symbian|Windows Phone|Phone)/i
);
}
/**
* 通过img获取base64格式图片
* @param img
* @returns
*/
export function getBase64Image(img) {
let canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
let ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
let ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
let dataURL = canvas.toDataURL("image/" + ext);
return dataURL;
}
/**
* 通过src获取base64格式图片
* @param src
* @returns
*/
export function getBase64ImageByUrl(src) {
return new Promise<string>((resolve, reject) => {
let image = new Image();
image.crossOrigin = "";
image.src = src;
image.onload = function () {
let base64 = getBase64Image(image);
resolve(base64);
};
});
}
/**
* 下载图片方法
* @param imgsrc 图片路径
* @param name 图片名称
*/
export function downloadIamge(imgsrc, name) {
//下载图片地址和图片名
let image = new Image();
// 解决跨域 Canvas 污染问题
image.setAttribute("crossOrigin", "anonymous");
image.onload = function () {
let canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
let context = canvas.getContext("2d");
context.drawImage(image, 0, 0, image.width, image.height);
let url = canvas.toDataURL("image/png"); //得到图片的base64编码数据
let a = document.createElement("a"); // 生成一个a元素
let event = new MouseEvent("click"); // 创建一个单击事件
a.download = name || "photo"; // 设置图片名称
a.href = url; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
};
image.src = imgsrc;
}
/**
* cocos截图方法
* @param node 节点
*/
export function screenshot(node: cc.Node) {
return new Promise<string>((resolve, reject) => {
let nodeCamera = new cc.Node();
nodeCamera.parent = cc.find("Canvas");
let camera = nodeCamera.addComponent(cc.Camera);
let position = node.getPosition();
let width = node.width * node.scaleX;
let height = node.height * node.scaleY;
// 当 alignWithScreen 为 true 的时候,摄像机会自动将视窗大小调整为整个屏幕的大小。如果想要完全自由地控制摄像机,则需要将 alignWithScreen 设置为 false。(v2.2.1 新增)
camera.alignWithScreen = false;
// 设置摄像机的投影模式是正交(true)还是透视(false)模式
camera.ortho = true;
// 摄像机在正交投影模式下的视窗大小。该属性在 alignWithScreen 设置为 false 时生效。
camera.orthoSize = height / 2;
let texture = new cc.RenderTexture();
// 如果截图内容中不包含 Mask 组件,可以不用传递第三个参数
texture.initWithSize(
width,
height,
cc.game["_renderContext"].STENCIL_INDEX8
);
// 如果设置了 targetTexture,那么摄像机渲染的内容不会输出到屏幕上,而是会渲染到 targetTexture 上。
camera.targetTexture = texture;
node.setPosition(cc.Vec2.ZERO);
// 渲染一次摄像机,即更新一次内容到 RenderTexture 中
camera.render(node);
node.setPosition(position);
// 从 render texture 读取像素数据,数据类型为 RGBA 格式的 Uint8Array 数组。
// 默认每次调用此函数会生成一个大小为 (长 x 高 x 4) 的 Uint8Array。
let data = texture.readPixels();
// 创建画布
let canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
// write the render data
// 1 像素 = 32 bit(RGBA),1 byte = 8 bit,所以 1 像素 = 4 byte
// 每行 width 像素,即 width * 4 字节
let rowBytes = width * 4;
for (let row = 0; row < height; row++) {
// RenderTexture 得到的纹理是上下翻转的
let srow = height - 1 - row;
let imageData = ctx.createImageData(width, 1);
let start = srow * width * 4;
for (let i = 0; i < rowBytes; i++) {
imageData.data[i] = data[start + i];
}
ctx.putImageData(imageData, 0, row);
}
let dataURL = canvas.toDataURL("image/jpeg");
nodeCamera.destroy();
resolve(dataURL);
});
}
/**
* cocos截图返回精灵方法
* @param node 节点
*/
export function screenshotSpriteFrame(node: cc.Node) {
return new Promise<cc.SpriteFrame>(async (resolve, reject) => {
const dataURL = await screenshot(node);
let img = document.createElement("img");
img.src = dataURL;
let texture2D = new cc.Texture2D();
texture2D.initWithElement(img);
let spriteFrame = new cc.SpriteFrame();
spriteFrame.setTexture(texture2D);
resolve(spriteFrame);
});
}
/**
* cocos渲染节点截图方法
* @param node 节点
*/
export function renderNode(nodeCapture: cc.Node) {
return new Promise<string>((resolve, reject) => {
let nodeCamera = new cc.Node();
nodeCamera.parent = cc.find("Canvas");
let camera = nodeCamera.addComponent(cc.Camera);
let position = nodeCapture.getPosition();
let width = nodeCapture.width * nodeCapture.scaleX;
let height = nodeCapture.height * nodeCapture.scaleY;
// 当 alignWithScreen 为 true 的时候,摄像机会自动将视窗大小调整为整个屏幕的大小。如果想要完全自由地控制摄像机,则需要将 alignWithScreen 设置为 false。(v2.2.1 新增)
camera.alignWithScreen = false;
// 设置摄像机的投影模式是正交(true)还是透视(false)模式
camera.ortho = true;
// 摄像机在正交投影模式下的视窗大小。该属性在 alignWithScreen 设置为 false 时生效。
camera.orthoSize = height / 2;
let texture = new cc.RenderTexture();
// 如果截图内容中不包含 Mask 组件,可以不用传递第三个参数
texture.initWithSize(
width,
height,
cc.RenderTexture.DepthStencilFormat.RB_FMT_S8
);
// 如果设置了 targetTexture,那么摄像机渲染的内容不会输出到屏幕上,而是会渲染到 targetTexture 上。
camera.targetTexture = texture;
// 创建画布
let canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
nodeCapture.setPosition(cc.Vec2.ZERO);
// 渲染一次摄像机,即更新一次内容到 RenderTexture 中
camera.render(nodeCapture);
nodeCapture.setPosition(position);
// 从 render texture 读取像素数据,数据类型为 RGBA 格式的 Uint8Array 数组。
// 默认每次调用此函数会生成一个大小为 (长 x 高 x 4) 的 Uint8Array。
let data = texture.readPixels();
// write the render data
// PNG 中 1 像素 = 32 bit(RGBA),1 byte = 8 bit,所以 1 像素 = 4 byte
// 每行 width 像素,即 width * 4 字节
let rowBytes = width * 4;
for (let row = 0; row < height; row++) {
// RenderTexture 得到的纹理是上下翻转的
let srow = height - 1 - row;
let imageData = ctx.createImageData(width, 1);
let start = srow * width * 4;
for (let i = 0; i < rowBytes; i++) {
imageData.data[i] = data[start + i];
}
ctx.putImageData(imageData, 0, row);
}
let dataURL = canvas.toDataURL("image/png");
let img = document.createElement("img");
img.src = dataURL;
nodeCamera.destroy();
let texture2D = new cc.Texture2D();
texture2D.initWithElement(img);
let spriteFrame = new cc.SpriteFrame();
spriteFrame.setTexture(texture2D);
let node = new cc.Node();
let sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = spriteFrame;
resolve(dataURL);
});
}
/**
* cocos creater 截屏方法
* 分享数据页
* orthoSize 视窗大小,用于调整截图避免出现黑边或者白边
* @returns 图片
*/
export function screenNode(
nd: cc.Node,
orthoSize: number = 750,
w: number = 750,
h: number = 1464
) {
let node = nd;
let camera = node?.getComponent(cc.Camera);
if (!camera) {
camera = node.addComponent(cc.Camera);
}
// 设置你想要的截图内容的 cullingMask
// camera.cullingMask = 0xffffffff;
// 新建一个 RenderTexture,并且设置 camera 的 targetTexture 为新建的 RenderTexture,这样 camera 的内容将会渲染到新建的 RenderTexture 中。
let texture = new cc.RenderTexture();
//区域截图关闭这个
camera.alignWithScreen = false;
// let gl = cc.game._renderContext; //gl.STENCIL_INDEX8
//尺寸固定750*1624
texture.initWithSize(w, h, cc.RenderTexture.DepthStencilFormat.RB_FMT_S8); //(node.width,node.height,cc.RenderTexture.DepthStencilFormat.RB_FMT_S8); //(cc.visibleRect.width, cc.visibleRect.height);
camera.targetTexture = texture;
//设置合适的比例,避免出现黑边或者白边
camera.orthoSize = orthoSize * node.anchorX * 0.975; //node.width* node.scaleX * 1.07;//截头像的比例 0.5 //截数据页的比例1.07
// camera.backgroundColor = cc.Color.TRANSPARENT;
// 渲染一次摄像机,即更新一次内容到 RenderTexture 中
camera.render();
// 这样我们就能从 RenderTexture 中获取到数据了
let data = texture.readPixels();
// 接下来就可以对这些数据进行操作了
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = texture.width;
canvas.height = texture.height;
let width = texture.width;
let height = texture.height;
let rowBytes = width * 4;
for (let row = 0; row < height; row++) {
let srow = height - 1 - row;
let imageData = ctx.createImageData(width, 1);
let start = srow * width * 4;
for (let i = 0; i < rowBytes; i++) {
imageData.data[i] = data[start + i];
}
ctx.putImageData(imageData, 0, row);
}
let dataURL = canvas.toDataURL("image/jpeg");
// let img = document.createElement("img");
// img.src = dataURL;
return dataURL;
}
/**
* cocos截取图片方法
* @param node 节点
*/
export function captureNode(nodeCapture: cc.Node) {
return new Promise<cc.SpriteFrame>((resolve, reject) => {
let nodeCamera = new cc.Node();
nodeCamera.parent = cc.find("Canvas");
let camera = nodeCamera.addComponent(cc.Camera);
let width = nodeCapture.width;
let height = nodeCapture.height;
let texture = new cc.RenderTexture();
texture.initWithSize(
cc.visibleRect.width,
cc.visibleRect.height,
cc.RenderTexture.DepthStencilFormat.RB_FMT_S8
);
camera.targetTexture = texture;
let canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
camera.render();
// 指定需要读取的区域的像素
let size = nodeCapture.getContentSize();
let pixels = new Uint8Array(size.width * size.height * 4);
let x = texture.width / 2 - nodeCapture.width / 2;
let y = texture.height / 2 - nodeCapture.height / 2;
let w = nodeCapture.width;
let h = nodeCapture.height;
let data = texture.readPixels(pixels, x, y, w, h);
// write the render data
let rowBytes = width * 4;
for (let row = 0; row < height; row++) {
let srow = height - 1 - row;
let imageData = ctx.createImageData(width, 1);
let start = srow * width * 4;
for (let i = 0; i < rowBytes; i++) {
imageData.data[i] = data[start + i];
}
ctx.putImageData(imageData, 0, row);
}
let dataURL = canvas.toDataURL("image/png");
let img = document.createElement("img");
img.src = dataURL;
let texture2D = new cc.Texture2D();
texture2D.initWithElement(img);
let spriteFrame = new cc.SpriteFrame();
spriteFrame.setTexture(texture2D);
let node = new cc.Node();
let sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = spriteFrame;
// return node;
resolve(spriteFrame);
});
}
/**
* 截圆形头像图
* @param avatar 头像
* @param frame 头像框
*/
export function captureAvatar(avatar,frame) {
return new Promise<string>((resolve, reject) => {
let canvas = document.createElement("canvas");
//?头像尺寸待定
let w = 600;
let h = 600;
canvas.width = w;
canvas.height = h;
let ctx = canvas.getContext("2d");
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "rgba(255, 255, 255, 0)";
ctx.fill();
// return;
let img = document.createElement("img");
img.src = frame;
let bgImage = document.createElement("img");
bgImage.src = avatar;
bgImage.crossOrigin = "Anonymous";
bgImage.onload = function () {
let circle = {
x: w / 2,
y: h / 2,
r: w / 2,
};
ctx.clearRect(0, 0, w, h);
ctx.save();
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2, false);
ctx.clip();
ctx.drawImage(bgImage, 0, 0, 600, 600);
ctx.drawImage(img, 0, 0, 600, 600);
let base64 = canvas.toDataURL("image/png");
// let img2 = document.createElement("img");
// img2.src = base64;
resolve(base64);
};
});
}
/**
* 清除对象中的空属性
* @param obj 对象
* @returns 对象
*/
export function clearEmpty(obj: any) {
const clearFun = () => {
for (const key in obj) {
if (
["[object Object]"].includes(
Object.prototype.toString.call(obj[key])
) &&
Object.keys(obj[key]).length > 0
) {
clearEmpty(obj[key]);
} else {
if (
["", null, undefined].includes(obj[key]) ||
(["[object Object]"].includes(
Object.prototype.toString.call(obj[key])
) &&
Object.keys(obj[key]).length === 0)
) {
delete obj[key];
}
}
}
return obj;
};
// 第一次清理空属性
clearFun();
// 第二次清理空对象
return clearFun();
}
/**
* 判断是否是当天函数
* @param timeStamp 时间戳
* @returns
*/
export function isToday(timeStamp){
if(!timeStamp) return false;
return !!(new Date(Number(timeStamp)).toDateString() === new Date().toDateString());
}
/**
* 返回当前场景中的canvas节点
* @returns
*/
export function getCanvas() {
return <any>director.getScene().getChildByName("Canvas");
}
/**
* base64解密
*/
export function decode(input) {
// private method for UTF-8 decoding
const _utf8_decode = function (utftext) {
let string = "";
let i = 0;
let c = 0;
let c1 = 0;
let c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c1 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
i += 2;
} else {
c1 = utftext.charCodeAt(i + 1);
c2 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
i += 3;
}
}
return string;
}
let _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
let output = "";
let chr1, chr2, chr3;
let enc1, enc2, enc3, enc4;
let i = 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 = _utf8_decode(output);
return output;
}
/**
* 是否是对象函数
* @param {对象} obj
*/
export function isObj(obj) {
// @ts-ignore
return ["[object Object]"].includes(Object.prototype.toString.call(obj));
}
/**
* 更新属性函数(深度搜索算法)
* @param {目标属性} targetParams
* @param {更新属性} params
*/
export function updateProps(targetParams, params) {
if (!targetParams ?? !isObj(targetParams)) targetParams = {};
if (!isObj(params)) return params;
Object.keys(params).forEach((key) => {
if (isObj(params[key])) {
targetParams[key] = targetParams?.[key] ?? {};
updateProps(targetParams[key], params[key]);
} else {
if (targetParams[key] !== params[key]) {
targetParams[key] = params[key];
}
}
});
return targetParams;
}
cocos creater 游戏开发工具方法
于 2021-12-20 20:25:18 首次发布