[add] first
This commit is contained in:
234
assets/script/framework/audioManager.ts
Normal file
234
assets/script/framework/audioManager.ts
Normal file
@@ -0,0 +1,234 @@
|
||||
import { _decorator, Node, AudioClip, AudioSource, director } from "cc";
|
||||
import { StorageManager } from "./storageManager";
|
||||
import { ResourceUtil } from "./resourceUtil";
|
||||
import { Lodash } from './lodash';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
interface AudioData {
|
||||
source: AudioSource;
|
||||
isMusic: boolean;
|
||||
}
|
||||
|
||||
interface AudioDataMap {
|
||||
[name: string]: AudioData;
|
||||
}
|
||||
|
||||
@ccclass("AudioManager")
|
||||
export class AudioManager {
|
||||
private _persistRootNode: Node = null!;
|
||||
private _audioSources: AudioSource[] = [];
|
||||
static _instance: AudioManager;
|
||||
dictWeaponSoundIndex: any = {};
|
||||
|
||||
static get instance() {
|
||||
if (this._instance) {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
this._instance = new AudioManager();
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
musicVolume: number = 0.8;
|
||||
soundVolume: number = 1;
|
||||
audios: AudioDataMap = {};
|
||||
arrSound: AudioData[] = [];
|
||||
|
||||
init() {
|
||||
if (this._persistRootNode) return; //避免切换场景初始化报错
|
||||
this._persistRootNode = new Node('audio');
|
||||
this.openAudio();
|
||||
director.getScene()!.addChild(this._persistRootNode);
|
||||
director.addPersistRootNode(this._persistRootNode)
|
||||
|
||||
this.musicVolume = this.getAudioSetting(true) ? 0.8 : 0;
|
||||
this.soundVolume = this.getAudioSetting(false) ? 1 : 0;
|
||||
}
|
||||
|
||||
private _getAudioSource(clip: AudioClip) {
|
||||
let result: AudioSource | undefined;
|
||||
for (let i = 0; i < this._audioSources.length; ++i) {
|
||||
let audioSource = this._audioSources[i];
|
||||
if (!audioSource.playing) {
|
||||
result = audioSource;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
result = this._persistRootNode.addComponent(AudioSource);
|
||||
result.playOnAwake = false;
|
||||
this._audioSources.push(result);
|
||||
}
|
||||
result.node.off(AudioSource.EventType.ENDED);
|
||||
result.clip = clip;
|
||||
result.currentTime = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
getAudioSetting(isMusic: boolean) {
|
||||
let state;
|
||||
if (isMusic) {
|
||||
state = StorageManager.instance.getGlobalData('music');
|
||||
} else {
|
||||
state = StorageManager.instance.getGlobalData('sound');
|
||||
}
|
||||
|
||||
return !state || state === 'true' ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音乐
|
||||
* @param {String} name 音乐名称可通过Constant.AUDIO_MUSIC 获取
|
||||
* @param {Boolean} loop 是否循环播放
|
||||
*/
|
||||
playMusic(name: string, loop: boolean) {
|
||||
let path = 'audio/music/' + name;
|
||||
ResourceUtil.loadRes(path, AudioClip, (err: any, clip: any) => {
|
||||
let source = this._getAudioSource(clip);
|
||||
let tmp: AudioData = {
|
||||
source,
|
||||
isMusic: true,
|
||||
};
|
||||
this.audios[name] = tmp;
|
||||
source.volume = this.musicVolume;
|
||||
source.loop = loop;
|
||||
source.play();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音效
|
||||
* @param {String} name 音效名称可通过Constant.AUDIO_SOUND 获取
|
||||
* @param {Boolean} loop 是否循环播放
|
||||
*/
|
||||
playSound(name: string, loop: boolean = false) {
|
||||
if (!this.soundVolume) {
|
||||
return;
|
||||
}
|
||||
|
||||
//音效一般是多个的,不会只有一个
|
||||
let path = 'audio/sound/';
|
||||
ResourceUtil.loadRes(path + name, AudioClip, (err: any, clip: any) => {
|
||||
let source = this._getAudioSource(clip);
|
||||
let tmp: AudioData = {
|
||||
source,
|
||||
isMusic: false,
|
||||
};
|
||||
this.arrSound.push(tmp);
|
||||
|
||||
if (loop) {
|
||||
this.audios[name] = tmp;
|
||||
}
|
||||
|
||||
source.volume = this.soundVolume;
|
||||
source.loop = loop;
|
||||
source.play();
|
||||
|
||||
source.node.on(AudioSource.EventType.ENDED, () => {
|
||||
Lodash.remove(this.arrSound, (obj: AudioData) => {
|
||||
return obj.source === tmp.source;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
stop(name: string) {
|
||||
if (this.audios.hasOwnProperty(name)) {
|
||||
let audio = this.audios[name];
|
||||
audio.source.stop();
|
||||
}
|
||||
}
|
||||
|
||||
stopAll() {
|
||||
for (const i in this.audios) {
|
||||
if (this.audios.hasOwnProperty(i)) {
|
||||
let audio = this.audios[i];
|
||||
audio.source.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
getMusicVolume() {
|
||||
return this.musicVolume;
|
||||
}
|
||||
|
||||
setMusic(flag: number) {
|
||||
this.musicVolume = flag;
|
||||
for (let item in this.audios) {
|
||||
if (this.audios.hasOwnProperty(item) && this.audios[item].isMusic) {
|
||||
let audio = this.audios[item];
|
||||
audio.source.volume = this.musicVolume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//看广告时先将音乐暂停
|
||||
pauseAll() {
|
||||
for (let item in this.audios) {
|
||||
if (this.audios.hasOwnProperty(item)) {
|
||||
let audio = this.audios[item];
|
||||
audio.source.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resumeAll() {
|
||||
for (let item in this.audios) {
|
||||
if (this.audios.hasOwnProperty(item)) {
|
||||
let audio = this.audios[item];
|
||||
audio.source.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openMusic() {
|
||||
this.setMusic(0.8);
|
||||
StorageManager.instance.setGlobalData('music', 'true');
|
||||
}
|
||||
|
||||
closeMusic() {
|
||||
this.setMusic(0);
|
||||
StorageManager.instance.setGlobalData('music', 'false');
|
||||
}
|
||||
|
||||
openSound() {
|
||||
this.setSound(1);
|
||||
StorageManager.instance.setGlobalData('sound', 'true');
|
||||
}
|
||||
|
||||
closeSound() {
|
||||
this.setSound(0);
|
||||
StorageManager.instance.setGlobalData('sound', 'false');
|
||||
}
|
||||
|
||||
openAudio() {
|
||||
this.openMusic();
|
||||
this.openSound();
|
||||
}
|
||||
|
||||
closeAudio() {
|
||||
this.closeMusic();
|
||||
this.closeSound();
|
||||
}
|
||||
|
||||
setSound(flag: number) {
|
||||
this.soundVolume = flag;
|
||||
for (let item in this.audios) {
|
||||
if (this.audios.hasOwnProperty(item) && !this.audios[item].isMusic) {
|
||||
let audio = this.audios[item];
|
||||
audio.source.volume = this.soundVolume;
|
||||
}
|
||||
}
|
||||
|
||||
for (let idx = 0; idx < this.arrSound.length; idx++) {
|
||||
let audio = this.arrSound[idx];
|
||||
audio.source.volume = this.soundVolume;
|
||||
}
|
||||
}
|
||||
|
||||
stopSingleSound(name: string) {
|
||||
if (this.audios.hasOwnProperty(name) && !this.audios[name].isMusic) {
|
||||
let audio = this.audios[name];
|
||||
audio.source.stop();
|
||||
}
|
||||
}
|
||||
}
|
11
assets/script/framework/audioManager.ts.meta
Normal file
11
assets/script/framework/audioManager.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "5e2ec645-1091-441e-80a0-c7a9575581c1",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
80
assets/script/framework/clientEvent.ts
Normal file
80
assets/script/framework/clientEvent.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { _decorator } from "cc";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("ClientEvent")
|
||||
export class ClientEvent {
|
||||
private static _handlers: { [key: string]: any[] } = {};
|
||||
|
||||
/**
|
||||
* 监听事件
|
||||
* @param {string} eventName 事件名称
|
||||
* @param {function} handler 监听函数
|
||||
* @param {object} target 监听目标
|
||||
*/
|
||||
public static on (eventName: string, handler: Function, target: any) {
|
||||
var objHandler: {} = {handler: handler, target: target};
|
||||
var handlerList: Array<any> = ClientEvent._handlers[eventName];
|
||||
if (!handlerList) {
|
||||
handlerList = [];
|
||||
ClientEvent._handlers[eventName] = handlerList;
|
||||
}
|
||||
|
||||
for (var i = 0; i < handlerList.length; i++) {
|
||||
if (!handlerList[i]) {
|
||||
handlerList[i] = objHandler;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
handlerList.push(objHandler);
|
||||
return handlerList.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消监听
|
||||
* @param {string} eventName 监听事件
|
||||
* @param {function} handler 监听函数
|
||||
* @param {object} target 监听目标
|
||||
*/
|
||||
public static off (eventName: string, handler: Function, target: any) {
|
||||
var handlerList = ClientEvent._handlers[eventName];
|
||||
|
||||
if (!handlerList) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < handlerList.length; i++) {
|
||||
var oldObj = handlerList[i];
|
||||
if (oldObj.handler === handler && (!target || target === oldObj.target)) {
|
||||
handlerList.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 分发事件
|
||||
* @param {string} eventName 分发事件名
|
||||
* @param {...any} params 分发事件参数
|
||||
*/
|
||||
public static dispatchEvent (eventName: string, ...args: any) {
|
||||
var handlerList = ClientEvent._handlers[eventName];
|
||||
|
||||
var args1 = [];
|
||||
var i;
|
||||
for (i = 1; i < arguments.length; i++) {
|
||||
args1.push(arguments[i]);
|
||||
}
|
||||
|
||||
if (!handlerList) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < handlerList.length; i++) {
|
||||
var objHandler = handlerList[i];
|
||||
if (objHandler.handler) {
|
||||
objHandler.handler.apply(objHandler.target, args1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
11
assets/script/framework/clientEvent.ts.meta
Normal file
11
assets/script/framework/clientEvent.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e55dbcc1-367d-4d52-b87c-af9ceeb2f099",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
282
assets/script/framework/constant.ts
Normal file
282
assets/script/framework/constant.ts
Normal file
@@ -0,0 +1,282 @@
|
||||
import { Enum } from "cc";
|
||||
export class Constant {
|
||||
public static GAME_NAME = 'Coin';
|
||||
public static GAME_VERSION = '1.0.1';
|
||||
public static GAME_FRAME = 60; //游戏当前帧率
|
||||
public static GAME_INIT_FRAME = 60; //游戏开发基础帧率
|
||||
|
||||
//本地缓存key值
|
||||
public static LOCAL_CACHE = {
|
||||
PLAYER: 'player', //玩家基础数据缓存,如金币砖石等信息,暂时由客户端存储,后续改由服务端管理
|
||||
SETTINGS: 'settings', //设置相关,所有杂项都丢里面进去
|
||||
DATA_VERSION: 'dataVersion', //数据版本
|
||||
ACCOUNT: 'account', //玩家账号
|
||||
// TMP_DATA: 'tmpData', //临时数据,不会存储到云盘
|
||||
HISTORY: "history", //关卡通关数据
|
||||
BAG: "bag", //玩家背包,即道具列表,字典类型
|
||||
}
|
||||
|
||||
static PTM_RATIO = 1;
|
||||
|
||||
static GAME_OBJ_TYPE = { // 二进制位
|
||||
PLAYER: 1,
|
||||
COIN: 2
|
||||
};
|
||||
|
||||
static ACTION = {
|
||||
MOVE: 1,
|
||||
STOP_MOVE: 2,//停止移动但是不转向敌人
|
||||
GAME_START: 3,
|
||||
GAME_OVER: 4,
|
||||
READY: 5,
|
||||
HEART_BEAT: 6,
|
||||
UPDATE_POS: 8,
|
||||
VIBRATE: 9,
|
||||
RUN: 13,
|
||||
IDLE: 14,
|
||||
IS_ATTACK_ED: 12,//被攻击
|
||||
HIT: 7,
|
||||
ICON: 15,
|
||||
HAMMER: 16,
|
||||
CREATE_HAMMER: 17,
|
||||
CREATE_ICON: 18,
|
||||
}
|
||||
|
||||
static NETWORK_STATUS = {
|
||||
COMMON_OFFLINE: 0,
|
||||
COMMON_ONLINE: 1,
|
||||
RELAY_OFFLINE: 2,
|
||||
RELAY_ONLINE: 3,
|
||||
}
|
||||
|
||||
static FRAME_SYNC_STATE = {
|
||||
STOP: 0,
|
||||
START: 1
|
||||
}
|
||||
|
||||
static COIN_TYPE = Enum({
|
||||
COIN: 1,
|
||||
PROP: 2
|
||||
});
|
||||
|
||||
static ADD_SIZE_PER_COIN = 0.03; //每1个金币 体积增加 5%
|
||||
static MIN_SPEED_PERCENT = 0.2; //最低速度降低百分比
|
||||
|
||||
static INIT_MOVE_SPEED = 20; //初始移动速度
|
||||
|
||||
static GAME_TIME = 60; //游戏时间60 * 4秒
|
||||
|
||||
static MIN_PLAYER = 2;//玩家最少人数
|
||||
static MAX_PLAYER = 2;//玩家最多人数
|
||||
|
||||
static EVENT_NAME = {
|
||||
ON_GET_ROOM_INFO: 'onGetRoomInfo', //获取到房间信息
|
||||
ON_RECV_SYNC:'onRecvSync', //帧同步数据
|
||||
ON_GAME_READY: 'onGameReady', //游戏准备开始
|
||||
ON_GAME_START: 'onGameStart', //开始游戏
|
||||
ON_GAME_321: 'onGame321', //开始游戏
|
||||
ON_GAME_END: 'onGameEnd', //结束游戏
|
||||
ON_SHOW_COIN_TIPS: "showCoinTips", //显示金币提示
|
||||
ON_OTHER_JOIN_ROOM: 'onOtherJoinRoom', //加入房间
|
||||
|
||||
SEND_MSG: 'sendMsg', //收到消息
|
||||
SEND_MSG_HEIGHT: 'sendMsgHeight', //收到消息
|
||||
SEND_VT: 'sendVt', //收到消息
|
||||
|
||||
OPEN_MEDIA: 'openMedia', //收到消息
|
||||
OPEN_CHANNEL: 'openChannel', //收到消息
|
||||
IS_TOUCH: 'is_touch', // 触摸
|
||||
GAME_INIT: 'game_init',
|
||||
|
||||
INIT_MEDIA: 'init_media', // 语音准备
|
||||
INIT_CHANNEL: 'init_channel', // channel准备
|
||||
CREATE_HAMMER: 'create_hammer', // channel准备
|
||||
CREATE_COIN: 'create_coin', // channel准备
|
||||
DIS_JOIN: 'dis_join', // channel准备
|
||||
|
||||
|
||||
OPEN_PGS: 'openPgs', // 开启社区
|
||||
|
||||
HUAWEI_LOGIN_MSG : 'huawei_login_msg', // 华为初始化
|
||||
}
|
||||
|
||||
static PANEL_NAME = {
|
||||
READY: 'fight/ready', //准备界面
|
||||
GAME_OVER: 'fight/gameOver',//结算界面
|
||||
FIGHT_UI: 'fight/fightUI', //结算界面
|
||||
READY_GO: 'fight/readyGo', //结算界面
|
||||
START_GAME: 'fight/startPanel', //开始游戏
|
||||
SELECT_GAME: 'fight/selectPanel', //选择界面
|
||||
TIP_PANEL: 'fight/tipPanel', //离开界面
|
||||
JOIN_ROOM_PANEL: 'fight/joinRoomPanel', //加入房间
|
||||
MATCH_PANEL: 'fight/matchPanel', //匹配界面
|
||||
TRANSITION:'fight/transitionPanel', // 过度界面
|
||||
TRANSITION_BG:'fight/transitionBgPanel', // 过度界面
|
||||
MESSAGE_PANEL:'fight/messagePanel', // 消息面板
|
||||
DOWNOFF_PANEL:'fight/downOffPanel', // 断线
|
||||
MEDIA_PANEL:'fight/mediaPanel', // 对话
|
||||
}
|
||||
|
||||
static SCENE_NAME = {
|
||||
FIGHT : "fight",
|
||||
START : "start",
|
||||
SLECT : "select"
|
||||
}
|
||||
|
||||
static AUDIO_NAME = {
|
||||
BACKGROUND: 'background', //背景音乐
|
||||
WIN: 'win', //胜利音效
|
||||
GO: 'go', //游戏开始音效
|
||||
TICK: 'tick', //倒计时音效
|
||||
TIME_OUT: 'timeout', //时间到音效
|
||||
GOLD: 'gold' ,//金币音效
|
||||
HIT: 'hit', //击中音效
|
||||
}
|
||||
|
||||
static EFFECT_NAME = {
|
||||
RUNNING: 'running', //跑步特效
|
||||
WIN: "leaveWinAni",
|
||||
TRANSITION: "transition07", //过场动画
|
||||
}
|
||||
|
||||
//道具类型
|
||||
static PROP_TYPE = {
|
||||
TO_SELF: "toSelf",//对己
|
||||
TO_ENEMY: "toEnemy",//对敌人
|
||||
}
|
||||
|
||||
//玩家动画类型
|
||||
static ANI_TYPE = {
|
||||
IDLE: 'idle',//普通待机
|
||||
RUN: 'run',//空手跑
|
||||
RUN_1: 'run1',//拿着锤子跑
|
||||
VICTORY: "victory",//胜利
|
||||
LOSE: "lose",//失败,哭泣,播放一次后播放lose1循环
|
||||
LOSE_1: "lose1",//失败,哭泣循环
|
||||
ATTACK: 'attack',//锤子攻击
|
||||
HIT: "hit",//被击中,先播放一次,再播放dizzy循环
|
||||
DIZZY: 'dizzy',//被击中眩晕
|
||||
}
|
||||
|
||||
public static EASY_TOUCH = {
|
||||
TOUCH_LEFT_X: 'touchLeftX', // 左手 x
|
||||
TOUCH_LEFT_Y: 'touchLeftY', // 左右 y
|
||||
TOUCH_RIGHT_X: 'touchRightX', // 右手 x
|
||||
TOUCH_RIGHT_Y: 'touchRightY', // 右手 y
|
||||
}
|
||||
|
||||
static PROP_DISAPPEAR_TIME = 10;//道具10秒后回收
|
||||
|
||||
static READY_PREFAB = {
|
||||
GIRL_MODEL: "fight/girlUI", //ui上显示的女生模型
|
||||
BOY_MODEL: "fight/boyUI", //ui上显示的男生模型
|
||||
JOIN_EFFECT: "joinEff", //加入房间特效
|
||||
VS_EFFECT: "vsAni" , //开始特效
|
||||
}
|
||||
|
||||
static ROOM_TIPS = {
|
||||
CREATE: "创建房间。。。",
|
||||
WAITING: "请稍等,房主正在创建房间。。。",
|
||||
LEAVE: "您的对手已经离开房间。。。",
|
||||
IN_ROOM: "已在房间内。。。",
|
||||
CREATE_ROOM_ERROR: "创建房间失败",
|
||||
JOIN_ROOM_ERROR: "加入房间失败",
|
||||
NO_ROOM_ID:"请输入正确的房间号",
|
||||
LEAVE_ROOM_ERROR:"离开房间出错",
|
||||
LEAVE_ROOM_MSG : "确认退出房间?",
|
||||
LEAVE_ROOM_SUCCESS : "成功离开房间",
|
||||
JOIN_ROOM_SUCCESS : "成功加入房间",
|
||||
MATCH_ROOM_ERROR : "匹配房间出错",
|
||||
PLAYER_LENGHT_ERROR : "长度需要大于2",
|
||||
LEAVE_GAME : "是否退出游戏?",
|
||||
INPUT_MSG : "请输入文字",
|
||||
VT_ERROR:"未识别到语音",
|
||||
PLAYER_LEAVE_1:"队友离开队伍,",
|
||||
PLAYER_LEAVE_2:"秒游戏结束",
|
||||
INIT_FAIL:"登录失败",
|
||||
MEDIA_FAIL:"语音权限不足,语音未开启",
|
||||
WORLD_LABEL:"世界频道",
|
||||
ROOM_LABEL:"房间号:",
|
||||
LOGIN_GAME_ERROR:"进入场景异常,请重试",
|
||||
HUA_WEI_LOAGIN_ERROR:"华为登录失败,请改用普通账号登录"
|
||||
}
|
||||
|
||||
static PLAYER_ORIGIN_SCALE = 1.5;//玩家初始缩放大小
|
||||
|
||||
static WORLD_ID = "cocosworldid00000"
|
||||
|
||||
static DIZZY_TIME = 1; //被榴莲击中后眩晕时间
|
||||
static HAMMER_TIME = 15; //锤子生成时间,每隔15秒
|
||||
|
||||
static AUTO_GEN_COIN = { //自动生成金币相关
|
||||
SECOND_PER_TIMES: 1, //每多少秒触发一次
|
||||
COIN_PER_TIMES: 1, //每次生成几个金币
|
||||
START_NUM: 10, //金币数量小于指定个数,开始自动生成
|
||||
END_NUM: 20 //金币数量大于指定个数,停止生成
|
||||
}
|
||||
|
||||
static REVIVE_TIME = 0.5; //复活时间
|
||||
static INIT_COLLIDER_CIRCLE = 0.8; //初始的人物碰撞矩形框
|
||||
static HAMMER_TIMES = 1; //锤子可用次数
|
||||
|
||||
static AI_PLAYER_ID = "ai00000";
|
||||
|
||||
static AI_PLAYER = 1;
|
||||
|
||||
static HAMMER_POS:number[][]= [
|
||||
[0, 0, 0],
|
||||
[-28, 0, -25],
|
||||
[28, 0, -25],
|
||||
[23, 0, 23],
|
||||
[-28, 0, 23]
|
||||
];
|
||||
|
||||
static AI_SPEED : number = 0.22;
|
||||
|
||||
static AI_POS_INDEX : number[][] = [
|
||||
[1, 26, 27, 19], // 初始化
|
||||
[2, 26, 19], // Cube-001
|
||||
[1, 3, 22], // Cube-002
|
||||
[2, 4, 23], // 3
|
||||
[3, 24, 5], // 4.......
|
||||
[6, 25, 4], // 5
|
||||
[5, 7, 20], //6 ..........
|
||||
[25, 8, 23, 6], // 7
|
||||
[10, 11, 18, 17], // 8
|
||||
[23, 22], // 9
|
||||
[13, 11, 18, 9], // 10
|
||||
[10, 17, 12, 28], // 11
|
||||
[11, 16, 13], // 12
|
||||
[10, 12, 15], // 13
|
||||
[13, 15, 16, 12], // 14
|
||||
[18, 16, 28, 9], // 15
|
||||
[15, 17, 28, 9], // 16
|
||||
[18, 16, 28, 9], // 17
|
||||
[15, 17, 28, 9], // 18
|
||||
[1, 27, 20], // 19
|
||||
[6, 21, 19], // 20
|
||||
[7, 14, 22, 20], // 21
|
||||
[23, 2, 14, 21, 2], // 22
|
||||
[7, 8, 22, 3, 4], // 23
|
||||
[25, 23], // 24
|
||||
[7, 24], // 25 ..............
|
||||
[27, 19, 22], // 26
|
||||
[21, 26, 19], // 27
|
||||
[7, 21], // 28
|
||||
];
|
||||
|
||||
static HUAWEI_LOGIN = {
|
||||
SIGN_IN_SUCCESS : 0, // 账号登录成功
|
||||
INIT_SUCCESS : 10000, // 初始化成功
|
||||
INIT_UNDER_AGE : 10001, // 未成年人登录
|
||||
INIT_ERROR : 10002, // 初始化报错
|
||||
SIGN_IN_ERROR : 10003, // 登录报错
|
||||
NO_HUAWEI : 10004 // 非华为手机
|
||||
}
|
||||
|
||||
static START_GAME :string = 'startGame';
|
||||
|
||||
static DISMISS :string = 'dismiss';
|
||||
|
||||
static START_GAME_TIME :string = 'start_game_time';
|
||||
}
|
11
assets/script/framework/constant.ts.meta
Normal file
11
assets/script/framework/constant.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "b08f0f24-88e9-4403-b7ba-a9459aec09c0",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
628
assets/script/framework/csvManager.ts
Normal file
628
assets/script/framework/csvManager.ts
Normal file
@@ -0,0 +1,628 @@
|
||||
import { _decorator } from "cc";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
var CELL_DELIMITERS = [",", ";", "\t", "|", "^"];
|
||||
var LINE_DELIMITERS = ["\r\n", "\r", "\n"];
|
||||
|
||||
var getterCast = function(value: any, index: any, cast: any, d: any) {
|
||||
|
||||
if (cast instanceof Array) {
|
||||
if (cast[index] === "number") {
|
||||
return Number(d[index]);
|
||||
} else if (cast[index] === "boolean") {
|
||||
return d[index] === "true" || d[index] === "t" || d[index] === "1";
|
||||
} else {
|
||||
return d[index];
|
||||
}
|
||||
} else {
|
||||
if (!isNaN(Number(value))) {
|
||||
return Number(d[index]);
|
||||
} else if (value == "false" || value == "true" || value == "t" || value == "f") {
|
||||
return d[index] === "true" || d[index] === "t" || d[index] === "1";
|
||||
} else {
|
||||
return d[index];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var CSV = {
|
||||
//
|
||||
|
||||
/* =========================================
|
||||
* Constants ===============================
|
||||
* ========================================= */
|
||||
|
||||
STANDARD_DECODE_OPTS: {
|
||||
skip: 0,
|
||||
limit: false,
|
||||
header: false,
|
||||
cast: false,
|
||||
comment: ""
|
||||
},
|
||||
|
||||
STANDARD_ENCODE_OPTS: {
|
||||
delimiter: CELL_DELIMITERS[0],
|
||||
newline: LINE_DELIMITERS[0],
|
||||
skip: 0,
|
||||
limit: false,
|
||||
header: false
|
||||
},
|
||||
|
||||
quoteMark: '"',
|
||||
doubleQuoteMark: '""',
|
||||
quoteRegex: /"/g,
|
||||
|
||||
/* =========================================
|
||||
* Utility Functions =======================
|
||||
* ========================================= */
|
||||
assign: function () {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var base = args[0];
|
||||
var rest = args.slice(1);
|
||||
for (var i = 0, len = rest.length; i < len; i++) {
|
||||
for (var attr in rest[i]) {
|
||||
base[attr] = rest[i][attr];
|
||||
}
|
||||
}
|
||||
|
||||
return base;
|
||||
},
|
||||
|
||||
map: function (collection: any, fn: Function) {
|
||||
var results = [];
|
||||
for (var i = 0, len = collection.length; i < len; i++) {
|
||||
results[i] = fn(collection[i], i);
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
getType: function (obj: any) {
|
||||
return Object.prototype.toString.call(obj).slice(8, -1);
|
||||
},
|
||||
|
||||
getLimit: function (limit: any, len: any) {
|
||||
return limit === false ? len : limit;
|
||||
},
|
||||
|
||||
buildObjectConstructor: function(fields: any, sample: any, cast: any) {
|
||||
return function(d: any) {
|
||||
var object: any = new Object();
|
||||
var setter = function(attr: any, value: any) {
|
||||
return object[attr] = value;
|
||||
};
|
||||
if (cast) {
|
||||
fields.forEach(function(attr: any, idx: number) {
|
||||
setter(attr, getterCast(sample[idx], idx, cast, d));
|
||||
});
|
||||
} else {
|
||||
fields.forEach(function(attr: any, idx: number) {
|
||||
setter(attr, getterCast(sample[idx], idx, null, d));
|
||||
});
|
||||
}
|
||||
// body.push("return object;");
|
||||
// body.join(";\n");
|
||||
return object;
|
||||
};
|
||||
},
|
||||
|
||||
buildArrayConstructor: function(fields: any, sample: any, cast: any) {
|
||||
return function(d: any) {
|
||||
var row = new Array(sample.length);
|
||||
var setter = function(idx: any, value: any) {
|
||||
return row[idx] = value;
|
||||
};
|
||||
if (cast) {
|
||||
fields.forEach(function(attr: any, idx: number) {
|
||||
setter(attr, getterCast(sample[idx], idx, cast, d));
|
||||
});
|
||||
} else {
|
||||
fields.forEach(function(attr: any, idx: number) {
|
||||
setter(attr, getterCast(sample[idx], idx, null, d));
|
||||
});
|
||||
}
|
||||
return row;
|
||||
};
|
||||
},
|
||||
|
||||
frequency: function (coll: any, needle: any, limit: any) {
|
||||
if (limit === void 0) limit = false;
|
||||
|
||||
var count = 0;
|
||||
var lastIndex = 0;
|
||||
var maxIndex = this.getLimit(limit, coll.length);
|
||||
|
||||
while (lastIndex < maxIndex) {
|
||||
lastIndex = coll.indexOf(needle, lastIndex);
|
||||
if (lastIndex === -1) break;
|
||||
lastIndex += 1;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
},
|
||||
|
||||
mostFrequent: function (coll: any, needles: any, limit: any) {
|
||||
var max = 0;
|
||||
var detected;
|
||||
|
||||
for (var cur = needles.length - 1; cur >= 0; cur--) {
|
||||
if (this.frequency(coll, needles[cur], limit) > max) {
|
||||
detected = needles[cur];
|
||||
}
|
||||
}
|
||||
|
||||
return detected || needles[0];
|
||||
},
|
||||
|
||||
unsafeParse: function (text: any, opts: any, fn: any) {
|
||||
var lines = text.split(opts.newline);
|
||||
|
||||
if (opts.skip > 0) {
|
||||
lines.splice(opts.skip);
|
||||
}
|
||||
|
||||
var fields;
|
||||
var constructor;
|
||||
|
||||
function cells(lines: any) {
|
||||
var line = lines.shift();
|
||||
if (line.indexOf('"') >= 0) {// 含引号
|
||||
|
||||
// 找到这行完整的数据, 找到对称的双引号
|
||||
var lastIndex = 0;
|
||||
var findIndex = 0;
|
||||
var count = 0;
|
||||
while (lines.length > 0) {
|
||||
lastIndex = line.indexOf('"', findIndex);
|
||||
if (lastIndex === -1 && count % 2 === 0) break;
|
||||
|
||||
if (lastIndex !== -1) {
|
||||
findIndex = lastIndex + 1;
|
||||
count++;
|
||||
} else {
|
||||
line = line + opts.newline + lines.shift();
|
||||
}
|
||||
}
|
||||
|
||||
var list = [];
|
||||
var item;
|
||||
|
||||
var quoteCount = 0;
|
||||
|
||||
var start = 0;
|
||||
var end = 0;
|
||||
var length = line.length;
|
||||
for (var key in line) {
|
||||
if (!line.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let numKey = parseInt(key);
|
||||
var value = line[key];
|
||||
|
||||
if (numKey === 0 && value === '"') {
|
||||
quoteCount++;
|
||||
start = 1;
|
||||
}
|
||||
|
||||
if (value === '"') {
|
||||
quoteCount++;
|
||||
|
||||
if (line[numKey - 1] === opts.delimiter && start === numKey) {
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
if (value === '"' && quoteCount % 2 === 0) {
|
||||
|
||||
if (line[numKey + 1] === opts.delimiter || numKey + 1 === length) {
|
||||
end = numKey;
|
||||
item = line.substring(start, end);
|
||||
list.push(item);
|
||||
start = end + 2;
|
||||
end = start;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (value === opts.delimiter && quoteCount % 2 === 0) {
|
||||
end = numKey;
|
||||
if (end > start) {
|
||||
item = line.substring(start, end);
|
||||
list.push(item);
|
||||
start = end + 1;
|
||||
end = start;
|
||||
} else if (end === start) {
|
||||
list.push("");
|
||||
start = end + 1;
|
||||
end = start;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end = length;
|
||||
|
||||
if (end >= start) {
|
||||
item = line.substring(start, end);
|
||||
list.push(item);
|
||||
}
|
||||
|
||||
return list;
|
||||
} else {
|
||||
return line.split(opts.delimiter);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.header) {
|
||||
if (opts.header === true) {
|
||||
opts.comment = cells(lines); // 第一行是注释
|
||||
opts.cast = cells(lines); // 第二行是数据类型
|
||||
fields = cells(lines);
|
||||
} else if (this.getType(opts.header) === "Array") {
|
||||
fields = opts.header;
|
||||
}
|
||||
|
||||
constructor = this.buildObjectConstructor(fields, lines[0].split(opts.delimiter), opts.cast);
|
||||
} else {
|
||||
constructor = this.buildArrayConstructor(fields, lines[0].split(opts.delimiter), opts.cast);
|
||||
}
|
||||
|
||||
while (lines.length > 0) {
|
||||
var row = cells(lines);
|
||||
if (row.length > 1) {
|
||||
fn(constructor(row), fields[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
safeParse: function (text: any, opts: any, fn: Function) {
|
||||
var delimiter = opts.delimiter;
|
||||
var newline = opts.newline;
|
||||
|
||||
var lines = text.split(newline);
|
||||
if (opts.skip > 0) {
|
||||
lines.splice(opts.skip);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
encodeCells: function (line: any, delimiter: any, newline: any) {
|
||||
var row = line.slice(0);
|
||||
for (var i = 0, len = row.length; i < len; i++) {
|
||||
if (row[i].indexOf(this.quoteMark) !== -1) {
|
||||
row[i] = row[i].replace(this.quoteRegex, this.doubleQuoteMark);
|
||||
}
|
||||
|
||||
if (row[i].indexOf(delimiter) !== -1 || row[i].indexOf(newline) !== -1) {
|
||||
row[i] = this.quoteMark + row[i] + this.quoteMark;
|
||||
}
|
||||
}
|
||||
|
||||
return row.join(delimiter);
|
||||
},
|
||||
|
||||
encodeArrays: function(coll: any, opts: any, fn: Function) {
|
||||
var delimiter = opts.delimiter;
|
||||
var newline = opts.newline;
|
||||
|
||||
if (opts.header && this.getType(opts.header) === "Array") {
|
||||
fn(this.encodeCells(opts.header, delimiter, newline));
|
||||
}
|
||||
|
||||
for (var cur = 0, lim = this.getLimit(opts.limit, coll.length); cur < lim; cur++) {
|
||||
fn(this.encodeCells(coll[cur], delimiter, newline));
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
encodeObjects: function (coll: any, opts: any, fn:Function) {
|
||||
var delimiter = opts.delimiter;
|
||||
var newline = opts.newline;
|
||||
var header;
|
||||
var row;
|
||||
|
||||
header = [];
|
||||
row = [];
|
||||
for (var key in coll[0]) {
|
||||
header.push(key);
|
||||
row.push(coll[0][key]);
|
||||
}
|
||||
|
||||
if (opts.header === true) {
|
||||
fn(this.encodeCells(header, delimiter, newline));
|
||||
} else if (this.getType(opts.header) === "Array") {
|
||||
fn(this.encodeCells(opts.header, delimiter, newline));
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
fn(this.encodeCells(row, delimiter));
|
||||
|
||||
for (var cur = 1, lim = this.getLimit(opts.limit, coll.length); cur < lim; cur++) {
|
||||
row = [];
|
||||
for (var key$1 = 0, len = header.length; key$1 < len; key$1++) {
|
||||
row.push(coll[cur][header[key$1]]);
|
||||
}
|
||||
|
||||
fn(this.encodeCells(row, delimiter, newline));
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
parse: function (text: any, opts: any, fn: Function) {
|
||||
var rows: any;
|
||||
|
||||
if (this.getType(opts) === "Function") {
|
||||
fn = opts;
|
||||
opts = {};
|
||||
} else if (this.getType(fn) !== "Function") {
|
||||
rows = [];
|
||||
fn = rows.push.bind(rows);
|
||||
} else {
|
||||
rows = [];
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
opts = this.assign({}, this.STANDARD_DECODE_OPTS, opts);
|
||||
//@ts-ignore
|
||||
this.opts = opts;
|
||||
|
||||
if (!opts.delimiter || !opts.newline) {
|
||||
var limit = Math.min(48, Math.floor(text.length / 20), text.length);
|
||||
opts.delimiter = opts.delimiter || this.mostFrequent(text, CELL_DELIMITERS, limit);
|
||||
opts.newline = opts.newline || this.mostFrequent(text, LINE_DELIMITERS, limit);
|
||||
}
|
||||
|
||||
// modify by jl 由表自行控制不要含有双引号.提高解析效率
|
||||
return this.unsafeParse(text, opts, fn) &&
|
||||
(rows.length > 0 ? rows : true);
|
||||
},
|
||||
|
||||
encode: function (coll: any, opts: any, fn: Function) {
|
||||
var lines: any;
|
||||
|
||||
if (this.getType(opts) === "Function") {
|
||||
fn = opts;
|
||||
opts = {};
|
||||
} else if (this.getType(fn) !== "Function") {
|
||||
lines = [];
|
||||
fn = lines.push.bind(lines);
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
opts = this.assign({}, this.STANDARD_ENCODE_OPTS, opts);
|
||||
|
||||
if (opts.skip > 0) {
|
||||
coll = coll.slice(opts.skip);
|
||||
}
|
||||
|
||||
return (this.getType(coll[0]) === "Array" ? this.encodeArrays : this.encodeObjects)(coll, opts, fn) &&
|
||||
(lines.length > 0 ? lines.join(opts.newline) : true);
|
||||
}
|
||||
};
|
||||
|
||||
@ccclass("CSVManager")
|
||||
export class CSVManager {
|
||||
/* class member could be defined like this */
|
||||
|
||||
static _instance: CSVManager;
|
||||
|
||||
static get instance () {
|
||||
if (this._instance) {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
this._instance = new CSVManager();
|
||||
return this._instance;
|
||||
}
|
||||
private _csvTables:any = {};
|
||||
private _csvTableForArr:any = {};
|
||||
private _tableCast:any = {};
|
||||
private _tableComment:any = {};
|
||||
|
||||
addTable (tableName:string, tableContent:string, force?:boolean) {
|
||||
if (this._csvTables[tableName] && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tableData: any = {};
|
||||
let tableArr: any[] = [];
|
||||
let opts = { header: true };
|
||||
CSV.parse(tableContent, opts, function (row: any, keyName: string) {
|
||||
tableData[row[keyName]] = row;
|
||||
tableArr.push(row);
|
||||
});
|
||||
|
||||
this._tableCast[tableName] = (CSV as any).opts.cast;
|
||||
this._tableComment[tableName] = (CSV as any).opts.comment;
|
||||
|
||||
this._csvTables[tableName] = tableData;
|
||||
this._csvTableForArr[tableName] = tableArr;
|
||||
|
||||
//this.csvTables[tableName].initFromText(tableContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名获取表的所有内容
|
||||
* @param {string} tableName 表名
|
||||
* @returns {object} 表内容
|
||||
*/
|
||||
getTableArr (tableName:string) {
|
||||
return this._csvTableForArr[tableName];
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名获取表的所有内容
|
||||
* @param {string} tableName 表名
|
||||
* @returns {object} 表内容
|
||||
*/
|
||||
getTable (tableName:string) {
|
||||
return this._csvTables[tableName];
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询一条表内容
|
||||
* @param {string} tableName 表名
|
||||
* @param {string} key 列名
|
||||
* @param {any} value 值
|
||||
* @returns {Object} 一条表内容
|
||||
*/
|
||||
queryOne (tableName:string, key:string, value:any) {
|
||||
var table = this.getTable(tableName);
|
||||
if (!table) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (key) {
|
||||
for (var tbItem in table) {
|
||||
if (!table.hasOwnProperty(tbItem)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (table[tbItem][key] === value) {
|
||||
return table[tbItem];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return table[value];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询一条表内容
|
||||
* @param {string}tableName 表名
|
||||
* @param {string}ID
|
||||
* @returns {Object} 一条表内容
|
||||
*/
|
||||
queryByID (tableName:string, ID:string) {
|
||||
//@ts-ignore
|
||||
return this.queryOne(tableName, null, ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询key和value对应的所有行内容
|
||||
* @param {string} tableName 表名
|
||||
* @param {string} key 列名
|
||||
* @param {any} value 值
|
||||
* @returns {Object}
|
||||
*/
|
||||
queryAll (tableName:string, key:string, value:any) {
|
||||
var table = this.getTable(tableName);
|
||||
if (!table || !key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ret: any = {};
|
||||
for (var tbItem in table) {
|
||||
if (!table.hasOwnProperty(tbItem)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (table[tbItem][key] === value) {
|
||||
ret[tbItem] = table[tbItem];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 选出指定表里所有 key 的值在 values 数组中的数据,返回 Object,key 为 ID
|
||||
* @param {string} tableName 表名
|
||||
* @param {string} key 列名
|
||||
* @param {Array}values 数值
|
||||
* @returns
|
||||
*/
|
||||
queryIn (tableName:string, key:string, values:Array<any>) {
|
||||
var table = this.getTable(tableName);
|
||||
if (!table || !key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ret: any = {};
|
||||
var keys = Object.keys(table);
|
||||
var length = keys.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
var item = table[keys[i]];
|
||||
if (values.indexOf(item[key]) > -1) {
|
||||
ret[keys[i]] = item;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 选出符合条件的数据。condition key 为表格的key,value 为值的数组。返回的object,key 为数据在表格的ID,value为具体数据
|
||||
* @param {string} tableName 表名
|
||||
* @param {any} condition 筛选条件
|
||||
* @returns
|
||||
*/
|
||||
queryByCondition (tableName:string, condition: any) {
|
||||
if (condition.constructor !== Object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var table = this.getTable(tableName);
|
||||
if (!table) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ret: any = {};
|
||||
var tableKeys = Object.keys(table);
|
||||
var tableKeysLength = tableKeys.length;
|
||||
var keys = Object.keys(condition);
|
||||
var keysLength = keys.length;
|
||||
for (var i = 0; i < tableKeysLength; i++) {
|
||||
var item = table[tableKeys[i]];
|
||||
var fit = true;
|
||||
for (var j = 0; j < keysLength; j++) {
|
||||
var key = keys[j];
|
||||
fit = fit && (condition[key] === item[key]) && !ret[tableKeys[i]];
|
||||
}
|
||||
|
||||
if (fit) {
|
||||
ret[tableKeys[i]] = item;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
queryOneByCondition (tableName:string, condition: any) {
|
||||
if (condition.constructor !== Object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var table = this.getTable(tableName);
|
||||
if (!table) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var keys = Object.keys(condition);
|
||||
var keysLength = keys.length;
|
||||
|
||||
for (let keyName in table) {
|
||||
var item = table[keyName];
|
||||
|
||||
var fit = true;
|
||||
for (var j = 0; j < keysLength; j++) {
|
||||
var key = keys[j];
|
||||
fit = fit && (condition[key] === item[key]);
|
||||
}
|
||||
|
||||
if (fit) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
11
assets/script/framework/csvManager.ts.meta
Normal file
11
assets/script/framework/csvManager.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "d755406e-aa72-4b00-a89b-c15516b5ee4f",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
309
assets/script/framework/effectManager.ts
Normal file
309
assets/script/framework/effectManager.ts
Normal file
@@ -0,0 +1,309 @@
|
||||
import { _decorator, Node, Prefab, AnimationComponent, ParticleSystemComponent, Vec3, find, AnimationState, AnimationClip, director } from 'cc';
|
||||
import { PoolManager } from './poolManager';
|
||||
import { ResourceUtil } from './resourceUtil';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('EffectManager')
|
||||
export class EffectManager{
|
||||
private _ndParent: Node = null!;
|
||||
public get ndParent() {
|
||||
if (!this._ndParent) {
|
||||
let ndEffectParent = find("effectManager") as Node;
|
||||
|
||||
if (ndEffectParent) {
|
||||
this._ndParent = ndEffectParent;
|
||||
} else {
|
||||
// console.warn("请在场景里添加effectManager节点");
|
||||
this._ndParent = new Node("effectManager");
|
||||
director.getScene()?.addChild(this._ndParent);
|
||||
}
|
||||
}
|
||||
|
||||
return this._ndParent;
|
||||
}
|
||||
|
||||
static _instance: EffectManager;
|
||||
|
||||
static get instance () {
|
||||
if (this._instance) {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
this._instance = new EffectManager();
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放动画
|
||||
* @param {string} path 动画节点路径
|
||||
* @param {string} aniName
|
||||
* @param {vec3} worPos 世界坐标
|
||||
* @param {boolean} isLoop 是否循环
|
||||
* @param {boolean} isRecycle 是否回收
|
||||
* @param {number} [scale=1] 缩放倍数
|
||||
* @param {Function} [callback=()=>{}] 回调函数
|
||||
*/
|
||||
public playAni (path: string, aniName: string, worPos: Vec3 = new Vec3(), isLoop: boolean = false, isRecycle: boolean = false, scale: number = 1, callback: Function = ()=>{}) {
|
||||
let childName: string = path.split("/")[1];
|
||||
let ndEffect: Node | null = this.ndParent.getChildByName(childName);
|
||||
|
||||
let cb = ()=>{
|
||||
ndEffect?.setScale(scale, scale, scale);
|
||||
ndEffect?.setWorldPosition(worPos);
|
||||
let ani: AnimationComponent= ndEffect?.getComponent(AnimationComponent) as AnimationComponent;
|
||||
ani.play(aniName);
|
||||
let aniState: AnimationState= ani.getState(aniName) as AnimationState;
|
||||
if (aniState) {
|
||||
if (isLoop) {
|
||||
aniState.wrapMode = AnimationClip.WrapMode.Loop;
|
||||
} else {
|
||||
aniState.wrapMode = AnimationClip.WrapMode.Normal;
|
||||
}
|
||||
}
|
||||
|
||||
ani.once(AnimationComponent.EventType.FINISHED, ()=>{
|
||||
callback && callback();
|
||||
if (isRecycle && ndEffect) {
|
||||
PoolManager.instance.putNode(ndEffect);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!ndEffect) {
|
||||
ResourceUtil.loadEffectRes(path).then((prefab: unknown)=>{
|
||||
ndEffect = PoolManager.instance.getNode(prefab as Prefab, this.ndParent) as Node;
|
||||
ndEffect.setScale(scale, scale, scale);
|
||||
ndEffect.setWorldPosition(worPos);
|
||||
cb();
|
||||
})
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除特效
|
||||
* @param {string} name 特效名称
|
||||
* @param {Node}} ndParent 特效父节点
|
||||
*/
|
||||
public removeEffect (name: string, ndParent: Node = this.ndParent) {
|
||||
let ndEffect: Node | null = ndParent.getChildByName(name);
|
||||
if (ndEffect) {
|
||||
let arrAni: AnimationComponent[] = ndEffect.getComponentsInChildren(AnimationComponent);
|
||||
arrAni.forEach((element: AnimationComponent)=>{
|
||||
element.stop();
|
||||
})
|
||||
|
||||
let arrParticle: [] = ndEffect?.getComponentsInChildren(ParticleSystemComponent) as any;
|
||||
arrParticle.forEach((element:ParticleSystemComponent)=>{
|
||||
element?.clear();
|
||||
element?.stop();
|
||||
})
|
||||
PoolManager.instance.putNode(ndEffect);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放粒子特效
|
||||
* @param {string} path 特效路径
|
||||
* @param {vec3}worPos 特效世界坐标
|
||||
* @param {number} [recycleTime=0] 特效节点回收时间,如果为0,则使用默认duration
|
||||
* @param {number} [scale=1] 缩放倍数
|
||||
* @param {vec3} eulerAngles 特效角度
|
||||
* @param {Function} [callback=()=>{}] 回调函数
|
||||
*/
|
||||
public playParticle (path: string, worPos: Vec3, recycleTime: number = 0, scale: number = 1, eulerAngles?: Vec3 | null, callback?: Function) {
|
||||
ResourceUtil.loadEffectRes(path).then((prefab: any)=>{
|
||||
let ndEffect: Node = PoolManager.instance.getNode(prefab as Prefab, this.ndParent) as Node;
|
||||
ndEffect.setScale(scale, scale, scale);
|
||||
ndEffect.setWorldPosition(worPos);
|
||||
|
||||
if (eulerAngles) {
|
||||
ndEffect.eulerAngles = eulerAngles;
|
||||
}
|
||||
|
||||
let maxDuration: number = 0;
|
||||
|
||||
let arrParticle: ParticleSystemComponent[]= ndEffect.getComponentsInChildren(ParticleSystemComponent);
|
||||
arrParticle.forEach((item: ParticleSystemComponent)=>{
|
||||
item.simulationSpeed = 1;
|
||||
item?.clear();
|
||||
item?.stop();
|
||||
item?.play()
|
||||
|
||||
let duration: number= item.duration;
|
||||
maxDuration = duration > maxDuration ? duration : maxDuration;
|
||||
})
|
||||
|
||||
let seconds: number = recycleTime && recycleTime > 0 ? recycleTime : maxDuration;
|
||||
|
||||
setTimeout(()=>{
|
||||
if (ndEffect.parent) {
|
||||
callback && callback();
|
||||
PoolManager.instance.putNode(ndEffect);
|
||||
}
|
||||
}, seconds * 1000)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放节点下面的动画和粒子
|
||||
*
|
||||
* @param {Node} targetNode 特效挂载节点
|
||||
* @param {string} effectPath 特效路径
|
||||
* @param {boolean} [isPlayAni=true] 是否播放动画
|
||||
* @param {boolean} [isPlayParticle=true] 是否播放特效
|
||||
* @param {number} [recycleTime=0] 特效节点回收时间,如果为0,则使用默认duration
|
||||
* @param {number} [scale=1] 缩放倍数
|
||||
* @param {Vec3} [pos=new Vec3()] 位移
|
||||
* @param {boolean} [isRecycle=true] 回收或者销毁
|
||||
* @param {Function} [callback=()=>{}] 回调函数
|
||||
* @returns
|
||||
* @memberof EffectManager
|
||||
*/
|
||||
public playEffect (targetNode: Node, effectPath: string, isPlayAni: boolean = true, isPlayParticle: boolean = true, recycleTime: number = 0, scale: number = 1, pos?: Vec3 | null, eulerAngles?: Vec3 | null, isRecycle: boolean = true, callback?: Function | null) {
|
||||
if (!targetNode || !targetNode.parent) {//父节点被回收的时候不播放
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceUtil.loadEffectRes(effectPath).then((prefab: any)=>{
|
||||
let ndEffect: Node = PoolManager.instance.getNode(prefab as Prefab, targetNode) as Node;
|
||||
ndEffect.setScale(scale, scale, scale);
|
||||
|
||||
if (pos) {
|
||||
ndEffect.setPosition(pos);
|
||||
}
|
||||
|
||||
if (eulerAngles) {
|
||||
ndEffect.eulerAngles = eulerAngles;
|
||||
}
|
||||
|
||||
let maxDuration: number = 0;
|
||||
|
||||
if (isPlayAni) {
|
||||
let arrAni: AnimationComponent[] = ndEffect.getComponentsInChildren(AnimationComponent);
|
||||
|
||||
if (arrAni.length) {
|
||||
arrAni.forEach((element: AnimationComponent, idx: number)=>{
|
||||
element?.play();
|
||||
|
||||
let aniName = element?.defaultClip?.name;
|
||||
if (aniName) {
|
||||
let aniState = element.getState(aniName);
|
||||
if (aniState) {
|
||||
aniState.time = 0;
|
||||
aniState.sample();
|
||||
|
||||
let duration = aniState.duration;
|
||||
maxDuration = duration > maxDuration ? duration : maxDuration;
|
||||
|
||||
aniState.speed = 1;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (isPlayParticle) {
|
||||
let arrParticle: ParticleSystemComponent[]= ndEffect.getComponentsInChildren(ParticleSystemComponent);
|
||||
|
||||
if (arrParticle.length) {
|
||||
arrParticle.forEach((element:ParticleSystemComponent)=>{
|
||||
element.simulationSpeed = 1;
|
||||
element?.clear();
|
||||
element?.stop();
|
||||
element?.play()
|
||||
|
||||
let duration: number= element.duration;
|
||||
maxDuration = duration > maxDuration ? duration : maxDuration;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let seconds: number = recycleTime && recycleTime > 0 ? recycleTime : maxDuration;
|
||||
|
||||
setTimeout(()=>{
|
||||
if (ndEffect.parent) {
|
||||
callback && callback();
|
||||
if (isRecycle) {
|
||||
PoolManager.instance.putNode(ndEffect);
|
||||
} else {
|
||||
ndEffect.destroy();
|
||||
}
|
||||
}
|
||||
}, seconds * 1000)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放节点上的粒子特效/托尾粒子特效
|
||||
*
|
||||
* @param {Node} ndParent
|
||||
* @memberof EffectManager
|
||||
*/
|
||||
public playTrail (ndParent: Node, recycleTime:number = 0, callback?:Function, speed: number = 1) {
|
||||
let maxDuration: number = 0;
|
||||
|
||||
if (!ndParent.active) {
|
||||
ndParent.active = true;
|
||||
}
|
||||
|
||||
let arrParticle: ParticleSystemComponent[]= ndParent.getComponentsInChildren(ParticleSystemComponent);
|
||||
arrParticle.forEach((element:ParticleSystemComponent)=>{
|
||||
element.simulationSpeed = speed;
|
||||
element?.clear();
|
||||
element?.stop();
|
||||
element?.play();
|
||||
|
||||
let duration: number= element.duration;
|
||||
maxDuration = duration > maxDuration ? duration : maxDuration;
|
||||
})
|
||||
|
||||
if (callback) {
|
||||
let seconds: number = recycleTime && recycleTime > 0 ? recycleTime : maxDuration;
|
||||
|
||||
setTimeout(()=>{
|
||||
callback();
|
||||
}, seconds * 1000)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放道具消失特效
|
||||
* @param {string} path 特效路径
|
||||
* @param {vec3}worPos 特效世界坐标
|
||||
* @param {Function} [callback=()=>{}] 回调函数
|
||||
*/
|
||||
public playDisappearEff (path: string, worPos: Vec3, cb: Function) {
|
||||
ResourceUtil.loadEffectRes(path).then((prefab: any)=>{
|
||||
let ndEffect: Node = PoolManager.instance.getNode(prefab as Prefab, this.ndParent) as Node;
|
||||
ndEffect.setWorldPosition(worPos);
|
||||
|
||||
let maxDuration: number = 0;
|
||||
|
||||
let arrParticle: ParticleSystemComponent[]= ndEffect.getComponentsInChildren(ParticleSystemComponent);
|
||||
arrParticle.forEach((item: ParticleSystemComponent)=>{
|
||||
item.simulationSpeed = 1;
|
||||
item?.clear();
|
||||
item?.stop();
|
||||
item?.play()
|
||||
|
||||
let duration: number= item.duration;
|
||||
maxDuration = duration > maxDuration ? duration : maxDuration;
|
||||
})
|
||||
|
||||
setTimeout(()=>{
|
||||
if (ndEffect && ndEffect.parent) {
|
||||
PoolManager.instance.putNode(ndEffect);
|
||||
}
|
||||
}, maxDuration * 1000)
|
||||
|
||||
cb && cb(()=>{
|
||||
if (ndEffect && ndEffect.parent) {
|
||||
PoolManager.instance.putNode(ndEffect);
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
11
assets/script/framework/effectManager.ts.meta
Normal file
11
assets/script/framework/effectManager.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "554ba46f-7575-4269-965e-5c54afbc0a5e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
141
assets/script/framework/localConfig.ts
Normal file
141
assets/script/framework/localConfig.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { _decorator, resources } from "cc";
|
||||
import { CSVManager } from "./csvManager";
|
||||
import { ResourceUtil } from "./resourceUtil";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("LocalConfig")
|
||||
export class LocalConfig {
|
||||
/* class member could be defined like this */
|
||||
private static _instance: LocalConfig;
|
||||
private _csvManager: CSVManager = new CSVManager();
|
||||
|
||||
static get instance () {
|
||||
if (this._instance) {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
this._instance = new LocalConfig();
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
private _callback: Function = new Function();
|
||||
private _currentLoad: number = 0;
|
||||
private _cntLoad: number = 0;
|
||||
|
||||
/**
|
||||
* 加载配置文件
|
||||
* @param {Function}cb 回调函数
|
||||
*/
|
||||
public loadConfig (cb: Function) {
|
||||
this._callback = cb;
|
||||
this._loadCSV();
|
||||
}
|
||||
|
||||
private _loadCSV () {
|
||||
//新增数据表 请往该数组中添加....
|
||||
resources.loadDir("datas", (err: any, assets)=>{
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
let arrCsvFiles = assets.filter((item: any)=>{
|
||||
return item._native !== ".md";
|
||||
})
|
||||
|
||||
this._cntLoad = arrCsvFiles.length;
|
||||
|
||||
//客户端加载
|
||||
if (arrCsvFiles.length) {
|
||||
arrCsvFiles.forEach((item, index, array)=> {
|
||||
ResourceUtil.getTextData(item.name, (err: any, content: any) => {
|
||||
this._csvManager.addTable(item.name, content);
|
||||
this._tryToCallbackOnFinished();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this._tryToCallbackOnFinished();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询一条表内容
|
||||
* @param {string} tableName 表名
|
||||
* @param {string} key 列名
|
||||
* @param {any} value 值
|
||||
* @returns {Object} 一条表内容
|
||||
*/
|
||||
queryOne (tableName: string, key: string, value: any) {
|
||||
return this._csvManager.queryOne(tableName, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询一条表内容
|
||||
* @param {string}tableName 表名
|
||||
* @param {string}ID
|
||||
* @returns {Object} 一条表内容
|
||||
*/
|
||||
queryByID (tableName: string, ID: string) {
|
||||
return this._csvManager.queryByID(tableName, ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名获取表的所有内容
|
||||
* @param {string} tableName 表名
|
||||
* @returns {object} 表内容
|
||||
*/
|
||||
getTable (tableName: string) {
|
||||
return this._csvManager.getTable(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名获取表的所有内容
|
||||
* @param {string} tableName 表名
|
||||
* @returns {object} 表内容
|
||||
*/
|
||||
getTableArr (tableName: string) {
|
||||
return this._csvManager.getTableArr(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询key和value对应的所有行内容
|
||||
* @param {string} tableName 表名
|
||||
* @param {string} key 列名
|
||||
* @param {any} value 值
|
||||
* @returns {Object}
|
||||
*/
|
||||
queryAll (tableName: string, key: string, value: any) {
|
||||
return this._csvManager.queryAll(tableName, key, value);
|
||||
}
|
||||
|
||||
//
|
||||
/**
|
||||
* 选出指定表里所有 key 的值在 values 数组中的数据,返回 Object,key 为 ID
|
||||
* @param {string} tableName 表名
|
||||
* @param {string} key 列名
|
||||
* @param {Array}values 数值
|
||||
* @returns
|
||||
*/
|
||||
queryIn (tableName: string, key: string, values: any[]) {
|
||||
return this._csvManager.queryIn(tableName, key, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选出符合条件的数据。condition key 为表格的key,value 为值的数组。返回的object,key 为数据在表格的ID,value为具体数据
|
||||
* @param {string} tableName 表名
|
||||
* @param {any} condition 筛选条件
|
||||
* @returns
|
||||
*/
|
||||
queryByCondition (tableName: string, condition: any) {
|
||||
return this._csvManager.queryByCondition(tableName, condition);
|
||||
}
|
||||
|
||||
private _tryToCallbackOnFinished () {
|
||||
if (this._callback) {
|
||||
this._currentLoad++;
|
||||
if (this._currentLoad >= this._cntLoad) {
|
||||
this._callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
assets/script/framework/localConfig.ts.meta
Normal file
11
assets/script/framework/localConfig.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "12fac499-8454-4621-86bb-cb188b5433a9",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
637
assets/script/framework/lodash.ts
Normal file
637
assets/script/framework/lodash.ts
Normal file
@@ -0,0 +1,637 @@
|
||||
import { _decorator } from "cc";
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
@ccclass("Lodash")
|
||||
export class Lodash {
|
||||
/* class member could be defined like this */
|
||||
// dummy = '';
|
||||
/**
|
||||
* 遍历 collection(集合)元素,返回 predicate(断言函数)第一个返回真值的第一个元素
|
||||
* @param {any} collection 一个用来迭代的集合
|
||||
* @param {Function} predicate 每次迭代调用的函数。
|
||||
* @returns 返回匹配元素,否则返回 undefined。
|
||||
*/
|
||||
public static find (collection: any, predicate: Function) {
|
||||
var result;
|
||||
if (!Array.isArray(collection)) {
|
||||
collection = Lodash._toArray(collection);
|
||||
}
|
||||
|
||||
result = collection.filter(predicate);
|
||||
if (result.length) {
|
||||
return result[0];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 iteratee 遍历 collection(集合) 中的每个元素
|
||||
* @param {any} collection 一个用来迭代的集合
|
||||
* @param {Function} iteratee 每次迭代调用的函数。
|
||||
*/
|
||||
public static forEach(collection: any, iteratee: any) {
|
||||
if (!Array.isArray(collection)) {
|
||||
var array = Lodash._toArrayKey(collection);
|
||||
array.forEach(function (value: any, index: number, arr: any[]) {
|
||||
var key1 = value['key'];
|
||||
var value1 = value['value'];
|
||||
iteratee(value1, key1, collection);
|
||||
});
|
||||
} else {
|
||||
collection.forEach(iteratee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 深度拷贝
|
||||
* @param {any} sObj 拷贝的对象
|
||||
* @returns
|
||||
*/
|
||||
public static cloneDeep(sObj: any) {
|
||||
if (sObj === null || typeof sObj !== "object") {
|
||||
return sObj;
|
||||
}
|
||||
|
||||
let s: any = {};
|
||||
if (sObj.constructor === Array) {
|
||||
s = [];
|
||||
}
|
||||
|
||||
for (let i in sObj) {
|
||||
if (sObj.hasOwnProperty(i)) {
|
||||
s[i] = Lodash.cloneDeep(sObj[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个数组, value(值) 是 iteratee(迭代函数)遍历 collection(集合)中的每个元素后返回的结果。
|
||||
* @param {Array|Object} collection 一个用来迭代的集合.
|
||||
* @param {Function} predicate 一个迭代函数,用来转换key(键
|
||||
* @returns {Array} 返回一个组成集合数组
|
||||
*/
|
||||
public static map(collection: any, iteratee: any) {
|
||||
if (!Array.isArray(collection)) {
|
||||
collection = Lodash._toArray(collection);
|
||||
}
|
||||
|
||||
let arr: any[] = [];
|
||||
collection.forEach(function (value: any, index: number, array: []) {
|
||||
arr.push(iteratee(value, index, array));
|
||||
});
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param srcObj
|
||||
* @returns
|
||||
*/
|
||||
private static _toArrayKey(srcObj: { [x: string]: any; hasOwnProperty: (arg0: string) => any; }) {
|
||||
var resultArr = [];
|
||||
|
||||
// to array
|
||||
for (var key in srcObj) {
|
||||
if (!srcObj.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
resultArr.push({ key: key, value: srcObj[key] });
|
||||
}
|
||||
|
||||
return resultArr;
|
||||
}
|
||||
|
||||
private static _toArray(srcObj: any) {
|
||||
let resultArr: any[] = [];
|
||||
|
||||
// to array
|
||||
for (var key in srcObj) {
|
||||
if (!srcObj.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
resultArr.push(srcObj[key]);
|
||||
}
|
||||
|
||||
return resultArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历 collection(集合)元素,返回 predicate(断言函数)返回真值 的所有元素的数组。
|
||||
* @param {Array|Object} collection 一个用来迭代的集合.
|
||||
* @param {Function} predicate 一个迭代函数,用来转换key(键
|
||||
* @returns 返回一个新的过滤后的数组。
|
||||
*/
|
||||
public static filter(collection: any, iteratees: Function) {
|
||||
if (!Array.isArray(collection)) {
|
||||
collection = Lodash._toArray(collection);
|
||||
}
|
||||
|
||||
return collection.filter(iteratees);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行深比较来确定两者的值是否相等。
|
||||
* @param {any}x
|
||||
* @param {any}y
|
||||
* @returns {boolean} 如果 两个值完全相同,那么返回 true,否则返回 false。
|
||||
*/
|
||||
public static isEqual(x: any, y: any): boolean {
|
||||
var in1 = x instanceof Object;
|
||||
var in2 = y instanceof Object;
|
||||
if (!in1 || !in2) {
|
||||
return x === y;
|
||||
}
|
||||
|
||||
if (Object.keys(x).length !== Object.keys(y).length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var p in x) {
|
||||
var a = x[p] instanceof Object;
|
||||
var b = y[p] instanceof Object;
|
||||
if (a && b) {
|
||||
return Lodash.isEqual(x[p], y[p]);
|
||||
} else if (x[p] !== y[p]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收一个要移除值的数组。
|
||||
* @param {Array} array 修改的数组
|
||||
* @param {Array} value 移除值的数组
|
||||
* @param {Function} comparator comparator(比较器)调用每个元素。
|
||||
* @returns
|
||||
*/
|
||||
public static pullAllWith(array: any[], value: any[], comparator: Function) {
|
||||
value.forEach(function (item) {
|
||||
var res = array.filter(function (n) {
|
||||
return comparator(n, item);
|
||||
});
|
||||
|
||||
res.forEach(function (item) {
|
||||
var index = array.indexOf(item);
|
||||
if (array.indexOf(item) !== -1) {
|
||||
array.splice(index, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前时间戳
|
||||
* @returns
|
||||
*/
|
||||
public static now() {
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收一个要移除值的数组。
|
||||
* @param {Array} array 修改的数组
|
||||
* @param {Array} value 移除值的数组
|
||||
* @returns
|
||||
*/
|
||||
public static pullAll(array: any[], value: any) {
|
||||
value.forEach(function (item: any) {
|
||||
var index = array.indexOf(item);
|
||||
if (array.indexOf(item) !== -1) {
|
||||
array.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从右到左遍历集合中每一个元素的。
|
||||
* @param {Array|Object} collection 一个用来迭代的集合.
|
||||
* @param {Function} predicate 一个迭代函数
|
||||
*/
|
||||
public static forEachRight(collection: [] | {}, iteratee: Function) {
|
||||
if (!Array.isArray(collection)) {
|
||||
collection = Lodash._toArray(collection);
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
for (var i = collection.length - 1; i >= 0; i--) {
|
||||
//@ts-ignore
|
||||
var ret = iteratee(collection[i]);
|
||||
if (!ret) break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查字符串string是否以 target 开头。
|
||||
* @param {string} str 要检索的字符串。
|
||||
* @param {string}target 要检查的字符串。
|
||||
* @param {number}position 检索的位置。
|
||||
* @returns
|
||||
*/
|
||||
public static startsWith(str: string, target: string, position: number) {
|
||||
str = str.substr(position);
|
||||
return str.startsWith(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查字符串string是否以 target 结束。
|
||||
* @param {string} str 要检索的字符串。
|
||||
* @param {string}target 要检查的字符串。
|
||||
* @param {number}position 检索的位置。
|
||||
* @returns
|
||||
*/
|
||||
public static endsWith(str: string, target: string, position: number) {
|
||||
str = str.substr(position);
|
||||
return str.endsWith(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除数组中predicate(断言)返回为真值的所有元素
|
||||
* @param {Array} array 一个用来迭代的集合.
|
||||
* @param {Function} predicate 一个迭代函数
|
||||
* @returns
|
||||
*/
|
||||
public static remove(array: any[], predicate: Function) {
|
||||
var result: any[] = [];
|
||||
var indexes: any[] = [];
|
||||
array.forEach(function (item, index) {
|
||||
if (predicate(item)) {
|
||||
result.push(item);
|
||||
indexes.push(index);
|
||||
}
|
||||
});
|
||||
|
||||
Lodash._basePullAt(array, indexes);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _basePullAt(array: any[], indexes: any[]) {
|
||||
var length = array ? indexes.length : 0;
|
||||
var lastIndex = length - 1;
|
||||
var previous;
|
||||
|
||||
while (length--) {
|
||||
var index = indexes[length];
|
||||
if (length === lastIndex || index !== previous) {
|
||||
previous = index;
|
||||
Array.prototype.splice.call(array, index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回第一个通过 predicate 判断为真值的元素的索引值
|
||||
* @param {Array} array 一个用来迭代的集合.
|
||||
* @param {Function} predicate 一个迭代函数
|
||||
* @param {number} fromIndex 开始查找索引值
|
||||
* @returns
|
||||
*/
|
||||
public static findIndex(array: any[], predicate: Function, fromIndex: number) {
|
||||
array = array.slice(fromIndex);
|
||||
var i;
|
||||
if (typeof predicate === "function") {
|
||||
for (i = 0; i < array.length; i++) {
|
||||
if (predicate(array[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} else if (Array.isArray(predicate)) {
|
||||
for (i = 0; i < array.length; i++) {
|
||||
var key = predicate[0];
|
||||
var vaule = true;
|
||||
//@ts-ignore
|
||||
if (predicate.length > 1) {
|
||||
vaule = predicate[1];
|
||||
}
|
||||
|
||||
if (array[i][key] === vaule) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < array.length; i++) {
|
||||
if (array[i] === predicate) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个新数组,将array与任何数组 或 值连接在一起。
|
||||
* @returns
|
||||
*/
|
||||
public static concat() {
|
||||
var length = arguments.length;
|
||||
if (!length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var array = arguments[0];
|
||||
var index = 1;
|
||||
while (index < length) {
|
||||
array = array.concat(arguments[index]);
|
||||
index++;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 value 是否是原始Number数值型 或者 对象。
|
||||
* @param {any }value
|
||||
* @returns
|
||||
*/
|
||||
public static isNumber(value: any) {
|
||||
return typeof value === 'number';
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回首次 value 在数组array中被找到的 索引值
|
||||
* @param {Array}array
|
||||
* @param {any}value
|
||||
* @param {number} fromIndex
|
||||
* @returns
|
||||
*/
|
||||
public static indexOf(array: any[], value: any, fromIndex: number) {
|
||||
array = array.slice(fromIndex);
|
||||
return array.indexOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 array 中的所有元素转换为由 separator 分隔的字符串。
|
||||
* @param {any} array 要转换的数组
|
||||
* @param {string} separator 分隔元素。
|
||||
* @returns
|
||||
*/
|
||||
public static join(array: any[], separator: string) {
|
||||
if (array === null) return '';
|
||||
|
||||
var result = '';
|
||||
array.forEach(function (item) {
|
||||
result += item + separator;
|
||||
});
|
||||
|
||||
return result.substr(0, result.length - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据separator 拆分字符串string。
|
||||
* @param {string} str 要转换的数组
|
||||
* @param {RegExp|string} separator 分隔元素。
|
||||
* @param {number} limit 限制结果的数量。
|
||||
* @returns
|
||||
*/
|
||||
public static split(str: string, separator: RegExp|string, limit: number) {
|
||||
return str.split(separator, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算 array 中的最大值。 如果 array 是 空的或者假值将会返回 undefined。
|
||||
* @param {Array}array
|
||||
* @returns
|
||||
*/
|
||||
public static max(array: any[]) {
|
||||
if (array && array.length) {
|
||||
var result;
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (i === 0) {
|
||||
result = array[0];
|
||||
} else if (result < array[i]) {
|
||||
result = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个切片数组,去除array前面的n个元素。(n默认值为1。)
|
||||
* @param {Array}array : 要查询的数组。
|
||||
* @param {number}n 要去除的元素个数。
|
||||
* @returns
|
||||
*/
|
||||
public static drop(array: any[], n: number) {
|
||||
var length = array === null ? 0 : array.length;
|
||||
if (!length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array.slice(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将array递归为一维数组。
|
||||
* @param {Array} arr
|
||||
* @returns
|
||||
*/
|
||||
public static flattenDeep(arr: any[]): any {
|
||||
return arr.reduce(function (prev: any[], cur: any[]) {
|
||||
return prev.concat(Array.isArray(cur) ? Lodash.flattenDeep(cur) : cur);
|
||||
}, [ ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个去重后的array数组副本。使用了SameValueZero 做等值比较。只有第一次出现的元素才会被保留。
|
||||
* @param {Array} array
|
||||
* @returns
|
||||
*/
|
||||
public static uniq(array: any[]) {
|
||||
let result: any[] = [];
|
||||
array.forEach(function (item) {
|
||||
if (result.indexOf(item) === -1) {
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 value 是否是 NaN。
|
||||
* @param {any}value
|
||||
* @returns
|
||||
*/
|
||||
public static isNaN(value: any) {
|
||||
// An `NaN` primitive is the only value that is not equal to itself.
|
||||
// Perform the `toStringTag` check first to avoid errors with some
|
||||
// ActiveX objects in IE.
|
||||
return Lodash.isNumber(value) && value !== +value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数组(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 [];
|
||||
}
|
||||
|
||||
var result = [];
|
||||
while (array.length > size) {
|
||||
result.push(array.slice(0, size));
|
||||
array = array.slice(size);
|
||||
}
|
||||
|
||||
result.push(array);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换 value 为一个有限数字
|
||||
* @param {any} value
|
||||
* @returns
|
||||
*/
|
||||
public static toFinite(value: any) {
|
||||
var INFINITY = 1 / 0;
|
||||
var MAX_INTEGER = 1.7976931348623157e+308;
|
||||
if (!value) {
|
||||
return value === 0 ? value : 0;
|
||||
}
|
||||
value = Number(value);
|
||||
if (value === INFINITY || value === -INFINITY) {
|
||||
var sign = (value < 0 ? -1 : 1);
|
||||
return sign * MAX_INTEGER;
|
||||
}
|
||||
return value === value ? value : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为对象
|
||||
* @param {any}value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isObject(value: any) {
|
||||
var type = typeof value;
|
||||
return value !== null && (type === 'object' || type === 'function');
|
||||
}
|
||||
|
||||
public static MAX_SAFE_INTEGER = 9007199254740991;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
public static isLength(value: any) {
|
||||
return typeof value === 'number' &&
|
||||
value > -1 && value % 1 === 0 && value <= Lodash.MAX_SAFE_INTEGER;
|
||||
}
|
||||
|
||||
public static _isArrayLike(value: []) {
|
||||
return value !== null && Lodash.isLength(value.length) /*&& !isFunction(value)*/;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数组总符合条件的最大值
|
||||
* @param {Array} array 一个用来迭代的集合.
|
||||
* @param {Function} predicate 一个迭代函数
|
||||
* @returns {Object} 返回最大值
|
||||
*/
|
||||
public static maxBy(array: any[], predicate: Function) {
|
||||
if (array && array.length) {
|
||||
var result;
|
||||
var objResult;
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (i === 0) {
|
||||
result = predicate(array[0]);
|
||||
objResult = array[0];
|
||||
} else if (result < array[i]) {
|
||||
result = (array[i]);
|
||||
objResult = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
return objResult;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数组总符合条件的最小值
|
||||
* @param {Array} array 一个用来迭代的集合.
|
||||
* @param {Function} predicate 一个迭代函数
|
||||
* @returns {Object} 返回最小值
|
||||
*/
|
||||
public static minBy(array: any[], predicate: Function) {
|
||||
if (array && array.length) {
|
||||
let result;
|
||||
let objResult;
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (i === 0) {
|
||||
result = predicate(array[0]);
|
||||
objResult = array[0];
|
||||
} else if (result > array[i]) {
|
||||
result = predicate(array[i]);
|
||||
objResult = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
return objResult;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
}
|
||||
/**
|
||||
* 返回复合迭代函数的总和
|
||||
* @param {Array|Object} collection 一个用来迭代的集合.
|
||||
* @param {Function} predicate 一个迭代函数
|
||||
* @returns {Object} 返回总和
|
||||
*/
|
||||
public static sumBy(collection: [] | {}, predicate: Function) {
|
||||
let sum: number = 0;
|
||||
for (let key in collection) {
|
||||
//@ts-ignore
|
||||
sum += predicate(collection[key]);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回复合迭代函数的次数
|
||||
* @param {Array|Object} collection 一个用来迭代的集合.
|
||||
* @param {Function} predicate 一个迭代函数,用来转换key(键
|
||||
* @returns {Object} 返回一个组成集合对象
|
||||
*/
|
||||
public static countBy(collection: [] | {}, predicate: Function) {
|
||||
let objRet: {[key: string]: number} = {};
|
||||
for (let key in collection) {
|
||||
let value: any = predicate(key);
|
||||
if (objRet.hasOwnProperty(value)) {
|
||||
objRet[value] += 1;
|
||||
} else {
|
||||
objRet[value] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return objRet;
|
||||
}
|
||||
|
||||
}
|
11
assets/script/framework/lodash.ts.meta
Normal file
11
assets/script/framework/lodash.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "a40a4a46-47a9-42aa-8d1c-a11d56e24025",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
247
assets/script/framework/playerData.ts
Normal file
247
assets/script/framework/playerData.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
import { _decorator, Component, log } from "cc";
|
||||
import { Constant } from "./constant";
|
||||
import { StorageManager } from "./storageManager";
|
||||
import { Util } from "./util";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("PlayerData")
|
||||
export class PlayerData extends Component {
|
||||
static _instance: PlayerData;
|
||||
|
||||
public serverTime: number = 0;
|
||||
public localTime: number = 0;
|
||||
|
||||
public static get instance () {
|
||||
if (this._instance) {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
this._instance = new PlayerData();
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
private _userId: string = '';
|
||||
private _playerInfo: any = null;
|
||||
private _history: any = null;
|
||||
private _settings: any = null;
|
||||
private _isNewBee: boolean = false; //默认非新手
|
||||
private _dataVersion: string = '';
|
||||
|
||||
public get userId () {
|
||||
return this._userId;
|
||||
}
|
||||
|
||||
public set userId (v: string) {
|
||||
this._userId = v;
|
||||
}
|
||||
|
||||
public get settings () {
|
||||
return this._settings;
|
||||
}
|
||||
|
||||
public set settings (v: any) {
|
||||
this._settings = v;
|
||||
}
|
||||
|
||||
public get playerInfo () {
|
||||
return this._playerInfo;
|
||||
}
|
||||
|
||||
public get history () {
|
||||
return this._history;
|
||||
}
|
||||
|
||||
public get isNewBee () {
|
||||
return this._isNewBee;
|
||||
}
|
||||
|
||||
public set isNewBee (v: boolean) {
|
||||
this._isNewBee = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加上用户数据
|
||||
*/
|
||||
public loadGlobalCache() {
|
||||
let userId: string = StorageManager.instance.getUserId();
|
||||
if (userId) {
|
||||
this._userId = userId;
|
||||
}
|
||||
}
|
||||
|
||||
public isInit:boolean = false;
|
||||
|
||||
/**
|
||||
* 加载本地存储数据
|
||||
*/
|
||||
public loadFromCache() {
|
||||
this.loadGlobalCache();
|
||||
if (!this.userId) {
|
||||
this.generateRandomAccount();
|
||||
}
|
||||
|
||||
//读取玩家基础数据
|
||||
this._playerInfo = this._loadDataByKey(Constant.LOCAL_CACHE.PLAYER);
|
||||
this._history = this._loadDataByKey(Constant.LOCAL_CACHE.HISTORY);
|
||||
this._settings = this._loadDataByKey(Constant.LOCAL_CACHE.SETTINGS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地存储数据
|
||||
* @param {string}keyName
|
||||
* @returns
|
||||
*/
|
||||
private _loadDataByKey (keyName: any) {
|
||||
let ret = {};
|
||||
let str = StorageManager.instance.getConfigData(keyName);
|
||||
if (str) {
|
||||
try {
|
||||
ret = JSON.parse(str);
|
||||
} catch (e) {
|
||||
ret = {};
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建角色数据
|
||||
* @param loginData
|
||||
*/
|
||||
public createPlayerInfo(loginData?:any) {
|
||||
this._playerInfo = {};
|
||||
if (loginData) {
|
||||
for (let key in loginData) {
|
||||
this._playerInfo[key] = loginData[key];
|
||||
}
|
||||
}
|
||||
|
||||
this.savePlayerInfoToLocalCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机账户
|
||||
* @returns
|
||||
*/
|
||||
public generateRandomAccount () {
|
||||
this.userId = new Date().getTime() + "_" + Math.floor(Math.random() * 1000);
|
||||
StorageManager.instance.setUserId(this._userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存用户数据
|
||||
* @param userId
|
||||
*/
|
||||
public saveAccount(userId: any) {
|
||||
this._userId = userId;
|
||||
StorageManager.instance.setUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存玩家数据
|
||||
*/
|
||||
public savePlayerInfoToLocalCache() {
|
||||
StorageManager.instance.setConfigData(Constant.LOCAL_CACHE.PLAYER, JSON.stringify(this._playerInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存玩家设置相关信息
|
||||
*/
|
||||
public saveSettingsToLocalCache () {
|
||||
StorageManager.instance.setConfigData(Constant.LOCAL_CACHE.SETTINGS, JSON.stringify(this._settings));
|
||||
|
||||
StorageManager.instance.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当数据同步完毕,即被覆盖的情况下,需要将数据写入到本地缓存,以免数据丢失
|
||||
*/
|
||||
public saveAll() {
|
||||
StorageManager.instance.setConfigDataWithoutSave(Constant.LOCAL_CACHE.PLAYER, JSON.stringify(this._playerInfo));
|
||||
StorageManager.instance.setConfigDataWithoutSave(Constant.LOCAL_CACHE.HISTORY, JSON.stringify(this._history));
|
||||
StorageManager.instance.setConfigDataWithoutSave(Constant.LOCAL_CACHE.SETTINGS, JSON.stringify(this._settings));
|
||||
StorageManager.instance.setConfigData(Constant.LOCAL_CACHE.DATA_VERSION, this._dataVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
* 例如钻石、金币、道具
|
||||
* @param {String} key
|
||||
* @param {Number} value
|
||||
*/
|
||||
public updatePlayerInfo(key:string, value: any) {
|
||||
this._playerInfo[key] = value;
|
||||
StorageManager.instance.setConfigData(Constant.LOCAL_CACHE.PLAYER, JSON.stringify(this._playerInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取玩家杂项值
|
||||
* @param {string} key
|
||||
*/
|
||||
public getSetting (key: string) {
|
||||
if (!this._settings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this._settings.hasOwnProperty(key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._settings[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置玩家杂项值
|
||||
* @param {string} key
|
||||
* @param {*} value
|
||||
*/
|
||||
public setSetting (key: string, value: any) {
|
||||
if (!this._settings) {
|
||||
this._settings = {};
|
||||
}
|
||||
|
||||
this._settings[key] = value;
|
||||
|
||||
this.saveSettingsToLocalCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除用户信息
|
||||
*/
|
||||
public clear () {
|
||||
this._playerInfo = {};
|
||||
this._settings = {};
|
||||
this.saveAll();
|
||||
}
|
||||
|
||||
|
||||
// 触摸参数
|
||||
private _easyTouchInfo: object = {};
|
||||
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
* 例如钻石、金币、道具
|
||||
* @param {String} key
|
||||
* @param {Number} value
|
||||
*/
|
||||
public updateEasyTouchInfo (key: string, value: number): void {
|
||||
this._easyTouchInfo[key] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 触控
|
||||
*
|
||||
* @param {String} key
|
||||
* @param {Number} value
|
||||
*/
|
||||
public getEasyTouchInfo (key: string) {
|
||||
if (!this._easyTouchInfo.hasOwnProperty(key)) {
|
||||
this._easyTouchInfo[key] = 0;
|
||||
}
|
||||
|
||||
return this._easyTouchInfo[key];
|
||||
}
|
||||
}
|
11
assets/script/framework/playerData.ts.meta
Normal file
11
assets/script/framework/playerData.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e5927076-94ef-42ea-8e5e-2e0d8d99c281",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
103
assets/script/framework/poolManager.ts
Normal file
103
assets/script/framework/poolManager.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { _decorator, Prefab, Node, instantiate, NodePool } from "cc";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("PoolManager")
|
||||
export class PoolManager {
|
||||
|
||||
private _dictPool: any = {}
|
||||
private _dictPrefab: any = {}
|
||||
|
||||
static _instance: PoolManager;
|
||||
|
||||
static get instance() {
|
||||
if (this._instance) {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
this._instance = new PoolManager();
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据预设从对象池中获取对应节点
|
||||
*/
|
||||
public getNode(prefab: Prefab, parent: Node) {
|
||||
let name = prefab.name;
|
||||
//@ts-ignore
|
||||
if (!prefab.position) {
|
||||
//@ts-ignore
|
||||
name = prefab.data.name;
|
||||
}
|
||||
|
||||
this._dictPrefab[name] = prefab;
|
||||
let node: Node = null!;
|
||||
if (this._dictPool.hasOwnProperty(name)) {
|
||||
//已有对应的对象池
|
||||
let pool = this._dictPool[name];
|
||||
if (pool.size() > 0) {
|
||||
node = pool.get();
|
||||
} else {
|
||||
node = instantiate(prefab);
|
||||
}
|
||||
} else {
|
||||
//没有对应对象池,创建他!
|
||||
let pool = new NodePool();
|
||||
this._dictPool[name] = pool;
|
||||
|
||||
node = instantiate(prefab);
|
||||
}
|
||||
|
||||
node.parent = parent;
|
||||
node.active = true;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对应节点放回对象池中
|
||||
*/
|
||||
public putNode(node: Node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
let name = node.name;
|
||||
let pool = null;
|
||||
if (this._dictPool.hasOwnProperty(name)) {
|
||||
//已有对应的对象池
|
||||
pool = this._dictPool[name];
|
||||
} else {
|
||||
//没有对应对象池,创建他!
|
||||
pool = new NodePool();
|
||||
this._dictPool[name] = pool;
|
||||
}
|
||||
|
||||
pool.put(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称,清除对应对象池
|
||||
*/
|
||||
public clearPool(name: string) {
|
||||
if (this._dictPool.hasOwnProperty(name)) {
|
||||
let pool = this._dictPool[name];
|
||||
pool.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预生成对象池
|
||||
* @param prefab
|
||||
* @param nodeNum
|
||||
* 使用——PoolManager.instance.prePool(prefab, 40);
|
||||
*/
|
||||
public prePool(prefab: Prefab, nodeNum: number) {
|
||||
const name = prefab.name;
|
||||
|
||||
let pool = new NodePool();
|
||||
this._dictPool[name] = pool;
|
||||
|
||||
for (let i = 0; i < nodeNum; i++) {
|
||||
const node = instantiate(prefab);
|
||||
pool.put(node);
|
||||
}
|
||||
}
|
||||
}
|
11
assets/script/framework/poolManager.ts.meta
Normal file
11
assets/script/framework/poolManager.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e4ab64f9-ff55-42a8-afd5-9fe51c00334c",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
302
assets/script/framework/resourceUtil.ts
Normal file
302
assets/script/framework/resourceUtil.ts
Normal file
@@ -0,0 +1,302 @@
|
||||
import { _decorator, Prefab, Node, SpriteComponent, SpriteFrame, ImageAsset, resources, error, Texture2D, instantiate, isValid, find, TextAsset, JsonAsset, assetManager } from "cc";
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
@ccclass("ResourceUtil")
|
||||
export class ResourceUtil {
|
||||
/**
|
||||
* 加载资源
|
||||
* @param url 资源路径
|
||||
* @param type 资源类型
|
||||
* @param cb 回调
|
||||
* @method loadRes
|
||||
*/
|
||||
public static loadRes (url: string, type: any, cb: Function = ()=>{}) {
|
||||
resources.load(url, (err: any, res: any)=>{
|
||||
if (err) {
|
||||
error(err.message || err);
|
||||
cb(err, res);
|
||||
return;
|
||||
}
|
||||
|
||||
cb && cb(null, res);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 加载资源
|
||||
* @param url 资源路径
|
||||
* @param type 资源类型
|
||||
* @method loadRes
|
||||
*/
|
||||
public static loadResType (url: string, type: any) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resources.load(url, type, (err: any, res: any) => {
|
||||
if (err) {
|
||||
error(err.message || err);
|
||||
reject && reject(err)
|
||||
return;
|
||||
}
|
||||
|
||||
resolve && resolve(res);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特效prefab
|
||||
* @param modulePath 路径
|
||||
* @returns
|
||||
*/
|
||||
public static loadEffectRes (modulePath: string) {
|
||||
return new Promise((resolve, reject)=>{
|
||||
this.loadRes(`prefab/effect/${modulePath}`, Prefab, (err: any, prefab: Prefab)=>{
|
||||
if (err) {
|
||||
console.error('effect load failed', modulePath);
|
||||
reject && reject();
|
||||
return;
|
||||
}
|
||||
|
||||
resolve && resolve(prefab);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型数据
|
||||
* @param modulePath 模型路径
|
||||
* @returns
|
||||
*/
|
||||
public static loadModelRes (modulePath: string) {
|
||||
return new Promise((resolve, reject)=>{
|
||||
this.loadRes(`prefab/model/${modulePath}`, Prefab, (err: any, prefab: Prefab)=>{
|
||||
if (err) {
|
||||
console.error("model load failed", modulePath);
|
||||
reject && reject();
|
||||
return;
|
||||
}
|
||||
|
||||
resolve && resolve(prefab);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多模型数据
|
||||
* @param path 资源路径
|
||||
* @param arrName 资源名称
|
||||
* @param progressCb 过程回调函数
|
||||
* @param completeCb 完成回调函数
|
||||
*/
|
||||
public static loadModelResArr (path: string ,arrName: Array<string>, progressCb: any, completeCb: any) {
|
||||
let arrUrls = arrName.map((item)=>{
|
||||
return `${path}/${item}`;
|
||||
})
|
||||
|
||||
resources.load(arrUrls, Prefab, progressCb, completeCb);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取贴图资源
|
||||
* @param path 贴图路径
|
||||
* @returns
|
||||
*/
|
||||
public static loadSpriteFrameRes(path: string) {
|
||||
return new Promise((resolve, reject)=>{
|
||||
this.loadRes(path, SpriteFrame, (err: any, img: ImageAsset)=>{
|
||||
if (err) {
|
||||
console.error('spriteFrame load failed!', path, err);
|
||||
reject && reject();
|
||||
return;
|
||||
}
|
||||
|
||||
let texture = new Texture2D();
|
||||
texture.image = img;
|
||||
|
||||
let sf = new SpriteFrame();
|
||||
sf.texture = texture;
|
||||
|
||||
resolve && resolve(sf);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取贴图资源
|
||||
* @param path 贴图路径
|
||||
* @returns
|
||||
*/
|
||||
public static loadSpriteFrameURL(url: string, sprite: SpriteComponent) {
|
||||
assetManager.loadRemote(url, (err: any, img: ImageAsset)=>{
|
||||
if (err) {
|
||||
console.error('spriteFrame load failed!', url, err);
|
||||
return;
|
||||
}
|
||||
|
||||
let texture = new Texture2D();
|
||||
texture.image = img;
|
||||
|
||||
let sf = new SpriteFrame();
|
||||
sf.texture = texture;
|
||||
sprite.spriteFrame = sf;
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关卡数据
|
||||
* @param level 关卡
|
||||
* @param cb 回调函数
|
||||
*/
|
||||
public static getMap (level: number, cb: Function) {
|
||||
let levelStr: string = 'map';
|
||||
//前面补0
|
||||
if (level >= 100) {
|
||||
levelStr += level;
|
||||
} else if (level >= 10) {
|
||||
levelStr += '0' + level;
|
||||
} else {
|
||||
levelStr += '00' + level;
|
||||
}
|
||||
|
||||
this.loadRes(`map/config/${levelStr}`, null, (err: {}, txtAsset: any)=>{
|
||||
if (err) {
|
||||
cb(err, txtAsset);
|
||||
return;
|
||||
}
|
||||
|
||||
let content: string = '';
|
||||
if (txtAsset._file) {
|
||||
//@ts-ignore
|
||||
if (window['LZString']) {
|
||||
//@ts-ignore
|
||||
content = window['LZString'].decompressFromEncodedURIComponent(txtAsset._file);
|
||||
}
|
||||
var objJson = JSON.parse(content);
|
||||
cb(null, objJson);
|
||||
} else if (txtAsset.text) {
|
||||
//@ts-ignore
|
||||
if (window['LZString']) {
|
||||
//@ts-ignore
|
||||
content = window['LZString'].decompressFromEncodedURIComponent(txtAsset.text);
|
||||
}
|
||||
var objJson = JSON.parse(content);
|
||||
cb(null, objJson);
|
||||
} else if (txtAsset.json) {
|
||||
cb(null, txtAsset.json);
|
||||
} else {
|
||||
cb('failed');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关卡数据
|
||||
* @param type 关卡类型
|
||||
* @param arrName 资源名称
|
||||
* @param progressCb 过程回调函数
|
||||
* @param completeCb 完成回调函数
|
||||
*/
|
||||
public static getMapObj(type: string, arrName: Array<string>, progressCb?:any, completeCb?:any) {
|
||||
let arrUrls: string[] = [];
|
||||
for (let idx = 0; idx < arrName.length; idx++) {
|
||||
arrUrls.push(`map/${type}/${arrName[idx]}`)
|
||||
}
|
||||
|
||||
resources.load(arrUrls, Prefab, progressCb, completeCb);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取UI prefab
|
||||
* @param prefabPath prefab路径
|
||||
* @param cb 回调函数
|
||||
*/
|
||||
public static getUIPrefabRes (prefabPath: string, cb?: Function) {
|
||||
this.loadRes("prefab/ui/" + prefabPath, Prefab, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建ui界面
|
||||
* @param path ui路径
|
||||
* @param cb 回调函数
|
||||
* @param parent 父节点
|
||||
*/
|
||||
public static createUI (path: string, cb?: Function, isTip?:boolean) {
|
||||
this.getUIPrefabRes(path, function (err: {}, prefab: Prefab) {
|
||||
if (err) return;
|
||||
let node: Node = instantiate(prefab);
|
||||
node.setPosition(0, 0, 0);
|
||||
var parent:Node = null;
|
||||
if(isTip){
|
||||
parent = find("Canvas/ui/tip") as Node;
|
||||
}else{
|
||||
parent = find("Canvas/ui/dislog") as Node;
|
||||
}
|
||||
|
||||
parent.addChild(node);
|
||||
cb && cb(null, node);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取json数据
|
||||
* @param fileName 文件名
|
||||
* @param cb 回调函数
|
||||
*/
|
||||
public static getJsonData (fileName: string, cb: Function) {
|
||||
this.loadRes("datas/" + fileName, null, function (err: any, content: JsonAsset) {
|
||||
if (err) {
|
||||
error(err.message || err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (content.json) {
|
||||
cb(err, content.json);
|
||||
} else {
|
||||
cb('failed!!!');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文本数据
|
||||
* @param fileName 文件名
|
||||
* @param cb 回调函数
|
||||
*/
|
||||
public static getTextData (fileName:string, cb: Function) {
|
||||
this.loadRes("datas/" + fileName, null, function (err: any, content: TextAsset) {
|
||||
if (err) {
|
||||
error(err.message || err);
|
||||
return;
|
||||
}
|
||||
|
||||
let text: string = content.text;
|
||||
cb(err, text);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置精灵贴图
|
||||
* @param path 资源路径
|
||||
* @param sprite 精灵
|
||||
* @param cb 回调函数
|
||||
*/
|
||||
public static setSpriteFrame (path: string, sprite: SpriteComponent, cb: Function) {
|
||||
this.loadRes(path + '/spriteFrame', SpriteFrame, (err: any, spriteFrame: SpriteFrame)=> {
|
||||
if (err) {
|
||||
console.error('set sprite frame failed! err:', path, err);
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sprite && isValid(sprite)) {
|
||||
sprite.spriteFrame = spriteFrame;
|
||||
cb(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static getEffectPrefab (effectName: string, cb: Function) {
|
||||
this.loadRes(`prefab/effect/${effectName}/${effectName}`, Prefab, cb);
|
||||
}
|
||||
|
||||
}
|
11
assets/script/framework/resourceUtil.ts.meta
Normal file
11
assets/script/framework/resourceUtil.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "7844ed5b-3b06-4afb-b24c-62310d414e6f",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
213
assets/script/framework/storageManager.ts
Normal file
213
assets/script/framework/storageManager.ts
Normal file
@@ -0,0 +1,213 @@
|
||||
import { _decorator, sys, log, native } from "cc";
|
||||
import { Util } from './util';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("StorageManager")
|
||||
export class StorageManager {
|
||||
private static _instance: StorageManager;
|
||||
|
||||
public static get instance () {
|
||||
if (this._instance) {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
this._instance = new StorageManager();
|
||||
this._instance.start();
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
private _jsonData: {[key: string]: any} = {};
|
||||
private _path: any = null;
|
||||
private KEY_CONFIG: string = 'template';
|
||||
private _markSave: boolean = false;
|
||||
private _saveTimer: number = -1;
|
||||
|
||||
start () {
|
||||
this._jsonData = {
|
||||
"userId": "",
|
||||
};
|
||||
|
||||
this._path = this._getConfigPath();
|
||||
|
||||
var content;
|
||||
if (sys.isNative) {
|
||||
var valueObject = native.fileUtils.getValueMapFromFile(this._path);
|
||||
content = valueObject[this.KEY_CONFIG];
|
||||
} else {
|
||||
content = sys.localStorage.getItem(this.KEY_CONFIG);
|
||||
}
|
||||
|
||||
log("content", content);
|
||||
|
||||
if (content && content.length) {
|
||||
if (content.startsWith('@')) {
|
||||
content = content.substring(1);
|
||||
content = Util.decrypt(content);
|
||||
}
|
||||
|
||||
try {
|
||||
//初始化操作
|
||||
var jsonData = JSON.parse(content);
|
||||
|
||||
log("content1", jsonData);
|
||||
this._jsonData = jsonData;
|
||||
}catch (excepaiton) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储配置文件,不保存到本地
|
||||
* @param {string}key 关键字
|
||||
* @param {any}value 存储值
|
||||
*/
|
||||
setConfigDataWithoutSave (key: string, value: any) {
|
||||
let account: string = this._jsonData.userId;
|
||||
if (this._jsonData[account]) {
|
||||
this._jsonData[account][key] = value;
|
||||
} else {
|
||||
console.error("no account can not save");
|
||||
}
|
||||
|
||||
this.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储配置文件,保存到本地
|
||||
* @param {string}key 关键字
|
||||
* @param {any}value 存储值
|
||||
*/
|
||||
setConfigData (key: string, value: any) {
|
||||
this.setConfigDataWithoutSave(key, value);
|
||||
this._markSave = true; //标记为需要存储,避免一直在写入,而是每隔一段时间进行写入
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据关键字获取数值
|
||||
* @param {string} key 关键字
|
||||
* @returns
|
||||
*/
|
||||
getConfigData (key: string) {
|
||||
let account: string = this._jsonData.userId;
|
||||
if (this._jsonData[account]) {
|
||||
var value = this._jsonData[account][key];
|
||||
return value ? value : "";
|
||||
} else {
|
||||
log("no account can not load");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置全局数据
|
||||
* @param {string} key 关键字
|
||||
* @param {any}value 存储值
|
||||
* @returns
|
||||
*/
|
||||
public setGlobalData (key:string, value: any) {
|
||||
this._jsonData[key] = value;
|
||||
this.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局数据
|
||||
* @param {string} key 关键字
|
||||
* @returns
|
||||
*/
|
||||
public getGlobalData (key:string) {
|
||||
return this._jsonData[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户唯一标示符
|
||||
* @param {string} userId 用户唯一标示符
|
||||
* @param {any}value 存储值
|
||||
* @returns
|
||||
*/
|
||||
public setUserId (userId:string) {
|
||||
this._jsonData.userId = userId;
|
||||
if (!this._jsonData[userId]) {
|
||||
this._jsonData[userId] = {};
|
||||
}
|
||||
|
||||
this.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户唯一标示符
|
||||
* @returns {string}
|
||||
*/
|
||||
public getUserId () {
|
||||
return this._jsonData.userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时存储
|
||||
* @returns
|
||||
*/
|
||||
public scheduleSave () {
|
||||
if (!this._markSave) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记为已修改
|
||||
*/
|
||||
public markModified () {
|
||||
this._markSave = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存配置文件
|
||||
* @returns
|
||||
*/
|
||||
public save () {
|
||||
// 写入文件
|
||||
var str = JSON.stringify(this._jsonData);
|
||||
let zipStr = '@' + Util.encrypt(str);
|
||||
|
||||
this._markSave = false;
|
||||
|
||||
if (!sys.isNative) {
|
||||
var ls = sys.localStorage;
|
||||
ls.setItem(this.KEY_CONFIG, zipStr);
|
||||
return;
|
||||
}
|
||||
|
||||
var valueObj: any = {};
|
||||
valueObj[this.KEY_CONFIG] = zipStr;
|
||||
native.fileUtils.writeValueMapToFile(valueObj, this._path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置文件路径
|
||||
* @returns 获取配置文件路径
|
||||
*/
|
||||
private _getConfigPath () {
|
||||
|
||||
let platform: any= sys.platform;
|
||||
|
||||
let path: string = "";
|
||||
|
||||
if (platform === sys.OS.WINDOWS) {
|
||||
path = "src/conf";
|
||||
} else if (platform === sys.OS.LINUX) {
|
||||
path = "./conf";
|
||||
} else {
|
||||
if (sys.isNative) {
|
||||
path = native.fileUtils.getWritablePath();
|
||||
path = path + "conf";
|
||||
} else {
|
||||
path = "src/conf";
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
11
assets/script/framework/storageManager.ts.meta
Normal file
11
assets/script/framework/storageManager.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "56893e3c-6d22-46c9-8a35-d9619ae9e789",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
287
assets/script/framework/uiManager.ts
Normal file
287
assets/script/framework/uiManager.ts
Normal file
@@ -0,0 +1,287 @@
|
||||
import { _decorator, Node, find, isValid} from "cc";
|
||||
import { ResourceUtil } from "./resourceUtil";
|
||||
import { PoolManager } from "./poolManager";
|
||||
import { Tips } from "../ui/common/tips";
|
||||
import { Constant } from "./constant";
|
||||
import { TransitionPanel } from "../ui/fight/transition_panel";
|
||||
import { TransitionBgPanel } from "../ui/fight/transition_bg_panel";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
const SHOW_STR_INTERVAL_TIME = 800;
|
||||
|
||||
@ccclass("UIManager")
|
||||
export class UIManager {
|
||||
private _dictSharedPanel: any = {}
|
||||
private _dictLoading: any = {}
|
||||
private _arrPopupDialog: any = []
|
||||
private _showTipsTime: number = 0
|
||||
private static _instance: UIManager;
|
||||
|
||||
public static get instance() {
|
||||
if (this._instance) {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
this._instance = new UIManager();
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前界面是否正在展示
|
||||
* @param panelPath
|
||||
*/
|
||||
public isDialogVisible(panelPath: string) {
|
||||
if (!this._dictSharedPanel.hasOwnProperty(panelPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let panel = this._dictSharedPanel[panelPath];
|
||||
return isValid(panel) && panel.active && panel.parent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 显示单例界面
|
||||
* @param {String} panelPath
|
||||
* @param {Array} args
|
||||
* @param {Function} cb 回调函数,创建完毕后回调
|
||||
*/
|
||||
public showDialog(panelPath: string, args?: any, cb?: Function, isTip?:boolean) {
|
||||
if (this._dictLoading[panelPath]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let idxSplit = panelPath.lastIndexOf('/');
|
||||
let scriptName = panelPath.slice(idxSplit + 1);
|
||||
|
||||
|
||||
if (!args) {
|
||||
args = [];
|
||||
}
|
||||
|
||||
if (this._dictSharedPanel.hasOwnProperty(panelPath)) {
|
||||
let panel = this._dictSharedPanel[panelPath];
|
||||
if (isValid(panel)) {
|
||||
var parent = null;
|
||||
if(isTip){
|
||||
parent = find("Canvas/ui/tip");
|
||||
}else{
|
||||
parent = find("Canvas/ui/dislog");
|
||||
}
|
||||
|
||||
panel.parent = parent;
|
||||
panel.active = true;
|
||||
let script = panel.getComponent(scriptName);
|
||||
let script2 = panel.getComponent(scriptName.charAt(0).toUpperCase() + scriptName.slice(1));
|
||||
|
||||
if (script && script.show) {
|
||||
script.show.apply(script, args);
|
||||
cb && cb(script);
|
||||
} else if (script2 && script2.show) {
|
||||
script2.show.apply(script2, args);
|
||||
cb && cb(script2);
|
||||
} else {
|
||||
throw `查找不到脚本文件${scriptName}`;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._dictLoading[panelPath] = true;
|
||||
ResourceUtil.createUI(panelPath, (err: any, node: any) => {
|
||||
//判断是否有可能在显示前已经被关掉了?
|
||||
let isCloseBeforeShow = false;
|
||||
if (!this._dictLoading[panelPath]) {
|
||||
//已经被关掉
|
||||
isCloseBeforeShow = true;
|
||||
}
|
||||
|
||||
this._dictLoading[panelPath] = false;
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
this._dictSharedPanel[panelPath] = node;
|
||||
|
||||
let script: any = node.getComponent(scriptName);
|
||||
let script2: any = node.getComponent(scriptName.charAt(0).toUpperCase() + scriptName.slice(1));
|
||||
if (script && script.show) {
|
||||
script.show.apply(script, args);
|
||||
cb && cb(script);
|
||||
} else if (script2 && script2.show) {
|
||||
script2.show.apply(script2, args);
|
||||
cb && cb(script2);
|
||||
} else {
|
||||
throw `查找不到脚本文件${scriptName}`;
|
||||
}
|
||||
|
||||
if (isCloseBeforeShow) {
|
||||
//如果在显示前又被关闭,则直接触发关闭掉
|
||||
this.hideDialog(panelPath);
|
||||
}
|
||||
}, isTip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏单例界面
|
||||
* @param {String} panelPath
|
||||
* @param {fn} callback
|
||||
*/
|
||||
public hideDialog(panelPath: string, callback?: Function) {
|
||||
if (this._dictSharedPanel.hasOwnProperty(panelPath)) {
|
||||
let panel = this._dictSharedPanel[panelPath];
|
||||
if (panel && isValid(panel)) {
|
||||
let ani = panel.getComponent('animationUI');
|
||||
if (ani) {
|
||||
ani.close(() => {
|
||||
panel.parent = null;
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
panel.parent = null;
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
} else if (callback && typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
this._dictLoading[panelPath] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将弹窗加入弹出窗队列
|
||||
* @param {string} panelPath
|
||||
* @param {string} scriptName
|
||||
* @param {*} param
|
||||
*/
|
||||
public pushToPopupSeq(panelPath: string, scriptName: string, param: any) {
|
||||
let popupDialog = {
|
||||
panelPath: panelPath,
|
||||
scriptName: scriptName,
|
||||
param: param,
|
||||
isShow: false
|
||||
};
|
||||
|
||||
this._arrPopupDialog.push(popupDialog);
|
||||
|
||||
this._checkPopupSeq();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将弹窗加入弹出窗队列
|
||||
* @param {number} index
|
||||
* @param {string} panelPath
|
||||
* @param {string} scriptName
|
||||
* @param {*} param
|
||||
*/
|
||||
public insertToPopupSeq(index: number, panelPath: string, param: any) {
|
||||
let popupDialog = {
|
||||
panelPath: panelPath,
|
||||
param: param,
|
||||
isShow: false
|
||||
};
|
||||
|
||||
this._arrPopupDialog.splice(index, 0, popupDialog);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将弹窗从弹出窗队列中移除
|
||||
* @param {string} panelPath
|
||||
*/
|
||||
public shiftFromPopupSeq(panelPath: string) {
|
||||
this.hideDialog(panelPath, () => {
|
||||
if (this._arrPopupDialog[0] && this._arrPopupDialog[0].panelPath === panelPath) {
|
||||
this._arrPopupDialog.shift();
|
||||
this._checkPopupSeq();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前是否需要弹窗
|
||||
*/
|
||||
private _checkPopupSeq() {
|
||||
if (this._arrPopupDialog.length > 0) {
|
||||
let first = this._arrPopupDialog[0];
|
||||
|
||||
if (!first.isShow) {
|
||||
this.showDialog(first.panelPath, first.param);
|
||||
this._arrPopupDialog[0].isShow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示提示
|
||||
* @param {String} content
|
||||
* @param {Function} cb
|
||||
*/
|
||||
public showTips(content: string | number, callback?: Function) {
|
||||
let str = String(content);
|
||||
let next = () => {
|
||||
this._showTipsAni(str, callback);
|
||||
}
|
||||
|
||||
var now = Date.now();
|
||||
if (now - this._showTipsTime < SHOW_STR_INTERVAL_TIME) {
|
||||
var spareTime = SHOW_STR_INTERVAL_TIME - (now - this._showTipsTime);
|
||||
setTimeout(() => {
|
||||
next();
|
||||
}, spareTime);
|
||||
|
||||
this._showTipsTime = now + spareTime;
|
||||
} else {
|
||||
next();
|
||||
this._showTipsTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部函数
|
||||
* @param {String} content
|
||||
* @param {Function} cb
|
||||
*/
|
||||
private _showTipsAni(content: string, callback?: Function) {
|
||||
ResourceUtil.getUIPrefabRes('common/tips', function (err: any, prefab: any) {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tipsNode = PoolManager.instance.getNode(prefab, find("Canvas") as Node);
|
||||
|
||||
let tipScript = tipsNode.getComponent(Tips) as Tips;
|
||||
tipScript.show(content, callback);
|
||||
});
|
||||
}
|
||||
|
||||
public showTransition(sceneName:string) {
|
||||
ResourceUtil.getUIPrefabRes(Constant.PANEL_NAME.TRANSITION, function (err: any, prefab: any) {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
let transitionNode = PoolManager.instance.getNode(prefab, find('') as Node);
|
||||
let transitionScript = transitionNode.getComponent(TransitionPanel) as TransitionPanel;
|
||||
transitionScript.show(sceneName);
|
||||
});
|
||||
}
|
||||
|
||||
public showTransitionBg(callback:Function) {
|
||||
ResourceUtil.getUIPrefabRes(Constant.PANEL_NAME.TRANSITION_BG, function (err: any, prefab: any) {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
let transitionNode = PoolManager.instance.getNode(prefab, find('Canvas/ui/tip') as Node);
|
||||
let transitionScript = transitionNode.getComponent(TransitionBgPanel) as TransitionBgPanel;
|
||||
transitionScript.show(callback);
|
||||
});
|
||||
}
|
||||
}
|
11
assets/script/framework/uiManager.ts.meta
Normal file
11
assets/script/framework/uiManager.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "f9384158-0e9e-46aa-85be-0adac295add4",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
12
assets/script/framework/util.meta
Normal file
12
assets/script/framework/util.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "4c8ec73a-d4c0-402c-8394-d4ae97d04575",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
902
assets/script/framework/util.ts
Normal file
902
assets/script/framework/util.ts
Normal file
@@ -0,0 +1,902 @@
|
||||
import { _decorator, Component, JsonAsset, Node, randomRange } from "cc";
|
||||
import { ResourceUtil } from "./resourceUtil";
|
||||
import { PlayerData } from "./playerData";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("Util")
|
||||
export class Util {
|
||||
/**
|
||||
* !#zh 拷贝object。
|
||||
*/
|
||||
/**
|
||||
* 深度拷贝
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断传入的参数是否为空的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: string) {
|
||||
return reHasUnicode.test(val);
|
||||
};
|
||||
|
||||
var unicodeToArray = function (val: string) {
|
||||
return val.match(reUnicode) || [];
|
||||
};
|
||||
|
||||
var asciiToArray = function (val: string) {
|
||||
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: string| number, end: string| number) {
|
||||
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, withoutHours: boolean = false, withoutMinutes: boolean = false, 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 (!withoutHours) {
|
||||
if (hour > 0) {
|
||||
timeStr += hour > 9 ? hour.toString() : '0' + hour;
|
||||
timeStr += ':';
|
||||
} else {
|
||||
timeStr += '00:';
|
||||
}
|
||||
}
|
||||
|
||||
if (!withoutMinutes) {
|
||||
timeStr += min > 9 ? min.toString() : '0' + min;
|
||||
timeStr += ':';
|
||||
}
|
||||
|
||||
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 {Array}arr 需要被随机的数组
|
||||
* @returns
|
||||
*/
|
||||
public static rand(arr: []): [] {
|
||||
let arrClone = this.clone(arr);
|
||||
// 首先从最大的数开始遍历,之后递减
|
||||
for (let i: number = arrClone.length - 1; i >= 0; i--) {
|
||||
// 随机索引值randomIndex是从0-arrClone.length中随机抽取的
|
||||
const randomIndex: number = Math.floor(Math.random() * (i + 1));
|
||||
// 下面三句相当于把从数组中随机抽取到的值与当前遍历的值互换位置
|
||||
const itemIndex: number = arrClone[randomIndex];
|
||||
arrClone[randomIndex] = arrClone[i];
|
||||
arrClone[i] = itemIndex;
|
||||
}
|
||||
// 每一次的遍历都相当于把从数组中随机抽取(不重复)的一个元素放到数组的最后面(索引顺序为:len-1,len-2,len-3......0)
|
||||
return arrClone;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得开始和结束两者之间相隔分钟数
|
||||
*
|
||||
* @static
|
||||
* @param {number} start
|
||||
* @param {number} end
|
||||
* @memberof Util
|
||||
*/
|
||||
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} 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) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前机型性能是否为低端机
|
||||
*/
|
||||
public static checkIsLowPhone(): Boolean {
|
||||
//@ts-ignore
|
||||
if (window.wx) {
|
||||
//微信性能数值参考:https://developers.weixin.qq.com/minigame/dev/guide/performance/perf-benchmarkLevel.html
|
||||
|
||||
let nowBenchmarkLevel: number = -1; //nowBenchmarkLevel = -1性能未知
|
||||
//@ts-ignore
|
||||
const sys = window.wx.getSystemInfoSync();
|
||||
const isIOS = sys.system.indexOf('iOS') >= 0;
|
||||
if (isIOS) {
|
||||
//微信不支持IO性能等级
|
||||
const model = sys.model;
|
||||
// iPhone 5s 及以下 设定为超低端机
|
||||
const ultraLowPhoneType = ['iPhone1,1', 'iPhone1,2', 'iPhone2,1', 'iPhone3,1', 'iPhone3,3', 'iPhone4,1', 'iPhone5,1', 'iPhone5,2', 'iPhone5,3', 'iPhone5,4', 'iPhone6,1', 'iPhone6,2'];
|
||||
// iPhone 6 ~ iPhone SE 设定为超低端机
|
||||
const lowPhoneType = ['iPhone6,2', 'iPhone7,1', 'iPhone7,2', 'iPhone8,1', 'iPhone8,2', 'iPhone8,4'];
|
||||
// iPhone 7 ~ iPhone X 设定为中端机
|
||||
const middlePhoneType = ['iPhone9,1', 'iPhone9,2', 'iPhone9,3', 'iPhone9,4', 'iPhone10,1', 'iPhone10,2', 'iPhone10,3', 'iPhone10,4', 'iPhone10,5', 'iPhone10,6'];
|
||||
// iPhone XS 及以上 设定为高端机
|
||||
const highPhoneType = ['iPhone11,2', 'iPhone11,4', 'iPhone11,6', 'iPhone11,8', 'iPhone12,1', 'iPhone12,3', 'iPhone12,5', 'iPhone12,8'];
|
||||
for (let i = 0; i < ultraLowPhoneType.length; i++) {
|
||||
if (model.indexOf(ultraLowPhoneType[i]) >= 0)
|
||||
nowBenchmarkLevel = 5;
|
||||
}
|
||||
for (let i = 0; i < lowPhoneType.length; i++) {
|
||||
if (model.indexOf(lowPhoneType[i]) >= 0)
|
||||
nowBenchmarkLevel = 10;
|
||||
}
|
||||
for (let i = 0; i < middlePhoneType.length; i++) {
|
||||
if (model.indexOf(middlePhoneType[i]) >= 0)
|
||||
nowBenchmarkLevel = 20;
|
||||
}
|
||||
for (let i = 0; i < highPhoneType.length; i++) {
|
||||
if (model.indexOf(highPhoneType[i]) >= 0)
|
||||
nowBenchmarkLevel = 30;
|
||||
}
|
||||
} else {
|
||||
nowBenchmarkLevel = sys.benchmarkLevel;
|
||||
}
|
||||
|
||||
if (nowBenchmarkLevel < 22) { //22的具体参数可参考微信官方
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取两个节点坐标在xz轴的距离
|
||||
*
|
||||
* @static
|
||||
* @param {Node} ndA
|
||||
* @param {Node} ndB
|
||||
* @param {boolean} [isLocal=false] 是否为本地坐标,反之为世界坐标
|
||||
* @return {*}
|
||||
* @memberof util
|
||||
*/
|
||||
public static getTwoNodeXZLength(ndA: Node, ndB: Node, isLocal: boolean = false) {
|
||||
const aX = isLocal ? ndA.position.x : ndA.worldPosition.x;
|
||||
const aZ = isLocal ? ndA.position.z : ndA.worldPosition.z;
|
||||
const bX = isLocal ? ndB.position.x : ndB.worldPosition.x;
|
||||
const bZ = isLocal ? ndB.position.z : ndB.worldPosition.z;
|
||||
return this.getTwoPosXZLength(aX, aZ, bX, bZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取两个坐标在xz轴的距离
|
||||
*
|
||||
* @static
|
||||
* @param {number} aX
|
||||
* @param {number} aZ
|
||||
* @param {number} bX
|
||||
* @param {number} bZ
|
||||
* @return {*}
|
||||
* @memberof util
|
||||
*/
|
||||
public static getTwoPosXZLength(aX: number, aZ: number, bX: number, bZ: number) {
|
||||
const x = aX - bX;
|
||||
const z = aZ - bZ;
|
||||
return Math.sqrt(x * x + z * z);
|
||||
}
|
||||
|
||||
public static distance (x: number, y: number, z: number) {
|
||||
return Math.sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机名字
|
||||
*
|
||||
* @static
|
||||
* @returns
|
||||
* @memberof Util
|
||||
*/
|
||||
public static createRandomName () {
|
||||
let name = "";
|
||||
for (let j = 0; j < Math.round(Math.random() * 3) + 1; j++) {
|
||||
name += String.fromCharCode(Math.round(Math.random() * 26) + 97);
|
||||
name += String.fromCharCode(Math.round(Math.random() * 20901) + 19968);
|
||||
|
||||
//打乱name
|
||||
if (Math.random() > 0.5) {
|
||||
name = name.split("").reverse().join("");
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机名字
|
||||
*
|
||||
* @param staticId
|
||||
*/
|
||||
public static async randomName (staticId:number) {
|
||||
let names: any = await ResourceUtil.loadResType("jsons/names", JsonAsset);
|
||||
var firsnames = names.json.firstnames;
|
||||
var boyNames = names.json.boyNames;
|
||||
var girlNames = names.json.girlNames;
|
||||
let lastName: string = '';
|
||||
if (staticId == 0) {
|
||||
lastName = boyNames[Math.floor(randomRange(0, 1) * boyNames.length)];
|
||||
} else {
|
||||
lastName = girlNames[Math.floor(randomRange(0, 1) * girlNames.length)];
|
||||
}
|
||||
|
||||
let firstName = firsnames[Math.floor(randomRange(0, 1) * firsnames.length)];
|
||||
var playerName = firstName + lastName;
|
||||
return playerName;
|
||||
}
|
||||
|
||||
}
|
11
assets/script/framework/util.ts.meta
Normal file
11
assets/script/framework/util.ts.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "5123890b-1801-4188-ba33-de0c5cc31b47",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
15
assets/script/framework/util/staticBatch.ts
Normal file
15
assets/script/framework/util/staticBatch.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { _decorator, Component, Node, BatchingUtility } from 'cc';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('StaticBatch')
|
||||
export class StaticBatch extends Component {
|
||||
|
||||
@property([Node])
|
||||
needBatches: Node[] = [];
|
||||
|
||||
start () {
|
||||
this.needBatches.forEach((node)=>{
|
||||
BatchingUtility.batchStaticModel(node, this.node);
|
||||
})
|
||||
}
|
||||
}
|
12
assets/script/framework/util/staticBatch.ts.meta
Normal file
12
assets/script/framework/util/staticBatch.ts.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "d5c7efbb-b2b1-4245-941f-009be3c9110a",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"moduleId": "project:///assets/script/framework/util/staticBatch.js",
|
||||
"simulateGlobals": []
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user