feat: add builder configuration file

feat: add cocos-service configuration file
feat: add device configuration file
feat: add engine configuration file
feat: add information configuration file
feat: add program configuration file
feat: add project configuration file
feat: add TypeScript configuration file
This commit is contained in:
ZhouXiao
2025-12-22 11:42:51 +08:00
parent 66cfa73345
commit 487c68994d
202 changed files with 57615 additions and 0 deletions

View File

@@ -0,0 +1,427 @@
type index = {
x: number,
y: number
}
/**
* AStar类用于实现A*寻路算法。
*/
export class AStar {
private map: any[][] = []; // 地图数组
private weightMap: number[][] = null; // 权重地图数组
private openlist: index[] = []; // 开放列表,存储待评估的节点
private closelist: index[] = []; // 封闭列表,存储已评估的节点
private parentMap: Map<index, index>; // 父节点映射,用于回溯路径
private gcostMap: Map<index, number>; // g成本映射记录从起点到当前节点的成本
private hcostMap: Map<index, number>; // h成本映射记录从当前节点到终点的估算成本
private startValue: number = 0;
private endValue: number = 0;
private pathValue: number = 0;
private isEightDirections: boolean = false;
private neighborMap: Map<index, index[]>;
constructor() {
this.openlist = [];
this.closelist = [];
this.parentMap = new Map();
this.gcostMap = new Map();
this.hcostMap = new Map();
}
/**
* 设置地图。
* @param map 二维数组表示的地图
*/
setMap(map: number[][]) {
this.map = map;
}
/**
* 设置权重地图。
* @param weightMap 二维数组表示的权重地图
*/
setWeightMap(weightMap: number[][]) {
this.weightMap = weightMap;
}
setValue(startValue: number, endValue: number, pathValue: number) {
this.startValue = startValue;
this.endValue = endValue;
this.pathValue = pathValue;
}
setEightDirections(isEightDirections: boolean) {
this.isEightDirections = isEightDirections;
}
setNeighborMap(neighborMap: Map<index, index[]>) {
this.neighborMap = neighborMap;
}
/**
* 在给定范围内根据指定类型搜索从起点到终点的路径。
* @param start 起点索引
* @param end 终点索引
* @param type 搜索类型(可能影响启发式函数的选择)
* @returns 返回找到的路径数组,如果无路径则返回空数组
*/
search(start: index, end: index, type: number) {
this.init(); // 初始化搜索环境
if (this.map[start.y][start.x] !== this.startValue ||
this.map[end.y][end.x] !== this.endValue) {
console.log("Invalid start or end point");
return [];
}
// 初始化起点信息,并将其加入开放列表
this.openlist.push(start);
this.gcostMap.set(start, 0); // 起点到起点的距离为0
this.hcostMap.set(start, this.getHeuristicCost(start, end, type)); // 起点到终点的启发式成本
this.parentMap.set(start, null); // 起点的父节点设置为null
// 循环直到开放列表为空,即所有可能的路径都被考虑
while (this.openlist.length > 0) {
const current = this.getMinCostNode(this.openlist); // 从开放列表中选择成本最小的节点
if (!current) {
this.openlist.splice(this.openlist.indexOf(current), 1);
continue;
}
// 判断是否到达终点
if (this.isArrived(current, end)) {
return this.reconstructPath(end); // 如果到达终点,返回路径重构的结果
} else {
// 从开放列表移除当前节点,将其加入封闭列表
this.openlist.splice(this.openlist.indexOf(current), 1);
this.closelist.push(current);
// 遍历当前节点的所有邻居节点
const neighbors = this.getNeighbors(current);
for (const neighbor of neighbors) {
const hCost = this.getHeuristicCost(neighbor, end, type); // 计算邻居节点到终点的启发式成本
const gCost = this.gcostMap.get(current) + this.getGCost(current, neighbor, type); // 计算当前节点到邻居节点的实际成本
const totalCost = gCost + hCost; // 计算总成本
// 根据邻居节点的状态进行处理
if (!this.isInClosedList(neighbor)) {
if (!this.isInOpenList(neighbor)) {
this.openlist.push(neighbor); // 如果邻居未在开放列表中,将其加入
this.updateCost(neighbor, gCost, hCost); // 更新邻居节点的成本信息
this.updateParent(neighbor, current); // 更新邻居节点的父节点信息
} else {
// 如果邻居已在开放列表中,但通过当前节点发现更优路径
if (totalCost < this.getCost(neighbor)) {
this.updateCost(neighbor, gCost, hCost); // 更新成本信息
this.updateParent(neighbor, current); // 更新父节点信息
}
}
}
}
}
}
console.log("No path found.");
return []; // 如果无法找到路径,返回空数组
}
/**
* 初始化算法状态。
*/
private init() {
// 重置所有列表和映射
this.openlist = [];
this.closelist = [];
this.parentMap = new Map();
this.gcostMap = new Map();
this.hcostMap = new Map();
}
/**
* 获取当前节点的邻居。
* @param current 当前节点坐标
* @returns 邻居节点数组
*/
private getNeighbors(current: index) {
if (this.neighborMap.size === 0) {
const neighbors: index[] = [];
// 尝试获取四个方向的邻居节点
const upindex = { x: current.x, y: current.y + 1 };
const downindex = { x: current.x, y: current.y - 1 };
const leftindex = { x: current.x - 1, y: current.y };
const rightindex = { x: current.x + 1, y: current.y };
const upleftindex = { x: current.x - 1, y: current.y + 1 };
const uprightindex = { x: current.x + 1, y: current.y + 1 };
const downleftindex = { x: current.x - 1, y: current.y - 1 };
const downrightindex = { x: current.x + 1, y: current.y - 1 };
// 如果合法则加入邻居列表
if (this.isValidIndex(upindex) && (this.map[upindex.y][upindex.x] == this.pathValue ||
this.map[upindex.y][upindex.x] == this.endValue)) {
neighbors.push(upindex);
}
if (this.isValidIndex(downindex) && (this.map[downindex.y][downindex.x] == this.pathValue ||
this.map[downindex.y][downindex.x] == this.endValue)) {
neighbors.push(downindex);
}
if (this.isValidIndex(leftindex) && (this.map[leftindex.y][leftindex.x] == this.pathValue ||
this.map[leftindex.y][leftindex.x] == this.endValue)) {
neighbors.push(leftindex);
}
if (this.isValidIndex(rightindex) && (this.map[rightindex.y][rightindex.x] == this.pathValue ||
this.map[rightindex.y][rightindex.x] == this.endValue)) {
neighbors.push(rightindex);
}
if (this.isEightDirections) {
if (this.isValidIndex(upleftindex) && (this.map[upleftindex.y][upleftindex.x] == this.pathValue ||
this.map[upleftindex.y][upleftindex.x] == this.endValue)) {
neighbors.push(upleftindex);
}
if (this.isValidIndex(downleftindex) && (this.map[downleftindex.y][downleftindex.x] == this.pathValue ||
this.map[downleftindex.y][downleftindex.x] == this.endValue)) {
neighbors.push(downleftindex);
}
if (this.isValidIndex(downrightindex) && (this.map[downrightindex.y][downrightindex.x] == this.pathValue ||
this.map[downrightindex.y][downrightindex.x] == this.endValue)) {
neighbors.push(downrightindex);
}
if (this.isValidIndex(uprightindex) && (this.map[uprightindex.y][uprightindex.x] == this.pathValue ||
this.map[uprightindex.y][uprightindex.x] == this.endValue)) {
neighbors.push(uprightindex);
}
}
return neighbors;
} else {
const _neighbors = this.neighborMap.get(current);
const neighbors: index[] = [];
for (const neighbor of _neighbors) {
if (this.map[neighbor.y][neighbor.x] == this.pathValue ||
this.map[neighbor.y][neighbor.x] == this.endValue) {
neighbors.push(neighbor);
}
}
return neighbors;
}
}
/**
* 计算从当前节点到邻居节点的实际成本
* @param current 当前节点
* @param neighbor 邻居节点
* @param type 距离计算类型
* @returns 返回从当前节点到邻居节点的成本
*/
private getGCost(current: index, neighbor: index, type: number = 0) {
let baseCost = 0;
// 计算基础距离成本
switch (type) {
case 0: {
// 计算曼哈顿距离
baseCost = Math.abs(current.x - neighbor.x) + Math.abs(current.y - neighbor.y);
break;
}
case 1: {
// 计算欧几里得距离
baseCost = Math.sqrt(Math.pow(current.x - neighbor.x, 2) + Math.pow(current.y - neighbor.y, 2));
break;
}
case 2: {
// 计算切比雪夫距离
const x = Math.abs(current.x - neighbor.x);
const y = Math.abs(current.y - neighbor.y);
const minxy = Math.min(x, y);
baseCost = x + y + (Math.sqrt(2) - 2) * minxy;
break;
}
}
// 如果存在权重地图,应用权重
if (this.weightMap && this.isValidIndex(neighbor)) {
const weight = this.weightMap[neighbor.y][neighbor.x];
return baseCost * weight;
}
return baseCost;
}
/**
* 根据给定的起始点和目标点,以及类型参数,计算启发式成本。
* @param start 起始点的索引,包含 x 和 y 坐标。
* @param end 目标点的索引,包含 x 和 y 坐标。
* @param type 计算成本的类型0 表示曼哈顿距离1 表示欧几里得距离2 表示切比雪夫距离,默认为 0。
* @returns 返回根据指定类型计算出的启发式成本。
*/
private getHeuristicCost(start: index, end: index, type: number = 0) {
switch (type) {
case 0: {
// 计算曼哈顿距离
return Math.abs(start.x - end.x) + Math.abs(start.y - end.y);
}
case 1: {
// 计算欧几里得距离
return Math.sqrt(Math.pow(start.x - end.x, 2) + Math.pow(start.y - end.y, 2));
}
case 2: {
// 计算切比雪夫距离
const x = Math.abs(start.x - end.x);
const y = Math.abs(start.y - end.y);
const minxy = Math.min(x, y);
return x + y + (Math.sqrt(2) - 2) * minxy;
}
}
}
/**
* 检查节点是否在封闭列表中。
* @param node 节点坐标
* @returns {boolean} 如果节点在封闭列表中返回true否则返回false
*/
private isInClosedList(node: index): boolean {
// 遍历封闭列表查找节点
let _index = -1;
for (let i = 0; i < this.closelist.length; i++) {
if (this.closelist[i].x == node.x && this.closelist[i].y == node.y) {
_index = i;
break;
}
}
return _index != -1;
}
/**
* 检查节点是否在开放列表中。
* @param node 节点坐标
* @returns {boolean} 如果节点在开放列表中返回true否则返回false
*/
private isInOpenList(node: index): boolean {
// 遍历开放列表查找节点
let _index = -1;
for (let i = 0; i < this.openlist.length; i++) {
if (this.openlist[i].x == node.x && this.openlist[i].y == node.y) {
_index = i;
break;
}
}
return _index != -1;
}
/**
* 获取节点的成本。
* @param node 节点坐标
* @returns 节点的总成本
*/
private getCost(node: index): number {
let gcost = 0;
let hcost = 0;
this.gcostMap.forEach((value, key) => {
if (key.x == node.x && key.y == node.y) {
gcost = value;
}
});
this.hcostMap.forEach((value, key) => {
if (key.x == node.x && key.y == node.y) {
hcost = value;
}
});
return gcost + hcost;
}
/**
* 获取开放列表中成本最小的节点。
* @param list 开放列表
* @returns 成本最小的节点
*/
private getMinCostNode(list: index[]): index {
let _minindex = -1;
let _mincost = Number.MAX_SAFE_INTEGER;
// 寻找成本最小的节点
for (let i = 0; i < list.length; i++) {
const cost = this.getCost(list[i]);
if (cost < _mincost) {
_minindex = i;
_mincost = cost;
}
}
return list[_minindex];
}
/**
* 更新节点的成本和父节点信息。
* @param node 节点坐标
* @param gcost 从起点到当前节点的实际成本
* @param hcost 从当前节点到终点的估算成本
*/
private updateCost(node: index, gcost: number, hcost: number) {
this.gcostMap.set(node, gcost);
this.hcostMap.set(node, hcost);
}
/**
* 更新节点的父节点。
* @param node 节点坐标
* @param parent 父节点坐标
*/
private updateParent(node: index, parent: index) {
const existingparent = this.parentMap.get(node);
// 仅当新的父节点成本更低时更新
if (!existingparent || this.getCost(parent) < this.getCost(existingparent)) {
this.parentMap.set(node, parent);
}
}
/**
* 根据父节点映射重构路径。
* @param endPoint 终点坐标
* @returns 从起点到终点的路径
*/
private reconstructPath(endPoint: index) {
const path = [endPoint];
let currentnode = endPoint;
// 逆向回溯路径
while (currentnode) {
let parent = null;
this.parentMap.forEach((value, key) => {
if (currentnode.x == key.x && currentnode.y == key.y) {
parent = value;
}
})
if (parent) {
path.unshift(parent);
currentnode = parent;
} else {
currentnode = null;
}
}
return path;
}
/**
* 检查给定的索引是否为有效索引。
* @param index 一个包含x和y属性的对象代表要检查的索引位置。
* @returns 返回一个布尔值如果索引位置有效则为true否则为false。
*/
private isValidIndex(index: index): boolean {
return index.x >= 0 && index.x < this.map[0].length && index.y >= 0 && index.y < this.map.length;
}
/**
* 判断当前节点是否到达了目标节点。
* @param node 一个包含x和y属性的对象代表当前节点的位置。
* @param end 一个包含x和y属性的对象代表目标节点的位置。
* @returns 返回一个布尔值如果当前节点已到达目标节点则为true否则为false。
*/
private isArrived(node: index, end: index) {
// 比较当前节点和目标节点的坐标,判断是否已经到达目标位置
return node.x == end.x && node.y == end.y;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "0da25f34-2c17-4ebe-a9d6-1a4c2c03a99b",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,185 @@
import { AudioClip, Node, AudioSource, tween } from "cc";
import { ResModel } from "../model/ResModel";
import { LoadTools } from "./LoadTools";
/** 声音相关工具类 */
export class AudioTools {
/** 单例模式 */
private static _instance: AudioTools = new AudioTools();
private constructor() { }
public static get _ins() {
return this._instance;
}
private audioDic: Map<string, AudioSource> = new Map();
private audioVolumeDic: Map<string, number> = new Map();
private audioPermanentDic: Map<AudioSource, boolean> = new Map();
bgAudio: AudioSource; //背景音乐
isPlayAudio: boolean = true; //是否播放音效
isPlayBG: boolean = true; //是否播放音乐
/** 播放背景音乐 */
playBG(audioUrl: string, value = 0.5) {
if (!this.isPlayBG) { return; }
if (ResModel._ins.AudioClipDic.get(audioUrl) != null) {
this.bgAudio = this.newAudioSource(ResModel._ins.AudioClipDic.get(audioUrl), value, true);
this.audioDic.set(audioUrl, this.bgAudio);
this.audioVolumeDic.set(audioUrl, value);
this.audioPermanentDic.set(this.bgAudio, true);
return this.bgAudio;
} else {
LoadTools._ins.loadResAny('music/' + audioUrl + '.mp3', AudioClip, (audio: AudioClip) => {
this.bgAudio = this.newAudioSource(audio, value, true);
this.audioDic.set(audioUrl, this.bgAudio);
this.audioVolumeDic.set(audioUrl, value);
this.audioPermanentDic.set(this.bgAudio, true);
return this.bgAudio;
});
}
};
/**
* 播放游戏音效
* @param audioUrl 音效文件的res/music/的路径 或者 resArr拖动的名字
* @param value 音量大小
* @param isLoop 是否循环播放
* @param isPermanent 是否永久播放
*/
playAudio(audioUrl: string, value = 0.5, isLoop = false, isPermanent = false) {
if (!this.isPlayAudio) { return; }
if (ResModel._ins.AudioClipDic.get(audioUrl) != null) {
let audioE = this.newAudioSource(ResModel._ins.AudioClipDic.get(audioUrl), value, isLoop);
this.audioDic.set(audioUrl, audioE);
this.audioVolumeDic.set(audioUrl, value);
this.audioPermanentDic.set(audioE, isPermanent);
return audioE;
} else {
LoadTools._ins.loadResAny('music/' + audioUrl + '.mp3', AudioClip, (audio: AudioClip) => {
let audioE = this.newAudioSource(audio, value, isLoop);
this.audioDic.set(audioUrl, audioE);
this.audioVolumeDic.set(audioUrl, value);
this.audioPermanentDic.set(audioE, isPermanent);
return audioE;
});
}
};
/** 停止播放某个音效 */
stopAudio(audioName: string) {
let audioE = this.audioDic.get(audioName);
if (audioE != null) {
audioE.stop();
}
}
/**
* 新建一个audioSource 来播放音效
* @param audioUrl 音效文件的res/music/的路径 或者 resArr拖动的名字
* @param value 音量大小
* @param isLoop 是否循环播放
*/
playAudioSource(audioUrl: string, value = 0.5, isLoop = false) {
if (!this.isPlayAudio) { return; }
if (ResModel._ins.AudioClipDic.get(audioUrl) != null) {
return this.newAudioSource(ResModel._ins.AudioClipDic.get(audioUrl), value, isLoop);
} else {
LoadTools._ins.loadResAny(audioUrl, AudioClip, (audioE: AudioClip) => {
this.newAudioSource(audioE, value, isLoop);
});
}
}
/** 新建一个 audioSource 播放音效 */
newAudioSource(audioClip: AudioClip, value = 0.5, isLoop = false) {
if (!this.isPlayAudio) { return; }
let node = new Node();
let audioE = node.addComponent(AudioSource);
audioE.clip = audioClip;
audioE.loop = isLoop;
audioE.volume = value;
audioE.play();
if (isLoop == false) {
tween(node).delay(audioE.duration + 0.1)
.removeSelf().union().start();
}
return audioE;
};
/** 停止所有音效 */
stopAllAudio() {
this.isPlayAudio = false;
this.isPlayBG = false;
for (let audioE of this.audioDic.values()) {
audioE.stop();
}
}
/** 恢复所有音效 */
resumeAllAudio() {
for (let audioE of this.audioDic.values()) {
if (this.audioPermanentDic.get(audioE) && !audioE.playing) {
audioE.play();
}
audioE.volume = this.audioVolumeDic.get(audioE.clip.name);
}
this.isPlayAudio = true;
this.isPlayBG = true;
}
/**
* 恢复指定音效
* @param audioName 音效文件的res/music/的路径 或者 resArr拖动的名字
*/
resumeAudioByName(audioName: string) {
let audioE = this.audioDic.get(audioName);
if (audioE != null) {
if (!audioE.playing) {
audioE.play();
}
audioE.volume = this.audioVolumeDic.get(audioE.clip.name);
}
}
/**
* 设置指定音效的音量
* @param audioName 音效文件的res/music/的路径 或者 resArr拖动的名字
* @param value 音量大小
*/
setAudioVolume(audioName: string, value: number) {
let audioE = this.audioDic.get(audioName);
if (audioE != null) {
audioE.volume = value;
this.audioVolumeDic.set(audioName, value);
}
}
/**
* 设置指定音效的循环播放
* @param audioName 音效文件的res/music/的路径 或者 resArr拖动的名字
* @param isLoop 是否循环播放
*/
setAudioLoop(audioName: string, isLoop: boolean) {
let audioE = this.audioDic.get(audioName);
if (audioE != null) {
audioE.loop = isLoop;
}
}
/**
* 设置指定音效的静音
* @param audioName 音效文件的res/music/的路径 或者 resArr拖动的名字
*/
muteAudio(audioName: string) {
let audioE = this.audioDic.get(audioName);
if (audioE != null) {
audioE.volume = 0.0;
}
}
/**
* 设置所有音效的静音
*/
muteAllAudio() {
for (let audioE of this.audioDic.values()) {
audioE.volume = 0.0;
}
this.isPlayAudio = false;
this.isPlayBG = false;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "b2bc325c-94d6-4223-8d5a-918cbdadfd93",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,98 @@
class Queue<T> {
private items: T[];
constructor() {
this.items = [];
}
enqueue(item: T): void {
this.items.push(item);
}
dequeue(): T | undefined {
return this.items.shift();
}
isEmpty(): boolean {
return this.items.length === 0;
}
}
type index = {
x: number;
y: number;
}
export class BFSPathfinding {
private map: number[][];
private visited: boolean[][];
private rows: number;
private cols: number;
private directions: index[];
constructor() {
this.map = [];
this.rows = 0;
this.cols = 0;
this.visited = [];
this.directions = [];
}
setMap(map: number[][]) {
this.map = map;
this.rows = this.map.length;
this.cols = this.map[0].length;
this.visited = Array.from({ length: this.rows }, () => Array(this.cols).fill(false));
this.directions = [{ x: 0, y: -1 }, { x: 0, y: 1 }, { x: -1, y: 0 }, { x: 1, y: 0 }];
}
findPath(start: index, end: index): index[] {
if (this.map[start.y][start.x] !== 0 ||
this.map[end.y][end.x] !== 0) {
return [];
}
const queue = new Queue<index>();
const prev: index[][] = Array.from({ length: this.rows }, () => Array(this.cols).fill(null));
queue.enqueue(start);
this.visited[start.y][start.x] = true;
while (!queue.isEmpty()) {
const current = queue.dequeue()!;
if (current.x === end.x && current.y === end.y) {
return this.constructPath(prev, start, end);
}
for (const direction of this.directions) {
const nextX = current.x + direction.x;
const nextY = current.y + direction.y;
if (this.isValid(nextX, nextY) && this.map[nextY][nextX] === 0 && !this.visited[nextY][nextX]) {
queue.enqueue({ x: nextX, y: nextY });
this.visited[nextY][nextX] = true;
prev[nextY][nextX] = current;
}
}
}
return [];
}
private isValid(x: number, y: number): boolean {
return x >= 0 && x < this.cols && y >= 0 && y < this.rows;
}
private constructPath(prev: index[][], start: index, end: index): index[] {
const path: index[] = [];
let current = end;
while (current !== start) {
path.unshift(current);
current = prev[current.y][current.x]!;
}
path.unshift(start);
return path;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "8ac0c6a2-e192-4b14-8cbe-97c0f60d1c1e",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,281 @@
import { director, Node, instantiate, Prefab, Vec3, v3, SpriteFrame, Sprite, AssetManager, resources, assetManager, AudioClip, Material, Texture2D, Label } from "cc";
import { ResModel } from "../model/ResModel";
import { weiSan } from "./weiSanTools";
import { EventManager, EventData } from "../manager/EventManager";
import { PoolManager } from "../manager/PoolManager";
/** 加载资源相关工具类 */
export class LoadTools {
/** 单例模式 */
private static _instance: LoadTools = new LoadTools();
private constructor() { }
public static get _ins() {
return this._instance;
}
/**
* 加载游戏场景
* @param sceneName 加载场景的名字
* @param callFunc 加载回调
*/
loadScene(sceneName: string, callFunc: any, isClear = true) {
if (isClear) {
ResModel._ins.clearResDic();
}
director.preloadScene(sceneName, () => {
director.loadScene(sceneName, callFunc);
});
};
/**
* 加载resource 下的预制体 资源
* @param url resource 下的资源路径
* @param callBack 加载完成回调
*/
loadResPrefab(url: string, callBack?: any, parent?: Node, Pos?: Vec3) {
this.loadResAny(url, Prefab, (prefab: Prefab) => {
let clone = instantiate(prefab);
if (parent) { parent.addChild(clone) };
if (Pos) { clone.position = v3(Pos.x, Pos.y, 0) };
if (callBack != null) {
callBack(clone);
}
})
}
/**
* 加载resource 下的图片资源并渲染到节点上
* @param url resource 下的资源路径
* @param callBack 加载完成回调
*/
loadResSpriteFrame(url: string, sprite: Node, parent?: Node, Pos?: Vec3, callBack?: any) {
resources.load(url + "/spriteFrame", SpriteFrame, function (error: any, SpriteFrame: SpriteFrame) {
if (error) {
weiSan.error(error);
} else {
sprite.getComponent(Sprite).spriteFrame = SpriteFrame;
if (parent) { parent.addChild(sprite) };
if (Pos) { sprite.position = v3(Pos.x, Pos.y, 0) };
if (callBack != null) {
callBack(sprite);
}
}
});
};
/**
* 加载resource 下的游戏资源
* @param url resource 下的资源路径
* @param resType 加载资源的类型
* @param callBack 加载完成回调
*/
loadResAny(url: string, resType: any, callBack?: any) {
resources.load(url, resType, function (error: any, res: any) {
if (error) {
weiSan.error(error);
} else {
if (callBack != null) {
callBack(res);
}
if (resType == Prefab) {
ResModel._ins.PrefabDic.set(url, res);
} else if (resType == SpriteFrame) {
if (!ResModel._ins.SpriteFrameDic.has(url)) {
ResModel._ins.SpriteFrameDic.set(url, res);
}
} else if (resType == AudioClip) {
if (!ResModel._ins.AudioClipDic.has(url)) {
ResModel._ins.AudioClipDic.set(url, res);
}
} else if (resType == Material) {
if (!ResModel._ins.MaterialDic.has(url)) {
ResModel._ins.MaterialDic.set(url, res);
}
} else if (resType == Texture2D) {
if (!ResModel._ins.TextureDic.has(url)) {
ResModel._ins.TextureDic.set(url, res);
}
} else if (resType === Prefab) {
if (!ResModel._ins.PrefabDic.has(url)) {
ResModel._ins.PrefabDic.set(url, res);
}
}
}
});
}
/** 加载bundle 场景 */
loadBundleScene(bundleName: string, sceneName: string, onFinishBack?: () => void, isInScene: boolean = true) {
assetManager.loadBundle(
bundleName,
(err: any, bundle: AssetManager.Bundle) => {
if (err) {
console.log(err);
}
else {
if (!isInScene) { return; }
bundle.loadScene(sceneName, (err, scene) => {
if (onFinishBack) {
onFinishBack();
}
director.runScene(scene);
});
}
}
);
}
/**
* 分帧加载预制体节点
* @param prefabName 要加载的预制体名称
* @param perFrameNum 每帧加载的数量
* @param totalNum 总共需要加载的数量
* @param usePool 是否使用对象池默认为true
* @param callBack 对每个创建的节点进行操作的回调函数
* @returns Promise<Node[]> 返回所有创建的节点数组
*/
loadPrefabByFrame(prefabName: string, perFrameNum: number, totalNum: number, usePool: boolean = true, callBack?: (node: Node, index: number) => void): Promise<Node[]> {
return new Promise((resolve, reject) => {
// 参数验证
if (!prefabName || prefabName.trim() === '') {
const error = 'prefabName cannot be empty';
weiSan.error(error);
reject(new Error(error));
return;
}
if (perFrameNum <= 0) {
const error = 'perFrameNum must be greater than 0';
weiSan.error(error);
reject(new Error(error));
return;
}
if (totalNum <= 0) {
const error = 'totalNum must be greater than 0';
weiSan.error(error);
reject(new Error(error));
return;
}
// 触发加载开始事件
EventManager.dispatchEvent(EventData.PREFAB_LOAD_START, {
prefabName: prefabName,
totalNum: totalNum,
usePool: usePool
});
// 创建节点的函数
const createNodeFunction = (prefab?: Prefab): Node | null => {
if (usePool) {
// 使用对象池创建节点
return PoolManager._ins.getNode(prefabName);
} else {
// 使用传统方式创建节点
if (!prefab) {
weiSan.error(`Prefab is required when not using pool: ${prefabName}`);
return null;
}
return instantiate(prefab);
}
};
if (usePool) {
// 使用对象池时,直接开始分帧创建
this.startFrameBasedCreation(prefabName, perFrameNum, totalNum, usePool, callBack, createNodeFunction, resolve, reject);
} else {
// 不使用对象池时,先加载预制体资源
this.loadResAny(prefabName, Prefab, (prefab: Prefab) => {
if (!prefab) {
const error = `Failed to load prefab: ${prefabName}`;
weiSan.error(error);
reject(new Error(error));
return;
}
this.startFrameBasedCreation(prefabName, perFrameNum, totalNum, usePool, callBack, createNodeFunction, resolve, reject, prefab);
});
}
});
}
/**
* 开始分帧创建节点的核心逻辑
*/
private startFrameBasedCreation(
prefabName: string,
perFrameNum: number,
totalNum: number,
usePool: boolean,
callBack: ((node: Node, index: number) => void) | undefined,
createNodeFunction: (prefab?: Prefab) => Node | null,
resolve: (value: Node[]) => void,
reject: (reason?: any) => void,
prefab?: Prefab
) {
// 开始分帧创建节点
const createdNodes: Node[] = [];
let currentCount = 0;
const createNodesPerFrame = () => {
const remainingCount = totalNum - currentCount;
const currentFrameCount = Math.min(perFrameNum, remainingCount);
// 创建当前帧的节点
for (let i = 0; i < currentFrameCount; i++) {
try {
const node = createNodeFunction(prefab);
if (!node) {
const error = `Failed to create node: ${prefabName}`;
weiSan.error(error);
reject(new Error(error));
return;
}
createdNodes.push(node);
// 执行回调函数
if (callBack) {
try {
callBack(node, currentCount);
} catch (callbackError) {
weiSan.warn(`Callback error for node ${currentCount}: ${callbackError}`);
}
}
currentCount++;
} catch (error) {
weiSan.error(`Error creating node instance: ${error}`);
reject(new Error(`Error creating node instance: ${error}`));
return;
}
}
// 计算进度并触发进度事件
const progress = (currentCount / totalNum) * 100;
EventManager.dispatchEvent(EventData.PREFAB_LOAD_PROGRESS, {
prefabName: prefabName,
currentNum: currentCount,
totalNum: totalNum,
progress: progress
});
// 检查是否完成
if (currentCount >= totalNum) {
// 触发完成事件
EventManager.dispatchEvent(EventData.PREFAB_LOAD_COMPLETE, {
prefabName: prefabName,
totalNum: totalNum,
nodes: createdNodes
});
weiSan.log(`Successfully loaded ${totalNum} instances of prefab: ${prefabName}`);
resolve(createdNodes);
} else {
// 继续下一帧,使用 setTimeout 来实现分帧
setTimeout(() => {
createNodesPerFrame();
}, 0);
}
};
// 开始第一帧的创建
createNodesPerFrame();
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "6a25c810-7df7-4956-9123-e14f337f08f5",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,706 @@
import { SpriteFrame, Vec3, Node, Vec2, Button, v2, sys, instantiate, game, Game, v3, Sprite, misc, UITransform, Layers, Camera, Canvas, director, Director, ImageAsset, renderer, RenderTexture, Size, Texture2D, view, sp } from "cc";
import { PlatformManager } from "../manager/PlatformManager";
import { ResModel } from "../model/ResModel";
import { LoadTools } from "./LoadTools";
import { AStar } from "./AStar";
import { BFSPathfinding } from "./BFS";
import { SplitRenderHelper } from "../SplitRender/SplitRenderHelper";
export type index = {
x: number;
y: number;
}
//@ts-ignore
game._calculateDT = function _calculateDT(useFixedDeltaTime: boolean): number {
this._useFixedDeltaTime = useFixedDeltaTime;
if (useFixedDeltaTime) {
this._startTime = performance.now();
return this.frameTime / 1000;
}
const now = performance.now();
this._deltaTime = now > this._startTime ? (now - this._startTime) / 1000 : 0;
if (this._deltaTime > Game.DEBUG_DT_THRESHOLD) {
this._deltaTime = this.frameTime / 1000;
}
this._startTime = now;
return this._deltaTime * Tools.getTimeScale();
}
/** 游戏常用工具类 */
export class Tools {
private static timeScale = 1;
private static aStar: AStar = new AStar();
private static bfs: BFSPathfinding = new BFSPathfinding();
/**
* 使用A*算法进行搜索。
* @param map 二维数字数组,代表地图或其他需要搜索的结构。
* @param start 搜索的起始点,其格式为 index 类型。
* @param end 搜索的终点,其格式为 index 类型。
* @param type 搜索类型,用数字表示,默认为 0。不同的类型可能影响搜索算法的行为。
* @returns 返回搜索结果,通常是一个路径数组或者搜索到的目标。
*/
public static aStarSearch(map: number[][], start: index, end: index, type: number = 0) {
this.aStar.setMap(map);
return this.aStar.search(start, end, type);
}
public static setaStarValue(startValue: number, endValue: number, pathValue: number) {
this.aStar.setValue(startValue, endValue, pathValue);
}
public static setaStarEightDirections(isEightDirections: boolean) {
this.aStar.setEightDirections(isEightDirections);
}
public static setaStarWeightMap(weightMap: number[][]) {
this.aStar.setWeightMap(weightMap);
}
public static setaStarNeighborMap(neighborMap: Map<index, index[]>) {
this.aStar.setNeighborMap(neighborMap);
}
/**
* 使用广度优先搜索算法在地图上寻找从起点到终点的路径。
* @param map 二维数字数组表示的地图。
* @param start 起点的索引。
* @param end 终点的索引。
* @returns 返回一个路径数组,如果不存在路径则返回空数组。
*/
public static bfsSearch(map: number[][], start: index, end: index) {
this.bfs.setMap(map); // 设置广度优先搜索对象的地图
return this.bfs.findPath(start, end); // 执行搜索并返回路径
}
/**
* 存储本地数据
* @param {*} isObject 是否是一个对象或者数组
*/
public static setStorage(key: string, value: any, isObject = false) {
PlatformManager.setStorage(key, value, isObject);
}
/**
* 获取存储数据
* @param {*} isObject 是否是一个对象或者数组
*/
public static getStorage(key: string, isObject = false) {
return PlatformManager.getStorage(key, isObject);
};
/**
* 获取时间缩放
* @returns 时间缩放
*/
public static getTimeScale() {
return Tools.timeScale;
}
/**
* 设置时间缩放
* @param scale 时间缩放
*/
public static setTimeScale(scale: number) {
Tools.timeScale = scale;
}
/**
* 获取截图
* @param node 截图的节点
* @param parent 截图的父节点
* @param pos 截图的位置
* @param canvas 默认摄像机渲染的canvas
* @param normalCamera 默认摄像机
*/
public static getScreenShot(node: Node, parent: Node, pos: Vec3, canvas: Canvas, normalCamera: Camera) {
const newCamera = new Node("PhotoCamera");
newCamera.setParent(canvas.node);
newCamera.setPosition(0, 0, 1000);
newCamera.addComponent(Camera);
newCamera.getComponent(Camera).visibility = normalCamera.visibility;
newCamera.getComponent(Camera).clearFlags = normalCamera.clearFlags;
newCamera.getComponent(Camera).near = normalCamera.near;
newCamera.getComponent(Camera).far = normalCamera.far;
newCamera.getComponent(Camera).projection = renderer.scene.CameraProjection.ORTHO;
newCamera.getComponent(Camera).orthoHeight = normalCamera.orthoHeight;
const newRenderTexture = new RenderTexture();
newRenderTexture.reset({
width: view.getVisibleSize().width,
height: view.getVisibleSize().height
});
newCamera.getComponent(Camera).targetTexture = newRenderTexture;
director.once(Director.EVENT_AFTER_DRAW, () => {
const newSpriteFrame = new SpriteFrame();
let data = newRenderTexture.readPixels(Math.round(node.getWorldPosition().x - node.getComponent(UITransform).width / 2 * node.scale.x),
Math.round(node.getWorldPosition().y - node.getComponent(UITransform).height / 2 * node.scale.y),
node.getComponent(UITransform).width * node.scale.x, node.getComponent(UITransform).height * node.scale.y)
let image = new ImageAsset();
image.reset({
_data: data,
_compressed: false,
width: node.getComponent(UITransform).width * node.scale.x,
height: node.getComponent(UITransform).height * node.scale.y,
format: Texture2D.PixelFormat.RGBA8888
})
let newTexture = new Texture2D();
newTexture.image = image;
newSpriteFrame.texture = newTexture;
newSpriteFrame.packable = false;
if (sys.isNative && (sys.os === sys.OS.IOS || sys.os === sys.OS.OSX)) {
newSpriteFrame.flipUVY = false;
} else {
newSpriteFrame.flipUVY = true;
}
let newSprite = new Node("PhotoSprite");
newSprite.addComponent(Sprite);
newSprite.setParent(parent);
newSprite.setPosition(pos);
newSprite.layer = Layers.Enum.UI_2D;
newSprite.getComponent(UITransform)
.setContentSize(new Size(node.getComponent(UITransform).width,
node.getComponent(UITransform).height));
newSprite.getComponent(Sprite).spriteFrame = newSpriteFrame;
newCamera.getComponent(Camera).targetTexture = null;
})
}
/**
* 保存文件。
* @param textToWrite 要保存的文件内容
* @param fileNameToSaveAs 要保存的文件名
* @param fileType 要保存的文件格式,默认为Json
*/
public static saveForBrowser(textToWrite: any, fileNameToSaveAs: string, fileType: string = 'application/json') {
if (sys.isBrowser) {
console.log("浏览器");
let textFileAsBlob = new Blob([textToWrite], { type: fileType });
let downloadLink = document.createElement("a");
downloadLink.download = fileNameToSaveAs;
downloadLink.innerHTML = "Download File";
downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
downloadLink.click();
}
}
/**
* 获取spine指定动画时间,如果没有该动画 则返回0
* @param spine 骨骼动画
* @param aniName 动画名称
* @returns 动画时间
*/
public static getSpineAnimationTime(spine: sp.Skeleton, aniName: string) {
const state = spine.getState();
if (state == undefined) throw `[ERROR SPINE ANIMATION] 无法获取获取动画状态`;
const { animations } = state.data.skeletonData;
let result = 0;
for (const key in animations) {
if (Object.prototype.hasOwnProperty.call(animations, key)) {
const element = animations[key];
if (element.name == aniName) {
result = element.duration;
}
}
}
return result;
}
//-----------------------------节点预制体相关-------------------------------
/**
* 新建一个预制体在场景里
* @param preName 预制体名字或url
* @param callFunc 加载预制体 完成后回调
* @param parent 存放预制体的父节点
* @param Pos 预制体的坐标
* @param zIndex 预制体的层级
*/
public static newPrefab(preName: string, parent?: Node, Pos?: Vec3, callFunc?: (age?: Node) => void): Node {
return NodeTools._ins.newPrefab(preName, callFunc, parent, Pos);
}
/**
* 新建一个图片在场景里
* @param sprName 图片名字或url
* @param callFunc 加载预制体 完成后回调
* @param parent 存放预制体的父节点
* @param Pos 预制体的坐标
* @param zIndex 预制体的层级
*/
public static newSprite(sprName: string, parent?: Node, Pos?: Vec3, callFunc?: (age?: Node) => void): Node {
return NodeTools._ins.newSprite(sprName, callFunc, parent, Pos);
}
/**
* 设置一个节点的SpriteFrame
* @param nodeT 节点的Node
* @param sprUrl 图片的url或者存放到resArr的名字
*/
public static setSpriteFrame(nodeT: Node, sprUrl: string) {
NodeTools._ins.setSpriteFrame(nodeT, sprUrl);
}
/** 设置一个节点的 groupIndex 包含子物体 */
public static setNodeLayerIndex(nodeT: Node, layer: Layers.Enum) {
NodeTools._ins.setNodeLayerIndex(nodeT, layer);
}
/**
* 设置一个Button的按下和松开的SpriteFrame
* @param norUrl 默认状态的名字或者路径
* @param preUrl 按下状态的名字或者路径
*/
public static setBtnClickSpr(Btn: Button, norUrl: string, preUrl: string) {
NodeTools._ins.setBtnClickSpr(Btn, norUrl, preUrl);
};
/** 切换父物体 不改变显示位置*/
public static setNodeParent(node: Node, parent: Node) {
NodeTools._ins.setNodeParent(node, parent);
};
//----------------------------------数学数组相关----------------------------------
/**
* 将多维数组展平
* @param arr 需要展平的多维数组
* @returns 展平后的数组
*/
public static flatArray(arr: any[]) {
return arr.reduce((acc, curr) => {
return acc.concat(Array.isArray(curr) ? Tools.flatArray(curr) : curr);
}, []);
}
/**
* 从数组中随机获取元素
* @param arr 需要随机获取元素的数组
* @param num 需要获取的元素数量
* @param sortFunc 排序函数,可选
* @returns 返回随机获取的元素数组
*/
public static randomGetElementFromArray(arr: any[], num: number, sortFunc: (a: any, b: any) => number = null) {
const tempArr = arr.slice();
const resultArr = [];
while (resultArr.length < num) {
const randomIndex = Tools.random(0, tempArr.length - 1);
resultArr.push(tempArr[randomIndex]);
tempArr.splice(randomIndex, 1);
}
if (sortFunc) {
resultArr.sort(sortFunc);
}
return resultArr;
}
/**
* 获取随机数
* @param isInteger 是否随机整数 默认整数
*/
public static random(x1: number, x2: number, isInteger = true): number {
return MathTools._ins.random(x1, x2, isInteger);
}
/**
* 根据概率数组 随机概率 返回数组的index
* @param chooseArr 需要随机概率的数组 例如[0.05,0.1,0.2,0.3]
*/
public static chooseRandom(chooseArr: Array<number>) {
return MathTools._ins.chooseRandom(chooseArr);
}
/** 传入一个弧度 返回一个Y轴折射后的弧度 */
public static refractionY(rad: number) {
return MathTools._ins.refractionY(rad);
};
/** 传入一个弧度 返回一个轴折射后的弧度 */
public static refractionX(rad: number) {
return MathTools._ins.refractionX(rad);
};
/** 重新打乱一个数组的顺序 洗牌 */
public static againSortArr(Arr: Array<any>) {
MathTools._ins.againSortArr(Arr);
};
/**
* 将一个数组 按照里面的对象排序
* @param tempArr 传入的数组
* @param sortName 对象属性名字
* @param isReverse 是否倒序
*/
public static sortArrForObject(tempArr: Array<any>, sortName: string, isReverse = false) {
MathTools._ins.sortArrForObject(tempArr, sortName, isReverse);
};
/**
* 取一定范围内不重复的数字
* @param minNum 最小取值范围
* @param maxNum 最大取值范围
* @param getNum 取几个数字
*/
public static getDiffNumRandom(minNum: number, maxNum: number, getNum: number) {
return MathTools._ins.getDiffNumRandom(minNum, maxNum, getNum);
};
//--------------------------------向量坐标计算相关------------------------------------
/**
* 根据两个点 求角度
* @param pos1 起始点坐标
* @param pos2 结束点坐标
* @param isVertical 是否以竖直方向为0度开始
*/
public static getAngleForPos(pos1: Vec2, pos2: Vec2, isVertical = false): number {
return VecTools._ins.getAngleForPos(pos1, pos2, isVertical);
};
/** 获取两个坐标之间的距离 */
public static getDistance(pos1: Vec3 | Vec2, pos2: Vec3 | Vec2): number {
if (pos1 instanceof Vec2 && pos2 instanceof Vec2) {
return Vec2.distance(pos1, pos2);
}
if (pos1 instanceof Vec3 && pos2 instanceof Vec3) {
return Vec3.distance(pos1, pos2);
}
};
/**
* 根据一个角度和长度 计算相对应的坐标
* @param angle 角度
* @param len 该角度上的长度
* @param startPos 初始的坐标
*/
public static getPosForAngleLen(angle: number, len: number, startPos: Vec2 = v2(0, 0)) {
return VecTools._ins.getPosForAngleLen(angle, len, startPos);
}
/**
* 获取节点在另一个节点下的坐标
* @param obj 节点
* @param mainObj 相对于的另一个节点
*/
public static getToNodePosForNode(obj: Node, mainObj: Node): Vec2 {
return VecTools._ins.getToNodePosForNode(obj, mainObj);
};
/** 获取节点的世界坐标 */
public static getToWorldPosAR(obj: Node) {
return VecTools._ins.getToWorldPosAR(obj);
}
/**
* 通过世界坐标 获取相对节点的坐标
* @param worldPos 世界坐标
* @param obj 相对节点下的
*/
public static getToNodePosForWorld(worldPos: Vec3, obj: Node) {
return VecTools._ins.getToNodePosForWorld(worldPos, obj);
}
/** 二维向量转三维向量 */
public static getVec3ForVec2(vec2: Vec2) {
return VecTools._ins.getVec3ForVec2(vec2);
}
/** 三维向量转二维向量 */
public static getVec2ForVec3(vec3: Vec3) {
return VecTools._ins.getVec2ForVec3(vec3);
}
/** 获取两向量方向 */
public static getDirection(startPos: Vec3 | Vec2, endPos: Vec3 | Vec2) {
return VecTools._ins.getDirection(startPos, endPos);
}
/** 获取多边形面积 */
public static getPolygonArea(polygon: Vec2[]) {
return VecTools._ins.getPolygonArea(polygon);
}
//--------------------------------数组操作相关------------------------------------
/** 根据value值 从数组里面移除 */
public static removeArrForValue(tempArr: Array<any>, value: any) {
return tempArr.splice(tempArr.indexOf(value), 1);
}
/** 从数组里面添加一个该数组里没有的元素 */
public static addArrNoValue(tempArr: Array<any>, value: any) {
if (tempArr.indexOf(value) < 0) {
tempArr.push(value);
return true;
}
return false;
}
/** 从数组指定位置 插入某个元素 */
public static addArrIndex(tempArr: Array<any>, index: number, value: any) {
return tempArr.splice(index, 0, value);
}
//--------------------------------其他------------------------------------
/**
* 字符串指定位置插入新字符
* @param source 需要操作的字符串
* @param start 从那个位置开始插入
* @param newStr 插入的新的字符
*/
public static insertStrForIndex(source: string, start: number, newStr: string): string {
return source.slice(0, start) + newStr + source.slice(start);
};
/**
* 数字整数前边补零 并返回字符串
* @param num 传入的数字
* @param length 前边补几个零
*/
public static prefixInteger(num: number, length = 2): string {
return (Array(length).join('0') + num).slice(-length);
};
/** 获取系统语言 */
public static getLanguageType(): string {
var langNumType = "EN"; //默认英语
if (sys.language == sys.Language.CHINESE) {
if (sys.languageCode.toLowerCase().indexOf("zh-cn") != -1 ||
sys.languageCode.toLowerCase().indexOf("zh_cn") != -1 ||
sys.languageCode.toLowerCase().indexOf("zh-hans-cn") != -1) {
langNumType = "CN"; //简体
} else {
langNumType = "CHT"; //繁体
}
}
// else if ( sys.language == sys.Language.KOREAN ) {
// langNumType = "KOR"; //韩语
// }
// else if (sys.language == sys.Language.JAPANESE) {
// langNumType = "JP"; //日语
// }
// else if ( window.navigator.language == "th-TH" ) {
// langNumType = "TH"; //泰语
// }
return langNumType;
}
}
/** 节点相关 工具类 */
class NodeTools {
/** 单例模式 */
private static _instance: NodeTools = new NodeTools();
private constructor() { }
public static get _ins() {
return this._instance;
}
/** 新建一个预制体在场景里 */
public newPrefab(preName: string, callFunc?: (age?: Node) => void, parent?: Node, Pos?: Vec3): Node {
let prefab = ResModel._ins.PrefabDic.get(preName);
let clone: Node = null;
if (prefab != null) {
clone = instantiate(prefab);
if (parent) { parent.addChild(clone) };
if (Pos) { clone.position = v3(Pos.x, Pos.y, Pos.z) };
if (callFunc != null) {
callFunc(clone);
}
} else {
LoadTools._ins.loadResPrefab(preName, callFunc, parent, Pos);
}
return clone;
}
/** 新建一个图片在场景里 */
public newSprite(sprName: string, callFunc?: (age?: Node) => void, parent?: Node, Pos?: Vec3) {
let sprite = new Node();
sprite.name = sprName;
sprite.layer = Layers.Enum.UI_2D;
if (ResModel._ins.SpriteFrameDic.get(sprName) != null) {
sprite.addComponent(Sprite).spriteFrame = ResModel._ins.SpriteFrameDic.get(sprName);
if (parent) { parent.addChild(sprite) };
if (Pos) { sprite.position = v3(Pos.x, Pos.y, Pos.z) };
if (callFunc != null) {
callFunc(sprite);
}
} else {
sprite.addComponent(Sprite);
LoadTools._ins.loadResSpriteFrame(sprName, sprite, parent, Pos, callFunc);
}
return sprite;
}
/** 设置一个节点的SpriteFrame */
public setSpriteFrame(nodeT: Node, sprUrl: string) {
if (nodeT.getComponent(Sprite) == null) {
nodeT.addComponent(Sprite);
}
if (ResModel._ins.SpriteFrameDic.get(sprUrl)) {
nodeT.getComponent(Sprite).spriteFrame = ResModel._ins.SpriteFrameDic.get(sprUrl)
} else {
LoadTools._ins.loadResAny(sprUrl, SpriteFrame, (spriteFrame: SpriteFrame) => {
nodeT.getComponent(Sprite).spriteFrame = spriteFrame;
})
}
}
/** 设置一个节点的 所属层 包含子物体 */
public setNodeLayerIndex(nodeT: Node, layer: Layers.Enum) {
nodeT.layer = layer;
for (let i = 0; i < nodeT.children.length; i++) {
this.setNodeLayerIndex(nodeT.children[i], layer);
}
}
/** 设置一个Button的按下和松开的SpriteFrame */
public setBtnClickSpr(Btn: Button, norUrl: string, preUrl: string) {
if (ResModel._ins.SpriteFrameDic.get(norUrl)) {
Btn.getComponent(Button).normalSprite = ResModel._ins.SpriteFrameDic.get(norUrl)
Btn.getComponent(Button).hoverSprite = ResModel._ins.SpriteFrameDic.get(norUrl)
Btn.getComponent(Button).pressedSprite = ResModel._ins.SpriteFrameDic.get(preUrl)
} else {
LoadTools._ins.loadResAny(norUrl, SpriteFrame, (spr: SpriteFrame) => {
Btn.getComponent(Button).normalSprite = spr;
Btn.getComponent(Button).hoverSprite = spr;
});
LoadTools._ins.loadResAny(preUrl, SpriteFrame, (spr: SpriteFrame) => {
Btn.getComponent(Button).pressedSprite = spr;
});
}
};
/** 切换父物体 不改变坐标 */
public setNodeParent(node: Node, parent: Node) {
let Pos = VecTools._ins.getToNodePosForNode(node, parent);
node.parent = parent;
node.position = v3(Pos.x, Pos.y);
};
}
/** 数学数组计算相关 工具类 */
class MathTools {
/** 单例模式 */
private static _instance: MathTools = new MathTools();
private constructor() { }
public static get _ins() {
return this._instance;
}
/** 获取随机数 */
public random(x1: number, x2: number, isInteger = true): number {
if (isInteger) {
return x1 + Math.floor(Math.random() * (x2 - x1 + 1));
}
return Math.random() * (x2 - x1) + x1;
}
/** 根据概率数组 随机概率 返回数组的index */
public chooseRandom(chooseArr: Array<number>) {
let total = 0; //概率总值
//首先计算出概率的总值,用来计算随机范围
for (let i = 0; i < chooseArr.length; i++) {
total += chooseArr[i];
}
let randNum = this.random(0, total, false)
for (let i = 0; i < chooseArr.length; i++) {
if (randNum < chooseArr[i] && chooseArr[i] > 0) {
return i;
} else {
randNum -= chooseArr[i];
}
}
return chooseArr.length - 1;
}
/** 弧度折射Y轴 */
public refractionY(rad: number) {
return Math.atan2(Math.sin(rad), -Math.cos(rad));
};
/** 弧度折射X轴 */
public refractionX(rad: number) {
return Math.atan2(-Math.sin(rad), Math.cos(rad));
};
/** 重新洗牌 一个数组 */
public againSortArr(Arr: Array<any>) {
for (let i = 0; i < Arr.length; i++) {
let tempR = Tools.random(0, Arr.length - 1);
if (tempR != i) {
let temp = Arr[i];
Arr[i] = Arr[tempR];
Arr[tempR] = temp;
}
}
}
/** 数组 对象排序 对象属性 是否倒序 */
public sortArrForObject(tempArr: Array<any>, sortName: string, isReverse = false) {
if (!isReverse) {
tempArr.sort((a, b) => {
return a[sortName] - b[sortName];
});
} else {
tempArr.sort((a, b) => {
return b[sortName] - a[sortName];
});
}
};
/** 取一定范围内不重复的数字 */
public getDiffNumRandom(minNum: number, maxNum: number, getNum: number) {
var arr = [];
for (let i = minNum; i <= maxNum; i++) {
arr.push(i);
}
const tempLen = arr.length - getNum;
for (let i = 0; i < tempLen; i++) {
let tempI = Tools.random(0, arr.length - 1);
arr.splice(tempI, 1);
}
return arr;
};
}
/** 向量坐标转换相关工具类 */
class VecTools {
/** 单例模式 */
private static _instance: VecTools = new VecTools();
private constructor() { }
public static get _ins() {
return this._instance;
}
/** 根据两个点 求角度 */
public getAngleForPos(pos1: Vec2, pos2: Vec2, isVertical = false): number {
let rad = 0;
if (isVertical) {
rad = -Math.atan2(pos2.x - pos1.x, pos2.y - pos1.y);
} else {
rad = Math.atan2(pos2.y - pos1.y, pos2.x - pos1.x);
}
return misc.radiansToDegrees(rad);
}
/** 根据一个角度和长度 计算相对应的坐标 */
public getPosForAngleLen(angle: number, len: number, startPos: Vec2 = v2(0, 0)) {
let rad = misc.degreesToRadians(angle);
return v2(startPos.x + Math.cos(rad) * len, startPos.y + Math.sin(rad) * len);
}
/** 获取节点在另一个节点下的坐标 */
public getToNodePosForNode(obj: Node, mainObj: Node): Vec2 {
let worldPos = obj.parent.getComponent(UITransform).convertToWorldSpaceAR(obj.position);
let nodePos = mainObj.getComponent(UITransform).convertToNodeSpaceAR(worldPos)
return v2(nodePos.x, nodePos.y);
};
/** 获取节点的世界坐标 */
public getToWorldPosAR(obj: Node) {
return obj.parent.getComponent(UITransform).convertToWorldSpaceAR(obj.position);
}
/** 通过世界坐标 获取相对节点的坐标 */
public getToNodePosForWorld(worldPos: Vec3, obj: Node) {
return obj.getComponent(UITransform).convertToNodeSpaceAR(worldPos);
}
/** 二维向量转三维向量 */
public getVec3ForVec2(vec2: Vec2) {
return v3(vec2.x, vec2.y, 0);
}
/** 三维向量转二维向量 */
public getVec2ForVec3(vec3: Vec3) {
return v2(vec3.x, vec3.y);
}
/** 获取两向量方向和距离
* @param startPos 起始位置
* @param endPos 结束位置
*/
public getDirection(startPos: Vec3 | Vec2, endPos: Vec3 | Vec2) {
if (startPos instanceof Vec2 && endPos instanceof Vec2) {
const deltaPos = endPos.clone().subtract(startPos);
const direction = deltaPos.normalize();
return direction;
} else if (startPos instanceof Vec3 && endPos instanceof Vec3) {
const deltaPos = endPos.clone().subtract(startPos);
const direction = deltaPos.normalize();
return direction;
}
}
public getPolygonArea(polygon: Vec2[]) {
return SplitRenderHelper.calculatePolygonArea(polygon);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "f3cbf87f-aa09-459e-8527-cd6f1be98ffb",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,31 @@
export class weiSan {
/** 是否开启 Log 信息 */
private static isLog = true;
private static logName:string = "微伞游戏Log:"
private static logInfo:string = "本游戏包含的所有内容(包括但不限于:代码、图片、视像及声音内容、名称)的所有权归北京米兜科技有限公司所有。任何单位或个人将本游戏提供的内容与服务用于商业、盈利、广告性等目的时,需征得北京米兜科技有限公司相关权利人的书面许可;将本网站提供的内容与服务用于非商业用途时,应遵守著作权法以及其他相关法律的规定,不得侵犯游戏所有者及相关权利人的权益。"
/** 普通log信息 */
public static log(...data: any[]): void {
if (!this.isLog) { return; }
console.log(this.logName,...data);
}
/** 追踪函数调用的log */
public static logTrace(...data: any[]){
if (!this.isLog) { return; }
console.trace(this.logName,...data);
}
/** 打印错误log信息 */
public static error(...data: any[]): void {
if (!this.isLog) { return; }
console.error(this.logName,...data);
}
/** 打印警告log信息 */
public static warn(...data: any[]): void {
if (!this.isLog) { return; }
console.warn(this.logName,...data);
}
public static initLog(){
console.log(this.logInfo);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "289a2b50-88c3-4705-9e74-63d767daaefb",
"files": [],
"subMetas": {},
"userData": {}
}