[add] Engine
This commit is contained in:
13
assets/Script/Engine/Utils/Act.meta
Normal file
13
assets/Script/Engine/Utils/Act.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "b43bf5ea-67c5-4fc8-9893-1f406a52508f",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
55
assets/Script/Engine/Utils/Act/Shake.ts
Normal file
55
assets/Script/Engine/Utils/Act/Shake.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
const { ccclass } = cc._decorator;
|
||||
|
||||
@ccclass
|
||||
export default class Shake extends cc.ActionInterval {
|
||||
private _init: boolean = false;
|
||||
private _initial_x: number = 0;
|
||||
private _initial_y: number = 0;
|
||||
private _strength_x: number = 0;
|
||||
private _strength_y: number = 0;
|
||||
|
||||
/**
|
||||
* 建立抖動動畫
|
||||
* @param {number} duration 動畫持續時長
|
||||
* @param {number} strength_x 抖動幅度: x方向
|
||||
* @param {number} strength_y 抖動幅度: y方向
|
||||
* @returns {Shake}
|
||||
*/
|
||||
public static create(duration: number, strength_x: number, strength_y: number): Shake {
|
||||
let act: Shake = new Shake();
|
||||
act.initWithDuration(duration, strength_x, strength_y);
|
||||
return act;
|
||||
}
|
||||
|
||||
public initWithDuration(duration: number, strength_x: number, strength_y: number): boolean {
|
||||
cc.ActionInterval.prototype['initWithDuration'].apply(this, arguments);
|
||||
this._strength_x = strength_x;
|
||||
this._strength_y = strength_y;
|
||||
return true;
|
||||
}
|
||||
|
||||
public fgRangeRand(min: number, max: number): number {
|
||||
let rnd: number = Math.random();
|
||||
return rnd * (max - min) + min;
|
||||
}
|
||||
|
||||
public update(time: number): void {
|
||||
let randx = this.fgRangeRand(-this._strength_x, this._strength_x);
|
||||
let randy = this.fgRangeRand(-this._strength_y, this._strength_y);
|
||||
this.getTarget()?.setPosition(randx + this._initial_x, randy + this._initial_y);
|
||||
}
|
||||
|
||||
public startWithTarget(target: cc.Node): void {
|
||||
cc.ActionInterval.prototype['startWithTarget'].apply(this, arguments);
|
||||
if (!this._init) {
|
||||
this._init = true;
|
||||
this._initial_x = target.x;
|
||||
this._initial_y = target.y;
|
||||
}
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
this.getTarget()?.setPosition(new cc.Vec2(this._initial_x, this._initial_y));
|
||||
cc.ActionInterval.prototype['stop'].apply(this);
|
||||
}
|
||||
}
|
10
assets/Script/Engine/Utils/Act/Shake.ts.meta
Normal file
10
assets/Script/Engine/Utils/Act/Shake.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "c5872cc0-91a4-49cb-a055-e037accd801d",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/Engine/Utils/Audio.meta
Normal file
13
assets/Script/Engine/Utils/Audio.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "d042d487-d962-4d90-920e-70ab9b8b383c",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
184
assets/Script/Engine/Utils/Audio/CSAudio.ts
Normal file
184
assets/Script/Engine/Utils/Audio/CSAudio.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
import LocalStorageData from "../../Data/LocalStorageData";
|
||||
|
||||
export default class CSAudio {
|
||||
private static _instance: CSAudio = null;
|
||||
public static get Instance(): CSAudio { return this._instance; }
|
||||
private _idToClip: Map<number, cc.AudioClip> = new Map<number, cc.AudioClip>();
|
||||
private _idToPath: Map<number, string> = new Map<number, string>();
|
||||
private _idToAudioId: Map<number, number> = new Map<number, number>();
|
||||
private _currentMusic: number = -1;
|
||||
/**判斷音效播放太過頻繁不疊加 */
|
||||
private _lastPlaySoundTime: Map<string, number> = new Map<string, number>();
|
||||
private readonly _canPlaySoundCutTime: number = 10;
|
||||
|
||||
constructor() {
|
||||
CSAudio._instance = this;
|
||||
if (LocalStorageData.Instance.MusicType) {
|
||||
this.SetMusicVolume(+LocalStorageData.Instance.MusicType);
|
||||
} else {
|
||||
this.SetMusicVolume(0.3);
|
||||
}
|
||||
if (LocalStorageData.Instance.SoundType) {
|
||||
this.SetSoundVolume(+LocalStorageData.Instance.SoundType);
|
||||
} else {
|
||||
this.SetSoundVolume(0.3);
|
||||
}
|
||||
}
|
||||
|
||||
public AddClipsInfo(clips: Map<number, cc.AudioClip>, pathes: Map<number, string>): void {
|
||||
this._idToClip = clips;
|
||||
this._idToPath = pathes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 設定AudioID
|
||||
* @param id
|
||||
* @param audioId
|
||||
*/
|
||||
private _setAudioId(id: number, audioId: number): void {
|
||||
this._idToAudioId.set(id, audioId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得AudioID
|
||||
* @param id
|
||||
*/
|
||||
private _getAudioId(id: number): number {
|
||||
if (this._idToAudioId.has(id)) {
|
||||
return this._idToAudioId.get(id);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打開音效音量
|
||||
*/
|
||||
public OpenSound(): void {
|
||||
this.SetSoundVolume(0.3);
|
||||
}
|
||||
/**
|
||||
* 關閉音效音量
|
||||
*/
|
||||
public CloseSound(): void {
|
||||
this.SetSoundVolume(0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 設定音效音量
|
||||
* @param volume
|
||||
*/
|
||||
public SetSoundVolume(volume: number): void {
|
||||
LocalStorageData.Instance.SoundType = volume.toString();
|
||||
cc.audioEngine.setEffectsVolume(volume);
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音效
|
||||
* @param id
|
||||
* @param loop
|
||||
*/
|
||||
public PlaySound(id: number, loop: boolean = false): void {
|
||||
// 靜音後有一禎仍然會撥放的問題:音量>0才撥放
|
||||
if (cc.audioEngine.getEffectsVolume() <= 0) {
|
||||
return;
|
||||
}
|
||||
if (this._idToClip.has(id)) {
|
||||
let path: string = this._idToPath.get(id);
|
||||
let timenum: number = new Date().getTime();
|
||||
if (!this._lastPlaySoundTime.has(path)) {
|
||||
this._lastPlaySoundTime.set(path, timenum);
|
||||
let audioId: number = cc.audioEngine.playEffect(this._idToClip.get(id), loop);
|
||||
this._setAudioId(id, audioId);
|
||||
} else {
|
||||
let lastTime: number = this._lastPlaySoundTime.get(path);
|
||||
if (timenum - lastTime > this._canPlaySoundCutTime) {
|
||||
this._lastPlaySoundTime.set(path, timenum);
|
||||
let audioId: number = cc.audioEngine.playEffect(this._idToClip.get(id), loop);
|
||||
this._setAudioId(id, audioId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cc.error("未知的Sound Id: ", id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止音效
|
||||
* @param id
|
||||
*/
|
||||
public StopSound(id: number): void {
|
||||
let audioId = this._getAudioId(id);
|
||||
if (audioId >= 0) {
|
||||
cc.audioEngine.stopEffect(audioId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打開音樂音量
|
||||
*/
|
||||
public OpenMusic(): void {
|
||||
this.SetMusicVolume(0.3);
|
||||
}
|
||||
/**
|
||||
* 關閉音樂音量
|
||||
*/
|
||||
public CloseMusic(): void {
|
||||
this.SetMusicVolume(0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 設定音樂音量
|
||||
* @param volume
|
||||
*/
|
||||
public SetMusicVolume(volume: number): void {
|
||||
cc.audioEngine.setMusicVolume(volume);
|
||||
LocalStorageData.Instance.MusicType = volume.toString();
|
||||
// 靜音後有一禎仍然會撥放的問題:背景音樂要回復
|
||||
if (this._currentMusic != -1 && volume > 0 && !cc.audioEngine.isMusicPlaying()) {
|
||||
this._ccMusicPlayId = cc.audioEngine.playMusic(this._idToClip.get(this._currentMusic), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 撥放音樂
|
||||
* @param id
|
||||
* @param loop
|
||||
*/
|
||||
public PlayMusic(id: number, loop: boolean = true): void {
|
||||
if (this._currentMusic != id) {
|
||||
if (this._idToClip.has(id)) {
|
||||
// 靜音後有一禎仍然會撥放的問題:音量>0才撥放
|
||||
if (cc.audioEngine.getMusicVolume() > 0) {
|
||||
this._ccMusicPlayId = cc.audioEngine.playMusic(this._idToClip.get(id), loop);
|
||||
}
|
||||
this._currentMusic = id;
|
||||
}
|
||||
else {
|
||||
cc.error("未知的Music Id: ", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
private _ccMusicPlayId: number = -1;
|
||||
private _currentMusicTime: number = -1;
|
||||
public pauseOrResume(isPause?: boolean) {
|
||||
if (isPause) {
|
||||
this._currentMusicTime = cc.audioEngine.getCurrentTime(this._ccMusicPlayId);
|
||||
cc.audioEngine.pauseAll();
|
||||
cc.audioEngine.stopMusic();
|
||||
} else {
|
||||
cc.audioEngine.resumeAll();
|
||||
cc.audioEngine.setCurrentTime(this._ccMusicPlayId, this._currentMusicTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止音樂
|
||||
* @param id
|
||||
*/
|
||||
public StopMusic(): void {
|
||||
cc.audioEngine.stopMusic();
|
||||
this._currentMusic = -1;
|
||||
}
|
||||
|
||||
}
|
10
assets/Script/Engine/Utils/Audio/CSAudio.ts.meta
Normal file
10
assets/Script/Engine/Utils/Audio/CSAudio.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "f3ba292a-ecad-4485-ab60-1cd3ee94979a",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
168
assets/Script/Engine/Utils/Audio/CSCommonAudios.ts
Normal file
168
assets/Script/Engine/Utils/Audio/CSCommonAudios.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import CSAudio from "./CSAudio";
|
||||
|
||||
export default class CSAppAudios {
|
||||
private static _instanceApp: CSAppAudios = null;
|
||||
public static get InstanceApp(): CSAppAudios { return this._instanceApp; }
|
||||
private _idToAppClip: Map<number, cc.AudioClip> = new Map<number, cc.AudioClip>();
|
||||
private _idToAppPath: Map<number, string> = new Map<number, string>();
|
||||
private _idToAppAudioId: Map<number, number> = new Map<number, number>();
|
||||
private _currentAppMusic: number = -1;
|
||||
/** 判斷音效播放太過頻繁不疊加 */
|
||||
private _lastAppPlaySoundTime: Map<string, number> = new Map<string, number>();
|
||||
private readonly _appCanPlaySoundCutTime: number = 10;
|
||||
constructor() {
|
||||
CSAppAudios._instanceApp = this;
|
||||
}
|
||||
|
||||
public AddAppClipsInfo(clips: Map<number, cc.AudioClip>, pathes: Map<number, string>): void {
|
||||
this._idToAppClip = clips;
|
||||
this._idToAppPath = pathes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 設定AudioID
|
||||
* @param id
|
||||
* @param audioId
|
||||
*/
|
||||
private _setAppAudioId(id: number, audioId: number): void {
|
||||
this._idToAppAudioId.set(id, audioId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打開音效音量
|
||||
*/
|
||||
public OpenSound(): void {
|
||||
CSAudio.Instance.OpenSound();
|
||||
}
|
||||
/**
|
||||
* 關閉音效音量
|
||||
*/
|
||||
public CloseSound(): void {
|
||||
CSAudio.Instance.CloseSound();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得AudioID
|
||||
* @param id
|
||||
*/
|
||||
private _getAppAudioId(id: number): number {
|
||||
if (this._idToAppAudioId.has(id)) {
|
||||
return this._idToAppAudioId.get(id);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放音效
|
||||
* @param id
|
||||
* @param loop
|
||||
*/
|
||||
public PlayAppSound(id: number, loop: boolean = false): void {
|
||||
// 靜音後有一禎仍然會撥放的問題:音量>0才撥放
|
||||
if (cc.audioEngine.getEffectsVolume() <= 0) {
|
||||
return;
|
||||
}
|
||||
if (this._idToAppClip.has(id)) {
|
||||
let path: string = this._idToAppPath.get(id);
|
||||
let timenum: number = new Date().getTime();
|
||||
if (!this._lastAppPlaySoundTime.has(path)) {
|
||||
this._lastAppPlaySoundTime.set(path, timenum);
|
||||
let audioId: number = cc.audioEngine.playEffect(this._idToAppClip.get(id), loop);
|
||||
this._setAppAudioId(id, audioId);
|
||||
} else {
|
||||
let lastTime: number = this._lastAppPlaySoundTime.get(path);
|
||||
if (timenum - lastTime > this._appCanPlaySoundCutTime) {
|
||||
this._lastAppPlaySoundTime.set(path, timenum);
|
||||
let audioId: number = cc.audioEngine.playEffect(this._idToAppClip.get(id), loop);
|
||||
this._setAppAudioId(id, audioId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cc.error("未知的Sound Id: ", id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止音效
|
||||
* @param id
|
||||
*/
|
||||
public StopAppSound(id: number): void {
|
||||
let audioId: number = this._getAppAudioId(id);
|
||||
if (audioId >= 0) {
|
||||
cc.audioEngine.stopEffect(audioId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打開音樂音量
|
||||
*/
|
||||
public OpenMusic(): void {
|
||||
this._setAppMusicVolume(0.3);
|
||||
CSAudio.Instance.OpenMusic();
|
||||
}
|
||||
/**
|
||||
* 關閉音樂音量
|
||||
*/
|
||||
public CloseMusic(): void {
|
||||
this._setAppMusicVolume(0.0); // 這邊再改改
|
||||
CSAudio.Instance.CloseMusic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 設定音樂音量
|
||||
* @param volume
|
||||
*/
|
||||
private _setAppMusicVolume(volume: number): void {
|
||||
// 靜音後有一禎仍然會撥放的問題:背景音樂要回復
|
||||
if (this._currentAppMusic != -1 && volume > 0 && !cc.audioEngine.isMusicPlaying()) {
|
||||
this._ccAppMusicPlayId = cc.audioEngine.playMusic(this._idToAppClip.get(this._currentAppMusic), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 撥放音樂
|
||||
* @param id
|
||||
* @param loop
|
||||
*/
|
||||
public PlayAppMusic(id: number, loop: boolean = true): void {
|
||||
if (this._currentAppMusic != id) {
|
||||
if (this._idToAppClip.has(id)) {
|
||||
// 靜音後有一禎仍然會撥放的問題:音量>0才撥放
|
||||
if (cc.audioEngine.getMusicVolume() > 0) {
|
||||
this._ccAppMusicPlayId = cc.audioEngine.playMusic(this._idToAppClip.get(id), loop);
|
||||
}
|
||||
this._currentAppMusic = id;
|
||||
} else {
|
||||
cc.error("未知的Music Id: ", id);
|
||||
}
|
||||
} else {
|
||||
this.StopMusic();
|
||||
this.PlayAppMusic(id);
|
||||
}
|
||||
}
|
||||
|
||||
private _ccAppMusicPlayId: number = -1;
|
||||
private _currentAppMusicTime: number = -1;
|
||||
|
||||
public pauseOrResume(isPause?: boolean): void {
|
||||
if (isPause) {
|
||||
this._currentAppMusicTime = cc.audioEngine.getCurrentTime(this._ccAppMusicPlayId);
|
||||
cc.audioEngine.pauseAll();
|
||||
cc.audioEngine.stopMusic();
|
||||
} else {
|
||||
cc.audioEngine.resumeAll();
|
||||
cc.audioEngine.setCurrentTime(this._ccAppMusicPlayId, this._currentAppMusicTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止音樂
|
||||
* @param id
|
||||
*/
|
||||
public StopMusic(): void {
|
||||
cc.audioEngine.stopMusic();
|
||||
this._currentAppMusic = -1;
|
||||
}
|
||||
|
||||
}
|
10
assets/Script/Engine/Utils/Audio/CSCommonAudios.ts.meta
Normal file
10
assets/Script/Engine/Utils/Audio/CSCommonAudios.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "ce946cad-16db-4383-a734-43bb8f14089e",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/Engine/Utils/Bezier.meta
Normal file
13
assets/Script/Engine/Utils/Bezier.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "4e2d4321-bbfb-46d8-87bc-15a7c99c000d",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
16
assets/Script/Engine/Utils/Bezier/Bezier.ts
Normal file
16
assets/Script/Engine/Utils/Bezier/Bezier.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export module Bezier {
|
||||
|
||||
export function GetPoint(p0: cc.Vec2, p1: cc.Vec2, p2: cc.Vec2, p3: cc.Vec2, t: number): cc.Vec2 {
|
||||
if (t < 0) {
|
||||
t = 0;
|
||||
}
|
||||
else if (t > 1) {
|
||||
t = 1
|
||||
}
|
||||
let OneMinusT = 1 - t;
|
||||
return p0.mul(OneMinusT * OneMinusT * OneMinusT)
|
||||
.add(p1.mul(3 * OneMinusT * OneMinusT * t))
|
||||
.add(p2.mul(3 * OneMinusT * t * t))
|
||||
.add(p3.mul(t * t * t));
|
||||
}
|
||||
}
|
10
assets/Script/Engine/Utils/Bezier/Bezier.ts.meta
Normal file
10
assets/Script/Engine/Utils/Bezier/Bezier.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "b47d81c4-01a1-45cd-94f8-19daf96f17a8",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/Engine/Utils/CCExtensions.meta
Normal file
13
assets/Script/Engine/Utils/CCExtensions.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "dcb480f5-98b4-4a48-9d82-e3e1fe837e8d",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
127
assets/Script/Engine/Utils/CCExtensions/ArrayExtension.ts
Normal file
127
assets/Script/Engine/Utils/CCExtensions/ArrayExtension.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
declare interface Array<T> {
|
||||
/**
|
||||
* 移除一個值並且回傳
|
||||
* @param index
|
||||
*/
|
||||
ExRemoveAt(index: number): T;
|
||||
/**
|
||||
* 移除全部值(注意. 參考的也會被清空)
|
||||
* @example
|
||||
*
|
||||
* let bar: number[] = [1, 2, 3];
|
||||
* let bar2: number[] = bar;
|
||||
* bar.Clear();
|
||||
* console.log(bar, bar2);
|
||||
*
|
||||
* // {
|
||||
* // "bar": [],
|
||||
* // "bar2": []
|
||||
* // }
|
||||
*/
|
||||
Clear(): void;
|
||||
/**
|
||||
* 物件陣列排序,asc&key陣列長度請一樣
|
||||
* PS. boolean 帶false是先true在false
|
||||
* @link JavaScript Object 排序 http://www.eion.com.tw/Blogger/?Pid=1170#:~:text=JavaScript%20Object%20排序
|
||||
* @param asc 是否升序排列(小到大)
|
||||
* @param key 需排序的key(優先順序左到右)(沒有就放空)
|
||||
*/
|
||||
ObjectSort(asc?: boolean[], key?: string[]): any[];
|
||||
/**
|
||||
* 設計給Array<cc.Component.EventHandler>forHoldButton使用
|
||||
* Add a non persistent listener to the UnityEvent.
|
||||
* @param call Callback function.
|
||||
*/
|
||||
AddListener(call: Function): void;
|
||||
}
|
||||
|
||||
Array.prototype.ExRemoveAt || Object.defineProperty(Array.prototype, "ExRemoveAt", {
|
||||
enumerable: false,
|
||||
value: function (index: number): any {
|
||||
let item: any = this.splice(index, 1);
|
||||
return item[0];
|
||||
}
|
||||
});
|
||||
|
||||
Array.prototype.Clear || Object.defineProperty(Array.prototype, "Clear", {
|
||||
enumerable: false,
|
||||
value: function (): void {
|
||||
this.length = 0;
|
||||
|
||||
// let foo: number[] = [1, 2, 3];
|
||||
// let bar: number[] = [1, 2, 3];
|
||||
// let foo2: number[] = foo;
|
||||
// let bar2: number[] = bar;
|
||||
// foo = [];
|
||||
// bar.length = 0;
|
||||
// console.log(foo, bar, foo2, bar2);
|
||||
|
||||
// {
|
||||
// "foo": [],
|
||||
// "bar": [],
|
||||
// "foo2": [
|
||||
// 1,
|
||||
// 2,
|
||||
// 3
|
||||
// ],
|
||||
// "bar2": []
|
||||
// }
|
||||
}
|
||||
});
|
||||
|
||||
Array.prototype.ObjectSort || Object.defineProperty(Array.prototype, "ObjectSort", {
|
||||
enumerable: false,
|
||||
/**
|
||||
* @param asc 是否升序排列(小到大)
|
||||
* @param key 需排序的key(優先順序左到右)(沒有就放空)
|
||||
*/
|
||||
value: function (asc: boolean[] = [true], key?: string[]): any[] {
|
||||
if (this.length === 0) {
|
||||
return this;
|
||||
} else if (!key || key.length === 0) {
|
||||
console.error(`ObjectSort key error`);
|
||||
return this;
|
||||
} else if (asc.length !== key.length) {
|
||||
console.error(`ObjectSort key asc error asc.length: ${asc.length}, key.length: ${key.length}`);
|
||||
return this;
|
||||
}
|
||||
for (let i: number = 0; i < key.length; i++) {
|
||||
const keyname: string = key[i];
|
||||
if (this[0][keyname] === undefined) {
|
||||
console.error(`ObjectSort has not key[${i}]: ${keyname}`);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
let count: number = key ? key.length : 1;
|
||||
let arr: any[];
|
||||
for (let i: number = count - 1; i >= 0; i--) {
|
||||
arr = this.sort(function (a: any, b: any): 1 | -1 {
|
||||
let mya: any = a;
|
||||
let myb: any = b;
|
||||
if (key) {
|
||||
mya = a[key[i]];
|
||||
myb = b[key[i]];
|
||||
}
|
||||
|
||||
// 加個等於數字相同不要再去排序到
|
||||
if (asc[i]) {
|
||||
return mya >= myb ? 1 : -1;
|
||||
} else {
|
||||
return mya <= myb ? 1 : -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
});
|
||||
|
||||
Array.prototype.AddListener || Object.defineProperty(Array.prototype, "AddListener", {
|
||||
enumerable: false,
|
||||
value: function (call: Function): void {
|
||||
let EventHandler: cc.Component.EventHandler = new cc.Component.EventHandler();
|
||||
EventHandler.target = <any>"Callback";
|
||||
EventHandler.component = "Callback";
|
||||
EventHandler.handler = <any>call;
|
||||
this.push(EventHandler);
|
||||
}
|
||||
});
|
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "02aa6cd7-21a1-4c22-bcbe-296bb938badd",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
429
assets/Script/Engine/Utils/CCExtensions/CCExtension.ts
Normal file
429
assets/Script/Engine/Utils/CCExtensions/CCExtension.ts
Normal file
@@ -0,0 +1,429 @@
|
||||
declare namespace cc {
|
||||
|
||||
export interface Node {
|
||||
/**
|
||||
* 設定世界座標
|
||||
* @param worldPoint
|
||||
*/
|
||||
SetWorldPosition(worldPoint: cc.Vec2 | cc.Vec3): void;
|
||||
/**
|
||||
* 取得世界座標
|
||||
*/
|
||||
GetWorldPosition(): cc.Vec2;
|
||||
/**
|
||||
* 取得目標在自己區域的相對座標
|
||||
* @param target
|
||||
*/
|
||||
GetTargetInMyLocalPosition(target: cc.Node): cc.Vec2;
|
||||
/**
|
||||
* 取得目標距離
|
||||
* @param target
|
||||
*/
|
||||
GetTargetDistance(target: cc.Node): number;
|
||||
/**
|
||||
* 設定長寬
|
||||
* @param size
|
||||
*/
|
||||
SetSizeDelta(size: cc.Vec2);
|
||||
/**
|
||||
* 取得長寬
|
||||
*/
|
||||
GetSizeDelta(): cc.Vec2;
|
||||
/**
|
||||
* 增加一個子物件
|
||||
* @param childObj
|
||||
*/
|
||||
ExAddChild(childObj: cc.Prefab | cc.Node, childActive?: boolean): cc.Node;
|
||||
|
||||
/**設定層級為最低層 */
|
||||
ExSetLowestOrder(): void;
|
||||
|
||||
/**設定層級為最高層 */
|
||||
ExSetHighestOrder(): void;
|
||||
|
||||
/**設定層級,比目標OBJ再低一層 */
|
||||
ExSetOrderUnderTheObj(obj: cc.Node, isNew?: boolean): number;
|
||||
|
||||
/**設定層級,比目標OBJ再高一層 */
|
||||
ExSetOrderOverTheObj(obj: cc.Node, isNew?: boolean): number;
|
||||
/**位置維持在原位 */
|
||||
ExSetParent(parentObj: cc.Node): void;
|
||||
ExSetGray(showGray: boolean): void;
|
||||
|
||||
/** 通過觀察目標來設置 rotation */
|
||||
ExLookAt(targetPos: cc.Vec3): void;
|
||||
|
||||
/**
|
||||
* !#zh
|
||||
* 当前节点的自身激活状态。<br/>
|
||||
* 值得注意的是,一个节点的父节点如果不被激活,那么即使它自身设为激活,它仍然无法激活。<br/>
|
||||
* 如果你想检查节点在场景中实际的激活状态可以使用 {{#crossLink "Node/activeInHierarchy:property"}}{{/crossLink}}。
|
||||
* @param value 当前节点的自身激活状态
|
||||
*/
|
||||
SetActive(value: boolean): void;
|
||||
}
|
||||
|
||||
// export interface ActionInterval {
|
||||
// step(dt: number): void;
|
||||
// }
|
||||
|
||||
export interface Tween {
|
||||
/**
|
||||
* 獲取持續時間
|
||||
* @example let duration = tween.duration();
|
||||
*/
|
||||
duration(): number;
|
||||
/**
|
||||
* 獲取已經進行的時間
|
||||
* @example let elapsed = tween.elapsed();
|
||||
*/
|
||||
elapsed(): number;
|
||||
/**
|
||||
* 跳轉到指定時間
|
||||
* @param time 時間(秒)
|
||||
* @example tween.goto(2);
|
||||
*/
|
||||
goto(time: number): void;
|
||||
}
|
||||
}
|
||||
|
||||
cc.Node.prototype.SetWorldPosition || Object.defineProperty(cc.Node.prototype, 'SetWorldPosition', {
|
||||
enumerable: false,
|
||||
value: function (cocosWorldPos: cc.Vec2 | cc.Vec3) {
|
||||
// let cocosWorldPos = new cc.Vec2(unityWorldPos.x + 711, unityWorldPos.y + 400);
|
||||
this.setPosition(this.parent.convertToNodeSpaceAR(cocosWorldPos));
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.GetWorldPosition || Object.defineProperty(cc.Node.prototype, 'GetWorldPosition', {
|
||||
enumerable: false,
|
||||
value: function () {
|
||||
let cocosWorldPos = this.parent.convertToWorldSpaceAR(this.position);
|
||||
// let unityWorldPos = new cc.Vec2(cocosWorldPos.x - 711, cocosWorldPos.y - 400);
|
||||
return cocosWorldPos;
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.GetTargetInMyLocalPosition || Object.defineProperty(cc.Node.prototype, 'GetTargetInMyLocalPosition', {
|
||||
enumerable: false,
|
||||
value: function (target: cc.Node): cc.Vec2 {
|
||||
let selfPos: cc.Vec2 = this.GetWorldPosition();
|
||||
let targetPos: cc.Vec2 = target.GetWorldPosition();
|
||||
let diff: cc.Vec2 = targetPos.sub(selfPos);
|
||||
let newPos: cc.Vec2 = this.getPosition().add(diff);
|
||||
return newPos;
|
||||
}
|
||||
});
|
||||
cc.Node.prototype.GetTargetDistance || Object.defineProperty(cc.Node.prototype, 'GetTargetDistance', {
|
||||
enumerable: false,
|
||||
value: function (target: cc.Node): number {
|
||||
let vector: cc.Vec2 = target.GetWorldPosition().sub(this.GetWorldPosition());
|
||||
let distance: number = vector.mag();
|
||||
return distance;
|
||||
}
|
||||
});
|
||||
cc.Node.prototype.SetSizeDelta || Object.defineProperty(cc.Node.prototype, 'SetSizeDelta', {
|
||||
enumerable: false,
|
||||
value: function (size: cc.Vec2) {
|
||||
this.setContentSize(size.x, size.y);
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.GetSizeDelta || Object.defineProperty(cc.Node.prototype, 'GetSizeDelta', {
|
||||
enumerable: false,
|
||||
value: function () {
|
||||
let size: cc.Size = this.GetSizeDelta();
|
||||
return new cc.Vec2(size.width, size.width);
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.ExAddChild || Object.defineProperty(cc.Node.prototype, 'ExAddChild', {
|
||||
enumerable: false,
|
||||
value: function (childObj: cc.Prefab | cc.Node, childActive: boolean = true) {
|
||||
let gameObj = null;
|
||||
if (childObj instanceof cc.Prefab) {
|
||||
gameObj = cc.instantiate(childObj);
|
||||
}
|
||||
else {
|
||||
gameObj = cc.instantiate(childObj);
|
||||
}
|
||||
gameObj.active = childActive ? true : childActive;
|
||||
gameObj.parent = this;
|
||||
return gameObj;
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.ExSetLowestOrder || Object.defineProperty(cc.Node.prototype, 'ExSetLowestOrder', {
|
||||
enumerable: false,
|
||||
value: function () {
|
||||
this.setSiblingIndex(0);
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.ExSetHighestOrder || Object.defineProperty(cc.Node.prototype, 'ExSetHighestOrder', {
|
||||
enumerable: false,
|
||||
value: function () {
|
||||
this.setSiblingIndex(Number.MAX_VALUE);
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.ExSetOrderUnderTheObj || Object.defineProperty(cc.Node.prototype, 'ExSetOrderUnderTheObj', {
|
||||
enumerable: false,
|
||||
value: function (obj: cc.Node, isNew?: boolean) {
|
||||
|
||||
let newIndex: number;
|
||||
let objIndex = obj.getSiblingIndex();
|
||||
|
||||
// 如果是新創的元件
|
||||
if (isNew) {
|
||||
newIndex = objIndex;
|
||||
}
|
||||
// 如果是已經在場景上的元件
|
||||
else {
|
||||
let myIndex = this.getSiblingIndex();
|
||||
|
||||
// 如果一開始就在它下面
|
||||
if (myIndex < objIndex) {
|
||||
newIndex = objIndex - 1;
|
||||
}
|
||||
else {
|
||||
newIndex = objIndex;
|
||||
}
|
||||
}
|
||||
this.setSiblingIndex(newIndex);
|
||||
return newIndex;
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.ExSetOrderOverTheObj || Object.defineProperty(cc.Node.prototype, 'ExSetOrderOverTheObj', {
|
||||
enumerable: false,
|
||||
value: function (obj: cc.Node, isNew?: boolean) {
|
||||
let newIndex: number;
|
||||
let objIndex = obj.getSiblingIndex();
|
||||
|
||||
// 如果是新創的元件
|
||||
if (isNew) {
|
||||
newIndex = objIndex + 1;
|
||||
}
|
||||
// 如果是已經在場景上的元件
|
||||
else {
|
||||
let myIndex = this.getSiblingIndex();
|
||||
|
||||
// 如果一開始就在它下面
|
||||
if (myIndex < objIndex) {
|
||||
newIndex = objIndex;
|
||||
}
|
||||
else {
|
||||
newIndex = objIndex + 1;
|
||||
}
|
||||
}
|
||||
this.setSiblingIndex(newIndex);
|
||||
return newIndex;
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.ExSetParent || Object.defineProperty(cc.Node.prototype, 'ExSetParent', {
|
||||
enumerable: false,
|
||||
value: function (parentObj: cc.Node) {
|
||||
let oriPos = this.GetWorldPosition();
|
||||
this.setParent(parentObj);
|
||||
this.SetWorldPosition(oriPos);
|
||||
}
|
||||
})
|
||||
cc.Node.prototype.ExSetGray || Object.defineProperty(cc.Node.prototype, 'ExSetGray', {
|
||||
enumerable: false,
|
||||
value: function (showGray: boolean): void {
|
||||
let btn: cc.Button = this.getComponent(cc.Button);
|
||||
if (btn) {
|
||||
btn.interactable = !showGray;
|
||||
}
|
||||
let material: cc.Material = cc.Material.createWithBuiltin(showGray ? cc.Material.BUILTIN_NAME.GRAY_SPRITE.toString() : cc.Material.BUILTIN_NAME.SPRITE.toString(), 0);
|
||||
!showGray && material.define("USE_TEXTURE", true, 0);
|
||||
let spriteComs: any[] = this.getComponentsInChildren(cc.Sprite).concat(this.getComponentsInChildren(cc.Label));
|
||||
for (let sprite of spriteComs) {
|
||||
sprite.setMaterial(0, material);
|
||||
}
|
||||
|
||||
// 先使用createWithBuiltin,如果材質球一直Create沒被刪除,會在修改。
|
||||
// let material: cc.Material = cc.Material.getBuiltinMaterial(showGray ? cc.Material.BUILTIN_NAME.GRAY_SPRITE.toString() : cc.Material.BUILTIN_NAME.SPRITE.toString());
|
||||
// for (let sprite of spriteComs) {
|
||||
// if (showGray) {
|
||||
// sprite.setMaterial(0, cc.Material.getBuiltinMaterial('2d-gray-sprite'));
|
||||
// }
|
||||
// else {
|
||||
// sprite.setMaterial(0, cc.Material.getBuiltinMaterial('2d-sprite'));
|
||||
// }
|
||||
// }
|
||||
},
|
||||
});
|
||||
cc.Node.prototype.ExLookAt || Object.defineProperty(cc.Node.prototype, "ExLookAt", {
|
||||
enumerable: false,
|
||||
value: function (targetPos: cc.Vec3): void {
|
||||
let TargetX: number = targetPos.x;
|
||||
let TargetY: number = targetPos.y;
|
||||
let SelfX: number = this.x;
|
||||
let SelfY: number = this.y;
|
||||
let r1: number = Math.atan2(TargetX - SelfX, TargetY - SelfY);
|
||||
let angle: number = (180 * r1 / Math.PI);
|
||||
this.angle = -angle;
|
||||
},
|
||||
});
|
||||
cc.Node.prototype.SetActive || Object.defineProperty(cc.Node.prototype, "SetActive", {
|
||||
enumerable: false,
|
||||
value: function (value: boolean): void {
|
||||
this.active = value;
|
||||
},
|
||||
});
|
||||
// cc.Node.prototype.SetWorldPosition = function (cocosWorldPos: cc.Vec2): void {
|
||||
// // let cocosWorldPos = new cc.Vec2(unityWorldPos.x + 711, unityWorldPos.y + 400);
|
||||
// this.setPosition(this.parent.convertToNodeSpaceAR(cocosWorldPos));
|
||||
// }
|
||||
// cc.Node.prototype.GetWorldPosition = function (): cc.Vec2 {
|
||||
// let cocosWorldPos = this.parent.convertToWorldSpaceAR(this.position);
|
||||
// // let unityWorldPos = new cc.Vec2(cocosWorldPos.x - 711, cocosWorldPos.y - 400);
|
||||
// return cocosWorldPos;
|
||||
// }
|
||||
|
||||
// cc.Node.prototype.SetSizeDelta = function (size: cc.Vec2) {
|
||||
// this.setContentSize(size.x, size.y);
|
||||
// }
|
||||
// cc.Node.prototype.GetSizeDelta = function (): cc.Vec2 {
|
||||
// let size: cc.Size = this.GetSizeDelta();
|
||||
// return new cc.Vec2(size.width, size.width);
|
||||
// }
|
||||
|
||||
// cc.Node.prototype.ExAddChild = function (childObj: cc.Prefab | cc.Node): cc.Node {
|
||||
|
||||
// let gameObj = null;
|
||||
// if (childObj instanceof cc.Prefab) {
|
||||
// gameObj = cc.instantiate(childObj);
|
||||
// }
|
||||
// else {
|
||||
// gameObj = cc.instantiate(childObj);
|
||||
// }
|
||||
// gameObj.parent = this;
|
||||
// return gameObj;
|
||||
// }
|
||||
|
||||
// cc.Node.prototype.ExSetLowestOrder = function (): void {
|
||||
// this.setSiblingIndex(0);
|
||||
// }
|
||||
// cc.Node.prototype.ExSetHighestOrder = function (): void {
|
||||
// this.setSiblingIndex(Number.MAX_VALUE);
|
||||
// }
|
||||
|
||||
|
||||
// cc.ActionInterval.prototype.step || Object.defineProperty(cc.ActionInterval.prototype, "step", {
|
||||
// enumerable: false,
|
||||
// value: function (dt: number): void {
|
||||
// if (this.paused) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (this._firstTick && !this._goto) {
|
||||
// this._firstTick = false;
|
||||
// this._elapsed = 0;
|
||||
// } else {
|
||||
// this._elapsed += dt;
|
||||
// }
|
||||
|
||||
// let t: number = this._elapsed / (this._duration > 0.0000001192092896 ? this._duration : 0.0000001192092896);
|
||||
// t = (1 > t ? t : 1);
|
||||
// this.update(t > 0 ? t : 0);
|
||||
|
||||
// // Compatible with repeat class, Discard after can be deleted (this._repeatMethod)
|
||||
// if (this._repeatMethod && this._timesForRepeat > 1 && this.isDone()) {
|
||||
// if (!this._repeatForever) {
|
||||
// this._timesForRepeat--;
|
||||
// }
|
||||
// this.startWithTarget(this.target);
|
||||
// this.step(this._elapsed - this._duration);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// /**
|
||||
// * 暂停
|
||||
// * @example tween.pause();
|
||||
// */
|
||||
// cc.Tween.prototype.pause = function () {
|
||||
// this._finalAction.paused = true;
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * 恢复
|
||||
// * @example tween.resume();
|
||||
// */
|
||||
// cc.Tween.prototype.resume = function () {
|
||||
// this._finalAction.paused = false;
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * 倍速播放
|
||||
// * @param speed 倍速
|
||||
// * @example tween.speed(2);
|
||||
// */
|
||||
// cc.Tween.prototype.speed = function (speed) {
|
||||
// this._finalAction._speedMethod = true;
|
||||
// this._finalAction._speed = speed;
|
||||
// }
|
||||
|
||||
cc.Tween.prototype.duration || Object.defineProperty(cc.Tween.prototype, "duration", {
|
||||
enumerable: false,
|
||||
value: function (): number {
|
||||
// let duration: number = this._finalAction._duration;
|
||||
let duration: number = 0;
|
||||
for (let i: number = 0; i < this["_actions"].length - 1; i++) {
|
||||
const action: any = this["_actions"][i];
|
||||
duration += action._duration;
|
||||
}
|
||||
// duration += ((cc.game.getFrameRate() / 3) / cc.game.getFrameRate());
|
||||
duration *= 1.3;
|
||||
return duration;
|
||||
}
|
||||
});
|
||||
|
||||
cc.Tween.prototype.elapsed || Object.defineProperty(cc.Tween.prototype, "elapsed", {
|
||||
enumerable: false,
|
||||
value: function (): number {
|
||||
return this._finalAction._elapsed;
|
||||
}
|
||||
});
|
||||
|
||||
cc.Tween.prototype.goto || Object.defineProperty(cc.Tween.prototype, "goto", {
|
||||
enumerable: false,
|
||||
/**
|
||||
* @param time 時間(秒)
|
||||
*/
|
||||
value: function (time: number): void {
|
||||
this._finalAction._goto = true;
|
||||
this._finalAction._elapsed = time;
|
||||
}
|
||||
});
|
||||
|
||||
// cc.ActionManager.prototype.pauseByTag = function (tag, pause) {
|
||||
// if (tag === cc.Action.TAG_INVALID) {
|
||||
// cc.logID(1002);
|
||||
// }
|
||||
|
||||
// let hashTargets = this._hashTargets;
|
||||
// for (let name in hashTargets) {
|
||||
// let element = hashTargets[name];
|
||||
// for (let i = 0, l = element.actions.length; i < l; ++i) {
|
||||
// let action = element.actions[i];
|
||||
// if (action && action.getTag() === tag) {
|
||||
// action.paused = pause;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 根据标签暂停动作
|
||||
// * @param tag tween的标签
|
||||
// * @example cc.Tween.pauseByTag(100);
|
||||
// */
|
||||
// cc.Tween.pauseByTag = function (tag) {
|
||||
// cc.director.getActionManager().pauseByTag(tag, true);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 根据标签恢复动作
|
||||
// * @param tag tween的标签
|
||||
// * @example cc.Tween.resumeByTag(100);
|
||||
// */
|
||||
// cc.Tween.resumeByTag = function (tag) {
|
||||
// cc.director.getActionManager().pauseByTag(tag, false);
|
||||
// }
|
10
assets/Script/Engine/Utils/CCExtensions/CCExtension.ts.meta
Normal file
10
assets/Script/Engine/Utils/CCExtensions/CCExtension.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "b373f805-9297-4af5-8ea6-0a250649b5b0",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
189
assets/Script/Engine/Utils/CCExtensions/NumberExtension.ts
Normal file
189
assets/Script/Engine/Utils/CCExtensions/NumberExtension.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
|
||||
declare interface Number {
|
||||
|
||||
/**
|
||||
* 金額每三位數(千)加逗號, 並且補到小數點第2位
|
||||
* 輸出 41,038,560.00
|
||||
* @param precision 補到小數點第幾位
|
||||
* @param isPadZero 是否要補零
|
||||
* */
|
||||
ExFormatNumberWithComma(precision?: number, isPadZero?: boolean): string;
|
||||
/**
|
||||
* 基本4位數(9,999-999B-T)
|
||||
* */
|
||||
ExTransferToBMK(precision?: number,offset?: number): string;
|
||||
/**
|
||||
* 數字轉字串, 頭補0
|
||||
* @param size
|
||||
*/
|
||||
Pad(size: number): string;
|
||||
/**
|
||||
* 四捨五入到小數點第X位 (同server計算規則)
|
||||
* @param precision
|
||||
*/
|
||||
ExToNumRoundDecimal(precision: number): number;
|
||||
/**
|
||||
* 無條件捨去到小數點第X位
|
||||
* @param precision
|
||||
*/
|
||||
ExToNumFloorDecimal(precision: number): number;
|
||||
/**
|
||||
* 無條件捨去強制保留X位小數,如:2,會在2後面補上00.即2.00
|
||||
* @param precision 補到小數點第幾位
|
||||
* @param isPadZero 是否要補零
|
||||
*/
|
||||
ExToStringFloorDecimal(precision: number, isPadZero?: boolean): string;
|
||||
/**
|
||||
* 取整數)
|
||||
*/
|
||||
ExToInt():number;
|
||||
/**
|
||||
* 小數轉整數(支援科學符號)
|
||||
*/
|
||||
Float2Fixed():number;
|
||||
/**
|
||||
* 數字長度(支援科學符號)
|
||||
*/
|
||||
DigitLength():number;
|
||||
|
||||
target: number;
|
||||
|
||||
|
||||
}
|
||||
|
||||
Number.prototype.ExFormatNumberWithComma || Object.defineProperty(Number.prototype, 'ExFormatNumberWithComma', {
|
||||
enumerable: false,
|
||||
value: function (precision: number = 2, isPadZero: boolean = true) {
|
||||
|
||||
// let arr = String(this).split('.');
|
||||
let arr = this.ExToStringFloorDecimal(precision, isPadZero).split('.');
|
||||
let num = arr[0], result = '';
|
||||
while (num.length > 3) {
|
||||
result = ',' + num.slice(-3) + result;
|
||||
num = num.slice(0, num.length - 3);
|
||||
}
|
||||
if (num.length > 0) result = num + result;
|
||||
return arr[1] ? result + '.' + arr[1] : result;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Number.prototype.ExTransferToBMK || Object.defineProperty(Number.prototype, 'ExTransferToBMK', {
|
||||
enumerable: false,
|
||||
value: function (precision: number=2,offset: number = 0) {
|
||||
/**千 */
|
||||
let MONEY_1K: number = 1000;
|
||||
/**萬 */
|
||||
// let MONEY_10K: number = 10000;
|
||||
/**十萬 */
|
||||
// let MONEY_100K: number = 100000;
|
||||
/**百萬 */
|
||||
let MONEY_1M: number = 1000000;
|
||||
/**千萬 */
|
||||
// let MONEY_10M: number = 10000000;
|
||||
/**億 */
|
||||
// let MONEY_100M: number = 100000000;
|
||||
/**十億 */
|
||||
let MONEY_1B: number = 1000000000;
|
||||
/**百億 */
|
||||
// let MONEY_10B: number = 10000000000;
|
||||
/**千億 */
|
||||
// let MONEY_100B: number = 100000000000;
|
||||
/**兆 */
|
||||
// let MONEY_1T: number = 1000000000000;
|
||||
offset = Math.pow(10, offset);
|
||||
// if (this >= MONEY_1T * offset) {
|
||||
// //(3)1,000T
|
||||
// //1T~
|
||||
// return (~~(this / MONEY_1T)).ExFormatNumberWithComma(0) + "T";
|
||||
// }
|
||||
if (this >= MONEY_1B * offset) {
|
||||
//1,000B~900,000B
|
||||
//1B~900B
|
||||
return (this / MONEY_1B).ExFormatNumberWithComma(3, false) + "B";
|
||||
}
|
||||
else if (this >= MONEY_1M * offset) {
|
||||
//1,000M~900,000M
|
||||
//1M~900M
|
||||
return (this / MONEY_1M).ExFormatNumberWithComma(3, false) + "M";
|
||||
}
|
||||
else if (this >= MONEY_1K * offset) {
|
||||
//1,000K~900,000K
|
||||
//1K~90K
|
||||
return (this / MONEY_1K).ExFormatNumberWithComma(3, false) + "K";
|
||||
}
|
||||
else {
|
||||
//0~9,000,000
|
||||
//0~9,000
|
||||
return this.ExFormatNumberWithComma(precision);
|
||||
}
|
||||
}
|
||||
})
|
||||
Number.prototype.Pad || Object.defineProperty(Number.prototype, 'Pad', {
|
||||
enumerable: false,
|
||||
value: function (size: number) {
|
||||
let s = this + "";
|
||||
while (s.length < size) s = "0" + s;
|
||||
return s;
|
||||
}
|
||||
})
|
||||
Number.prototype.ExToNumRoundDecimal || Object.defineProperty(Number.prototype, 'ExToNumRoundDecimal', {
|
||||
enumerable: false,
|
||||
value: function (precision: number) {
|
||||
return Math.round(Math.round(this * Math.pow(10, (precision || 0) + 1)) / 10) / Math.pow(10, (precision || 0));
|
||||
}
|
||||
})
|
||||
Number.prototype.ExToInt || Object.defineProperty(Number.prototype, 'ExToInt',{
|
||||
enumerable: false,
|
||||
value: function (){
|
||||
return ~~this;
|
||||
}
|
||||
})
|
||||
Number.prototype.ExToNumFloorDecimal || Object.defineProperty(Number.prototype, 'ExToNumFloorDecimal', {
|
||||
enumerable: false,
|
||||
value: function (precision: number) {
|
||||
let str = this.toPrecision(12);
|
||||
let dotPos = str.indexOf('.');
|
||||
return dotPos == -1 ? this : +`${str.substr(0, dotPos + 1 + precision)}`;
|
||||
}
|
||||
})
|
||||
Number.prototype.ExToStringFloorDecimal || Object.defineProperty(Number.prototype, 'ExToStringFloorDecimal', {
|
||||
enumerable: false,
|
||||
value: function (precision: number, isPadZero: boolean = true) {
|
||||
// 取小數點第X位
|
||||
let f = this.ExToNumFloorDecimal(precision);
|
||||
let s = f.toString();
|
||||
// 補0
|
||||
if (isPadZero) {
|
||||
let rs = s.indexOf('.');
|
||||
if (rs < 0) {
|
||||
rs = s.length;
|
||||
s += '.';
|
||||
}
|
||||
while (s.length <= rs + precision) {
|
||||
s += '0';
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
})
|
||||
Number.prototype.Float2Fixed || Object.defineProperty(Number.prototype, 'Float2Fixed', {
|
||||
enumerable: false,
|
||||
value: function () {
|
||||
if (this.toString().indexOf('e') === -1) {
|
||||
return Number(this.toString().replace('.', ''));
|
||||
}
|
||||
const dLen = this.DigitLength();
|
||||
return dLen > 0 ? +parseFloat((this * Math.pow(10, dLen)).toPrecision(12)) : this;
|
||||
}
|
||||
})
|
||||
Number.prototype.DigitLength || Object.defineProperty(Number.prototype, 'DigitLength', {
|
||||
enumerable: false,
|
||||
value: function () {
|
||||
const eSplit = this.toString().split(/[eE]/);
|
||||
const len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0));
|
||||
return len > 0 ? len : 0;
|
||||
}
|
||||
})
|
||||
|
||||
|
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "788e7381-bee6-4b74-addb-c4aa4c4ff4e3",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/Engine/Utils/CovrtFile.meta
Normal file
13
assets/Script/Engine/Utils/CovrtFile.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "919cddcd-eed2-40a7-be67-2e21365fefe4",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
109
assets/Script/Engine/Utils/CovrtFile/ImageConver.ts
Normal file
109
assets/Script/Engine/Utils/CovrtFile/ImageConver.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
export module ImageConver {
|
||||
export function ImageToBase64(Texture2D: cc.Texture2D): string {
|
||||
let image: ImageBitmap = Texture2D["_image"];
|
||||
let cv: HTMLCanvasElement = document.createElement("canvas");
|
||||
let context: CanvasRenderingContext2D = cv.getContext("2d");
|
||||
cv.width = image.width || 128;
|
||||
cv.height = image.height || 128;
|
||||
context.drawImage(image, 0, 0, image.width || 128, image.height || 128);
|
||||
let DataURL: string = cv.toDataURL();
|
||||
return DataURL;
|
||||
}
|
||||
export function Base64toBlob(b64Data: any, contentType: string = "image/png", sliceSize: number = 512): Blob {
|
||||
let byteCharacters: string = atob(b64Data.substring(b64Data.indexOf(",") + 1));
|
||||
const byteArrays: any[] = [];
|
||||
for (let offset: number = 0; offset < byteCharacters.length; offset += sliceSize) {
|
||||
const slice: string = byteCharacters.slice(offset, offset + sliceSize);
|
||||
|
||||
const byteNumbers: any[] = new Array(slice.length);
|
||||
for (let i: number = 0; i < slice.length; i++) {
|
||||
byteNumbers[i] = slice.charCodeAt(i);
|
||||
}
|
||||
const byteArray: Uint8Array = new Uint8Array(byteNumbers);
|
||||
byteArrays.push(byteArray);
|
||||
}
|
||||
const blob: Blob = new Blob(byteArrays, { type: contentType });
|
||||
return blob;
|
||||
}
|
||||
|
||||
export function BlobToImageNode(BlobData: Blob, node: cc.Node): void {
|
||||
let reader: FileReader = new FileReader();
|
||||
reader.onloadend = function (): void {
|
||||
ImageConver.Base64ToImageNode(reader.result + "", node);
|
||||
};
|
||||
reader.readAsDataURL(BlobData);
|
||||
}
|
||||
|
||||
export function Base64ToImageNode(base64: string, node: cc.Node): void {
|
||||
let image: HTMLImageElement = new Image();
|
||||
image.src = base64;
|
||||
image.onload = function (): void {
|
||||
let texture: cc.Texture2D = new cc.Texture2D();
|
||||
texture.initWithElement(image);
|
||||
texture.handleLoadedTexture();
|
||||
let spriteFrame: cc.SpriteFrame = new cc.SpriteFrame(texture);
|
||||
let sprite: cc.Sprite = node.addComponent(cc.Sprite);
|
||||
sprite.spriteFrame = spriteFrame;
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
export function Node2Base64(nodeCapture: cc.Node): string {
|
||||
let nodeCamera: cc.Node = new cc.Node();
|
||||
nodeCamera.parent = cc.find("Canvas");
|
||||
let camera: cc.Camera = nodeCamera.addComponent(cc.Camera);
|
||||
|
||||
let position: cc.Vec2 = nodeCapture.getPosition();
|
||||
let width: number = nodeCapture.width;
|
||||
let height: number = nodeCapture.height;
|
||||
|
||||
// 当 alignWithScreen 为 true 的时候,摄像机会自动将视窗大小调整为整个屏幕的大小。如果想要完全自由地控制摄像机,则需要将 alignWithScreen 设置为 false。(v2.2.1 新增)
|
||||
camera.alignWithScreen = false;
|
||||
// 设置摄像机的投影模式是正交(true)还是透视(false)模式
|
||||
camera.ortho = true;
|
||||
// 摄像机在正交投影模式下的视窗大小。该属性在 alignWithScreen 设置为 false 时生效。
|
||||
camera.orthoSize = height / 2;
|
||||
|
||||
let texture: cc.RenderTexture = new cc.RenderTexture();
|
||||
// 如果截图内容中不包含 Mask 组件,可以不用传递第三个参数
|
||||
texture.initWithSize(width, height);
|
||||
|
||||
// 如果设置了 targetTexture,那么摄像机渲染的内容不会输出到屏幕上,而是会渲染到 targetTexture 上。
|
||||
camera.targetTexture = texture;
|
||||
|
||||
// 创建画布
|
||||
let canvas: HTMLCanvasElement = document.createElement("canvas");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
let ctx: CanvasRenderingContext2D = canvas.getContext("2d");
|
||||
|
||||
nodeCapture.setPosition(cc.Vec2.ZERO);
|
||||
// 渲染一次摄像机,即更新一次内容到 RenderTexture 中
|
||||
camera.render(nodeCapture);
|
||||
nodeCapture.setPosition(position);
|
||||
|
||||
// 从 render texture 读取像素数据,数据类型为 RGBA 格式的 Uint8Array 数组。
|
||||
// 默认每次调用此函数会生成一个大小为 (长 x 高 x 4) 的 Uint8Array。
|
||||
let data: Uint8Array = texture.readPixels();
|
||||
// write the render data
|
||||
// PNG 中 1 像素 = 32 bit(RGBA),1 byte = 8 bit,所以 1 像素 = 4 byte
|
||||
// 每行 width 像素,即 width * 4 字节
|
||||
let rowBytes: number = width * 4;
|
||||
for (let row: number = 0; row < height; row++) {
|
||||
// RenderTexture 得到的纹理是上下翻转的
|
||||
let srow: number = height - 1 - row;
|
||||
let imageData: ImageData = ctx.createImageData(width, 1);
|
||||
let start: number = srow * width * 4;
|
||||
for (let i: number = 0; i < rowBytes; i++) {
|
||||
imageData.data[i] = data[start + i];
|
||||
}
|
||||
|
||||
ctx.putImageData(imageData, 0, row);
|
||||
}
|
||||
|
||||
let dataURL: string = canvas.toDataURL("image/png");
|
||||
|
||||
return dataURL;
|
||||
}
|
||||
}
|
10
assets/Script/Engine/Utils/CovrtFile/ImageConver.ts.meta
Normal file
10
assets/Script/Engine/Utils/CovrtFile/ImageConver.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "425b00d6-0d47-4978-9a9f-235733348e3d",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/Engine/Utils/Number.meta
Normal file
13
assets/Script/Engine/Utils/Number.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "d6e55fc6-00b6-496a-aae2-74d694c1223b",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
192
assets/Script/Engine/Utils/Number/NumberEx.ts
Normal file
192
assets/Script/Engine/Utils/Number/NumberEx.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
import { CoroutineV2 } from "../../CatanEngine/CoroutineV2/CoroutineV2";
|
||||
import { RandomEx } from "./RandomEx";
|
||||
|
||||
export module NumberEx {
|
||||
/**
|
||||
* 數字滾動
|
||||
* @param startNum
|
||||
* @param endNum
|
||||
* @param callbackfn
|
||||
* @param chabgeRate
|
||||
*/
|
||||
export function* ChangeScore(startNum: number, endNum: number, callbackfn: (num: number) => void, sec: number) {
|
||||
let fps = 30;
|
||||
let waitTime = 0.03;
|
||||
let changeRate = sec * fps; // -1為了讓changeRate數字能混亂點
|
||||
changeRate = changeRate - 1 <= 0 ? changeRate : changeRate - 1;
|
||||
changeRate = 1 / changeRate;
|
||||
let diff = endNum - startNum;
|
||||
let isIncrease = endNum >= startNum;
|
||||
let tempScore = startNum;
|
||||
let counter = 0;
|
||||
//let randomRate = 0;
|
||||
while (true) {
|
||||
if (endNum != tempScore) {
|
||||
/*if (counter % 2 == 0) {
|
||||
if (isIncrease) {
|
||||
randomRate = RandomEx.GetFloat(0, diff * changeRate).ExToNumFloorDecimal(2);
|
||||
} else {
|
||||
randomRate = RandomEx.GetFloat(0, -diff * changeRate).ExToNumFloorDecimal(2);
|
||||
}
|
||||
} else {
|
||||
randomRate = -randomRate;
|
||||
}*/
|
||||
tempScore += diff * changeRate //+ randomRate;
|
||||
// 遞增
|
||||
if (isIncrease && tempScore > endNum) {
|
||||
tempScore = endNum;
|
||||
}
|
||||
// 遞減
|
||||
if (!isIncrease && tempScore < endNum) {
|
||||
tempScore = endNum;
|
||||
}
|
||||
callbackfn(tempScore.ExToInt());
|
||||
// yield null;
|
||||
counter++;
|
||||
yield CoroutineV2.WaitTime(waitTime);
|
||||
}
|
||||
else {
|
||||
callbackfn(endNum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 數字跳動
|
||||
* @param minNum 起始數字
|
||||
* @param maxNum 最終數字
|
||||
* @param callbackfn callbackfn
|
||||
* @param sec 時間
|
||||
*/
|
||||
export function* BeatScore(minNum: number, maxNum: number, endNum: number, callbackfn: (num: number) => void, sec: number): IterableIterator<any> {
|
||||
let fps: number = 13;
|
||||
let waitTime: number = 0.07;
|
||||
let changeRate: number = sec * fps; // -1為了讓changeRate數字能混亂點
|
||||
changeRate = changeRate - 1 <= 0 ? changeRate : changeRate - 1;
|
||||
changeRate = 1 / changeRate;
|
||||
let diff: number = maxNum - minNum;
|
||||
let isIncrease: boolean = maxNum >= minNum;
|
||||
let tempScore: number = minNum;
|
||||
let counter: number = 0;
|
||||
let randomRate: number = 0;
|
||||
let lastNum: number = minNum;
|
||||
let nowNum: number = minNum;
|
||||
while (true) {
|
||||
if (maxNum !== tempScore) {
|
||||
if (counter % 2 === 0) {
|
||||
if (isIncrease) {
|
||||
randomRate = RandomEx.GetFloat(0, diff * changeRate).ExToNumFloorDecimal(2);
|
||||
} else {
|
||||
randomRate = RandomEx.GetFloat(0, -diff * changeRate).ExToNumFloorDecimal(2);
|
||||
}
|
||||
} else {
|
||||
randomRate = -randomRate;
|
||||
}
|
||||
|
||||
tempScore += diff * changeRate + randomRate;
|
||||
// 遞增
|
||||
if (isIncrease && tempScore > maxNum) {
|
||||
tempScore = maxNum;
|
||||
}
|
||||
// 遞減
|
||||
if (!isIncrease && tempScore < maxNum) {
|
||||
tempScore = maxNum;
|
||||
}
|
||||
while (nowNum === lastNum) {
|
||||
nowNum = RandomEx.GetInt(minNum, maxNum + 1);
|
||||
}
|
||||
lastNum = nowNum;
|
||||
callbackfn(nowNum);
|
||||
// yield null;
|
||||
counter++;
|
||||
yield CoroutineV2.WaitTime(waitTime);
|
||||
} else {
|
||||
callbackfn(endNum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测数字是否越界,如果越界给出提示
|
||||
* @param {*number} num 输入数
|
||||
*/
|
||||
function checkBoundary(num: number) {
|
||||
if (_boundaryCheckingState) {
|
||||
if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
|
||||
console.warn(`${num} is beyond boundary when transfer to integer, the results may not be accurate`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 精确乘法
|
||||
*/
|
||||
export function times(num1: number, num2: number, ...others: number[]): number {
|
||||
if (others.length > 0) {
|
||||
return times(times(num1, num2), others[0], ...others.slice(1));
|
||||
}
|
||||
const num1Changed = num1.Float2Fixed();
|
||||
const num2Changed = num2.Float2Fixed();
|
||||
const baseNum = num1.DigitLength() + num2.DigitLength();
|
||||
const leftValue = num1Changed * num2Changed;
|
||||
|
||||
checkBoundary(leftValue);
|
||||
|
||||
return leftValue / Math.pow(10, baseNum);
|
||||
}
|
||||
|
||||
/**
|
||||
* 精确加法
|
||||
*/
|
||||
export function plus(num1: number, num2: number, ...others: number[]): number {
|
||||
if (others.length > 0) {
|
||||
return plus(plus(num1, num2), others[0], ...others.slice(1));
|
||||
}
|
||||
const baseNum = Math.pow(10, Math.max(num1.DigitLength(), num2.DigitLength()));
|
||||
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 精确减法
|
||||
*/
|
||||
export function minus(num1: number, num2: number, ...others: number[]): number {
|
||||
if (others.length > 0) {
|
||||
return minus(minus(num1, num2), others[0], ...others.slice(1));
|
||||
}
|
||||
const baseNum = Math.pow(10, Math.max(num1.DigitLength(), num2.DigitLength()));
|
||||
return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 精确除法
|
||||
*/
|
||||
export function divide(num1: number, num2: number, ...others: number[]): number {
|
||||
if (others.length > 0) {
|
||||
return divide(divide(num1, num2), others[0], ...others.slice(1));
|
||||
}
|
||||
const num1Changed = num1.Float2Fixed();
|
||||
const num2Changed = num2.Float2Fixed();
|
||||
checkBoundary(num1Changed);
|
||||
checkBoundary(num2Changed);
|
||||
return times((num1Changed / num2Changed), Math.pow(10, num2.DigitLength() - num1.DigitLength()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 四舍五入
|
||||
*/
|
||||
export function round(num: number, ratio: number): number {
|
||||
const base = Math.pow(10, ratio);
|
||||
return divide(Math.round(times(num, base)), base);
|
||||
}
|
||||
|
||||
let _boundaryCheckingState = false;
|
||||
/**
|
||||
* 是否进行边界检查
|
||||
* @param flag 标记开关,true 为开启,false 为关闭
|
||||
*/
|
||||
function enableBoundaryChecking(flag = true) {
|
||||
_boundaryCheckingState = flag;
|
||||
}
|
||||
}
|
10
assets/Script/Engine/Utils/Number/NumberEx.ts.meta
Normal file
10
assets/Script/Engine/Utils/Number/NumberEx.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "363f5f7f-0623-4013-8571-0bb5c1dc95e6",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
90
assets/Script/Engine/Utils/Number/RandomEx.ts
Normal file
90
assets/Script/Engine/Utils/Number/RandomEx.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
export module RandomEx {
|
||||
|
||||
/**
|
||||
* 取得隨機布林值
|
||||
*/
|
||||
export function GetBool() {
|
||||
return GetInt() >= 0;
|
||||
}
|
||||
/**
|
||||
* 取得隨機整數(回傳min ~ max - 1)
|
||||
* @param min
|
||||
* @param max
|
||||
*/
|
||||
export function GetInt(min: number = Number.MIN_VALUE, max: number = Number.MAX_VALUE): number {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
/**
|
||||
* 取得隨機小數
|
||||
* @param min
|
||||
* @param max
|
||||
*/
|
||||
export function GetFloat(min: number = Number.MIN_VALUE, max: number = Number.MAX_VALUE): number {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
/**
|
||||
* 隨機取得複數個不重複回傳
|
||||
* @param num 取得數量
|
||||
* @param items 陣列
|
||||
*/
|
||||
export function GetMultiNoRepeat(num: number, items: any[]): any[] {
|
||||
let result: any[] = [];
|
||||
for (let i: number = 0; i < num; i++) {
|
||||
let ran: number = Math.floor(Math.random() * items.length);
|
||||
let item = items.splice(ran, 1)[0];
|
||||
if (result.indexOf(item) == -1) {
|
||||
result.push(item);
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根據權重取得複數個不重複回傳
|
||||
* @param prize 獎項
|
||||
* @param weights 機率
|
||||
* @param count 數量
|
||||
*/
|
||||
export function GetMultiNoRepeatByWeight(prize: any[], weights: number[] = null, count: number = 1): any[] {
|
||||
if (weights === null) {
|
||||
weights = [];
|
||||
for (let i: number = 0; i < prize.length; i++) {
|
||||
weights.push(1);
|
||||
}
|
||||
}
|
||||
let target: any[] = [];
|
||||
for (let i: number = 0; i < count; i++) {
|
||||
let results: number[] = RandomEx.GetPrizeByWeight(prize, weights);
|
||||
prize.splice(results[0], 1);
|
||||
weights.splice(results[0], 1);
|
||||
target.push(results[1]);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根據權重隨機取值
|
||||
* @param prize 獎項
|
||||
* @param weights 機率
|
||||
*/
|
||||
export function GetPrizeByWeight(prize: any[], weights: number[]): any[] {
|
||||
if (prize.length !== weights.length) {
|
||||
console.error(`GetWeight error -> prize.length:${prize.length} !== weights.length:${weights.length}`);
|
||||
return null;
|
||||
}
|
||||
let totalWeight: number = 0;
|
||||
for (let i: number = 0; i < weights.length; i++) {
|
||||
totalWeight += weights[i];
|
||||
}
|
||||
let random: number = RandomEx.GetInt(0, totalWeight) + 1;
|
||||
let nowWeight: number = weights[0];
|
||||
for (let i: number = 0; i < weights.length; i++) {
|
||||
if (nowWeight >= random) {
|
||||
return [i, prize[i]];
|
||||
}
|
||||
nowWeight += weights[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
10
assets/Script/Engine/Utils/Number/RandomEx.ts.meta
Normal file
10
assets/Script/Engine/Utils/Number/RandomEx.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "ba4dee5b-ca5b-4435-a068-c4f5dd832bab",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/Engine/Utils/ScrollView.meta
Normal file
13
assets/Script/Engine/Utils/ScrollView.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "f6471056-03d8-4d55-b039-6b62d056547c",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
75
assets/Script/Engine/Utils/ScrollView/ScrollBase.ts
Normal file
75
assets/Script/Engine/Utils/ScrollView/ScrollBase.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { CoroutineV2 } from "../../CatanEngine/CoroutineV2/CoroutineV2";
|
||||
import UIPanel from "../../Component/UIPanel/UIPanel";
|
||||
import ScrollItem from "./ScrollItem";
|
||||
import UISuperLayout from "./UISuperLayout";
|
||||
|
||||
const { ccclass, property } = cc._decorator;
|
||||
|
||||
/** Scroll基底 */
|
||||
@ccclass
|
||||
export default class ScrollBase extends UIPanel {
|
||||
//#region 外調參數
|
||||
|
||||
@property({ displayName: "List", type: UISuperLayout })
|
||||
public List: UISuperLayout = null;
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region public
|
||||
|
||||
/** ListData */
|
||||
public get ListData(): any[] { throw new Error("ListData必須被override"); }
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region protected
|
||||
|
||||
/** 列表資料 */
|
||||
protected _listData: any[] = [];
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region ScrollView Function
|
||||
|
||||
/**
|
||||
* 創建/刷新列表
|
||||
* @param isScrollTo 0 不滾動
|
||||
* @param isScrollTo 1 滚动到头部
|
||||
* @param isScrollTo 2 滚动到尾部
|
||||
* @param isScrollTo 3 自动居中到最近Item
|
||||
*/
|
||||
public *CreateList(isScrollTo: number = 0): IterableIterator<any> {
|
||||
if (!this.node.active) {
|
||||
return;
|
||||
}
|
||||
this.List?.CreateItem(this.ListData.length);
|
||||
yield CoroutineV2.WaitTime(5 / cc.game.getFrameRate());
|
||||
switch (isScrollTo) {
|
||||
case 1: {
|
||||
this.List?.scrollToHeader(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
this.List?.scrollToFooter(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
this.List?.scrollToCenter();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public OnRefreshEvent(node: cc.Node, index: number): void {
|
||||
let listData: any[] = this.ListData;
|
||||
let info: any = listData[index];
|
||||
node.getComponent(ScrollItem).ImplementSet(info, this, index);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
10
assets/Script/Engine/Utils/ScrollView/ScrollBase.ts.meta
Normal file
10
assets/Script/Engine/Utils/ScrollView/ScrollBase.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "3e607467-693c-46a9-ac93-ab973e52024d",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
8
assets/Script/Engine/Utils/ScrollView/ScrollItem.ts
Normal file
8
assets/Script/Engine/Utils/ScrollView/ScrollItem.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
const { ccclass, property } = cc._decorator;
|
||||
@ccclass
|
||||
export default class ScrollItem extends cc.Component {
|
||||
ImplementSet(...iniData: any[]): void {
|
||||
//
|
||||
}
|
||||
}
|
10
assets/Script/Engine/Utils/ScrollView/ScrollItem.ts.meta
Normal file
10
assets/Script/Engine/Utils/ScrollView/ScrollItem.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "0a733d8c-80ae-4e0b-be1b-07dba226c237",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
1460
assets/Script/Engine/Utils/ScrollView/UISuperLayout.ts
Normal file
1460
assets/Script/Engine/Utils/ScrollView/UISuperLayout.ts
Normal file
File diff suppressed because it is too large
Load Diff
10
assets/Script/Engine/Utils/ScrollView/UISuperLayout.ts.meta
Normal file
10
assets/Script/Engine/Utils/ScrollView/UISuperLayout.ts.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "67f1a0e4-877e-4ad0-bc1b-e1175c620ca1",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
547
assets/Script/Engine/Utils/ScrollView/UISuperScrollView.ts
Normal file
547
assets/Script/Engine/Utils/ScrollView/UISuperScrollView.ts
Normal file
@@ -0,0 +1,547 @@
|
||||
import UISuperLayout from "./UISuperLayout";
|
||||
|
||||
|
||||
const { ccclass, property } = cc._decorator;
|
||||
|
||||
const quintEaseOut: (time: number) => number = (time: number) => {
|
||||
time -= 1;
|
||||
return (time * time * time * time * time + 1);
|
||||
};
|
||||
const EPSILON = 1e-4;
|
||||
const OUT_OF_BOUNDARY_BREAKING_FACTOR = 0.05;
|
||||
var _tempVec2: cc.Vec2 = new cc.Vec2();
|
||||
export enum ScrollViewDirection {
|
||||
HORIZONTAL,
|
||||
VERTICAL,
|
||||
NONE,
|
||||
}
|
||||
|
||||
@ccclass
|
||||
export default class UISuperScrollview extends cc.ScrollView {
|
||||
private direction: ScrollViewDirection = ScrollViewDirection.NONE;
|
||||
private _layout: UISuperLayout;
|
||||
@property({
|
||||
tooltip: "注意!向上传递事件只会发送当前滑动相反方向,如果开启horizontal则会发送vertical事件。如果开启vertical则会发送horizontal事件。同时开启horizontal和vertical 不会发送任何事件"
|
||||
}) isTransmitEvent: boolean = false;
|
||||
@property pullRefresh: boolean = false;
|
||||
@property({
|
||||
displayName: "顶部偏移量",
|
||||
tooltip: "下拉时超过此偏移会发送下拉事件",
|
||||
visible: function () { return (this as any).pullRefresh; }
|
||||
}) headerOutOffset: number = 200;
|
||||
@property({
|
||||
displayName: "满足触发Header的倍数",
|
||||
visible: function () { return (this as any).pullRefresh; }
|
||||
}) headerMultiple: number = 2;
|
||||
@property({
|
||||
displayName: "底部偏移量",
|
||||
tooltip: "上拉时超过此偏移会发送上拉事件",
|
||||
visible: function () { return (this as any).pullRefresh; }
|
||||
}) footerOutOffset: number = 200;
|
||||
@property({
|
||||
displayName: "满足触发Footer的倍数",
|
||||
visible: function () { return (this as any).pullRefresh; }
|
||||
}) footerMultiple: number = 2;
|
||||
@property({
|
||||
type: cc.Component.EventHandler,
|
||||
visible: function () { return (this as any).pullRefresh; }
|
||||
}) headerEvents: cc.Component.EventHandler[] = [];
|
||||
@property({
|
||||
type: cc.Component.EventHandler,
|
||||
visible: function () { return (this as any).pullRefresh; }
|
||||
}) footerEvents: cc.Component.EventHandler[] = [];
|
||||
prevLocation: cc.Vec2 = new cc.Vec2();
|
||||
location: cc.Vec2 = new cc.Vec2();
|
||||
set autoScrolling(value: boolean) { (this as any)._autoScrolling = value; }
|
||||
private _touchBeganPosition = new cc.Vec2();
|
||||
private _touchEndPosition = new cc.Vec2();
|
||||
private isMoveHeader: boolean = false;
|
||||
private isMoveFooter: boolean = false;
|
||||
private isLockHeader: boolean = false;
|
||||
private isLockFooter: boolean = false;
|
||||
private headerProgress: number = 0;
|
||||
private footerProgress: number = 0;
|
||||
private isCustomScroll: boolean = false;
|
||||
canTouchMove: boolean = true;
|
||||
get view(): cc.Node { return this["_view"]; }
|
||||
onLoad() {
|
||||
if (this.layout && this.layout.autoCenter) {
|
||||
this.brake = 0.7;
|
||||
}
|
||||
}
|
||||
public onEnable() {
|
||||
super.onEnable();
|
||||
this.node.on("scroll-ended-with-threshold", this.dispatchPageTurningEvent, this);
|
||||
}
|
||||
public onDisable() {
|
||||
super.onDisable();
|
||||
this.node.off("scroll-ended-with-threshold", this.dispatchPageTurningEvent, this);
|
||||
}
|
||||
get layout() {
|
||||
if (!this._layout) {
|
||||
this._layout = this.content && this.content.getComponent(UISuperLayout);
|
||||
}
|
||||
return this._layout;
|
||||
}
|
||||
private isCallSoonFinish: boolean = false;
|
||||
get _curPageIdx() {
|
||||
return this.layout["_currPageIndex"];
|
||||
}
|
||||
getPages() {
|
||||
return new Array(this.layout.itemTotal);
|
||||
}
|
||||
protected _getContentTopBoundary() {
|
||||
if (!this.content) {
|
||||
return -1;
|
||||
}
|
||||
let offset = this.layout.isOfTopBoundary == 0 ? this["_topBoundary"] : this.layout.isOfTopBoundary;
|
||||
return offset;
|
||||
}
|
||||
protected _getContentBottomBoundary() {
|
||||
if (!this.content) {
|
||||
return -1;
|
||||
}
|
||||
let offset = this.layout.isOfButtomBoundary == 0 ? this["_bottomBoundary"] : this.layout.isOfButtomBoundary;
|
||||
return offset;
|
||||
}
|
||||
protected _getContentLeftBoundary() {
|
||||
if (!this.content) {
|
||||
return -1;
|
||||
}
|
||||
let offset = this.layout.isOfLeftBoundary == 0 ? this["_leftBoundary"] : this.layout.isOfLeftBoundary;
|
||||
return offset;
|
||||
}
|
||||
protected _getContentRightBoundary() {
|
||||
if (!this.content) {
|
||||
return -1;
|
||||
}
|
||||
let offset = this.layout.isOfRightBoundary == 0 ? this["_rightBoundary"] : this.layout.isOfRightBoundary;
|
||||
return offset;
|
||||
}
|
||||
|
||||
public _onTouchBegan(event: cc.Event.EventTouch, captureListeners?: Node[]): void {
|
||||
this.isCallSoonFinish = false;
|
||||
this.isCustomScroll = false;
|
||||
this.layout["onTouchBegin"]();
|
||||
if (!this.canTouchMove) {
|
||||
return;
|
||||
}
|
||||
this.direction = ScrollViewDirection.NONE;
|
||||
if (this.layout.isPageView) {
|
||||
_tempVec2 = event.getLocation();
|
||||
// cc.Vec2.set(this._touchBeganPosition, _tempVec2.x, _tempVec2.y)
|
||||
this._touchBeganPosition = cc.v2(_tempVec2.x, _tempVec2.y);
|
||||
}
|
||||
super["_onTouchBegan"](event, captureListeners);
|
||||
if (this.isTransmitEvent) {
|
||||
this.transmitEvent(event, cc.Node.EventType.TOUCH_START);
|
||||
}
|
||||
}
|
||||
public _onTouchMoved(event: cc.Event.EventTouch, captureListeners: any) {
|
||||
this.isCallSoonFinish = false;
|
||||
this.isCustomScroll = false;
|
||||
|
||||
if (!this.canTouchMove) return;
|
||||
if (this.isTransmitEvent) {
|
||||
if (this.direction == ScrollViewDirection.NONE) {
|
||||
var start = event.getStartLocation();
|
||||
var curre = event.getLocation();
|
||||
var xOffset = Math.abs(start.x - curre.x);
|
||||
var yOffset = Math.abs(start.y - curre.y);
|
||||
if (xOffset > yOffset) {
|
||||
// 本ScrollView滑动方向过程中达到一定偏移量是也可以向上发送事件
|
||||
// if (this.vertical) {
|
||||
// if (xOffset - yOffset > 50) {
|
||||
// this.direction = UIScrollViewDirection.HORIZONTAL
|
||||
// }
|
||||
// }
|
||||
this.direction = ScrollViewDirection.HORIZONTAL;
|
||||
|
||||
} else if (yOffset > xOffset) {
|
||||
// 本ScrollView滑动方向过程中达到一定偏移量是也可以向上发送事件
|
||||
// if (this.horizontal) {
|
||||
// if (yOffset - xOffset > 50) {
|
||||
// this.direction = UIScrollViewDirection.VERTICAL
|
||||
// }
|
||||
// }
|
||||
this.direction = ScrollViewDirection.VERTICAL;
|
||||
}
|
||||
}
|
||||
var canTransmit = (this.vertical && this.direction === ScrollViewDirection.HORIZONTAL) || this.horizontal && this.direction == ScrollViewDirection.VERTICAL;
|
||||
if (canTransmit) {
|
||||
this.transmitEvent(event, cc.Node.EventType.TOUCH_MOVE);
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.prevLocation = event.touch.getPreviousLocation();
|
||||
this.location = event.touch.getLocation();
|
||||
super["_onTouchMoved"](event, captureListeners);
|
||||
if (this.pullRefresh) {
|
||||
let outOfBoundary = this["_getHowMuchOutOfBoundary"]();
|
||||
let offset = this.vertical ? outOfBoundary.y : -outOfBoundary.x;
|
||||
if (offset > 0 && !this.isLockHeader && !this.isLockFooter) {
|
||||
this.headerProgress = offset < EPSILON ? 0 : offset / this.headerOutOffset;
|
||||
this.isMoveHeader = this.headerProgress >= this.headerMultiple;
|
||||
cc.Component.EventHandler.emitEvents(this.headerEvents, this, { action: false, progress: this.headerProgress, stage: this.isMoveHeader ? "wait" : "touch" });
|
||||
cc.Component.EventHandler.emitEvents(this.footerEvents, this, { action: false, progress: 0, stage: "release" });
|
||||
} else if (offset < 0 && !this.isLockHeader && !this.isLockFooter) {
|
||||
this.footerProgress = -offset < EPSILON ? 0 : -offset / this.footerOutOffset;
|
||||
this.isMoveFooter = this.footerProgress >= this.footerMultiple;
|
||||
cc.Component.EventHandler.emitEvents(this.footerEvents, this, { action: false, progress: this.footerProgress, stage: this.isMoveFooter ? "wait" : "touch" });
|
||||
cc.Component.EventHandler.emitEvents(this.headerEvents, this, { action: false, progress: 0, stage: "release" });
|
||||
} else if (offset == 0 && !this.isLockHeader && !this.isLockFooter) {
|
||||
this.clearProgress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public _onTouchEnded(event: cc.Event.EventTouch, captureListeners: any) {
|
||||
this.isCallSoonFinish = false;
|
||||
this.isCustomScroll = false;
|
||||
if (!this.canTouchMove) return;
|
||||
if (this.layout.isPageView) {
|
||||
_tempVec2 = event.getLocation();
|
||||
// cc.Vec2.set(this._touchEndPosition, _tempVec2.x, _tempVec2.y)
|
||||
this._touchEndPosition = cc.v2(_tempVec2.x, _tempVec2.y);
|
||||
}
|
||||
super["_onTouchEnded"](event, captureListeners);
|
||||
if (this.isTransmitEvent) {
|
||||
this.transmitEvent(event, cc.Node.EventType.TOUCH_END);
|
||||
}
|
||||
}
|
||||
public _onTouchCancelled(event: cc.Event.EventTouch, captureListeners: any) {
|
||||
this.isCallSoonFinish = false;
|
||||
this.isCustomScroll = false;
|
||||
if (!this.canTouchMove) return;
|
||||
if (this.layout.isPageView) {
|
||||
_tempVec2 = event.getLocation();
|
||||
// cc.Vec2.set(this._touchEndPosition, _tempVec2.x, _tempVec2.y)
|
||||
this._touchEndPosition = cc.v2(_tempVec2.x, _tempVec2.y);
|
||||
}
|
||||
if (this.isTransmitEvent) {
|
||||
this.transmitEvent(event, cc.Node.EventType.TOUCH_CANCEL);
|
||||
}
|
||||
super["_onTouchCancelled"](event, captureListeners);
|
||||
}
|
||||
scrollToAny(moveDelta: cc.Vec2, timeInSecond?: number, attenuated: boolean = true) {
|
||||
this.isCustomScroll = true;
|
||||
if (timeInSecond) {
|
||||
this._startAutoScroll(moveDelta, timeInSecond, attenuated, true);
|
||||
} else {
|
||||
this["_moveContent"](moveDelta);
|
||||
}
|
||||
}
|
||||
release() {
|
||||
this.isMoveHeader = false;
|
||||
this.isMoveFooter = false;
|
||||
if (this.isLockHeader || this.isLockFooter) {
|
||||
this.vertical && this.isLockHeader && (this["_topBoundary"] += this.headerOutOffset);
|
||||
this.vertical && this.isLockFooter && (this["_bottomBoundary"] -= this.footerOutOffset);
|
||||
this.horizontal && this.isLockHeader && (this["_leftBoundary"] -= this.headerOutOffset);
|
||||
this.horizontal && this.isLockFooter && (this["_rightBoundary"] += this.footerOutOffset);
|
||||
this.clearProgress();
|
||||
this.layout["onPositionChanged"]();
|
||||
this.isLockHeader = false;
|
||||
this.isLockFooter = false;
|
||||
this.startAutoScroll();
|
||||
}
|
||||
}
|
||||
startAutoScroll() {
|
||||
this["_autoScrolling"] = true;
|
||||
this["_outOfBoundaryAmountDirty"] = true;
|
||||
}
|
||||
protected _startAutoScroll(deltaMove: any, timeInSecond: any, attenuated: any, flag: boolean = false) {
|
||||
if (this.pullRefresh) { // 如果没有刷新/加载的监听者 则不计算
|
||||
if (this.isMoveHeader && !this.isLockHeader) {
|
||||
if (this.vertical) {
|
||||
this["_topBoundary"] -= this.headerOutOffset;
|
||||
deltaMove.y -= this.headerOutOffset;
|
||||
}
|
||||
if (this.horizontal) {
|
||||
this["_leftBoundary"] += this.headerOutOffset;
|
||||
deltaMove.x += this.headerOutOffset;
|
||||
}
|
||||
this.isLockHeader = true;
|
||||
cc.Component.EventHandler.emitEvents(this.headerEvents, this, { action: true, progress: this.headerProgress, stage: 'lock' });
|
||||
} else if (this.isMoveFooter && !this.isLockFooter) {
|
||||
if (this.vertical) {
|
||||
this["_bottomBoundary"] += this.footerOutOffset;
|
||||
deltaMove.y += this.footerOutOffset;
|
||||
}
|
||||
if (this.horizontal) {
|
||||
this["_rightBoundary"] -= this.footerOutOffset;
|
||||
deltaMove.x -= this.footerOutOffset;
|
||||
}
|
||||
this.isLockFooter = true;
|
||||
cc.Component.EventHandler.emitEvents(this.footerEvents, this, { action: true, progress: this.footerProgress, stage: 'lock' });
|
||||
}
|
||||
}
|
||||
|
||||
super["_startAutoScroll"](deltaMove, timeInSecond, attenuated);
|
||||
if (!flag && this.layout.autoCenter) {
|
||||
const touchMoveVelocity = this["_calculateTouchMoveVelocity"]();
|
||||
if (!this.isQuicklyScrollable(touchMoveVelocity)) {
|
||||
this.soonFinish();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected _updateScrollBar(outOfBoundary: any) {
|
||||
super["_updateScrollBar"](cc.v2(outOfBoundary.x, outOfBoundary.y));
|
||||
if (this["_autoScrollBraking"]) return; // 自动回弹时不计算 (非手动)
|
||||
if (!this["_autoScrolling"]) return; // 非自动滚动时不计算
|
||||
if (!this.pullRefresh) return;
|
||||
let offset = this.vertical ? outOfBoundary.y : -outOfBoundary.x;
|
||||
if (offset > 0) { // 下滑
|
||||
let progress = offset < EPSILON ? 0 : offset / this.headerOutOffset; //根据参数 headerOutOffset 计算当前下滑的办百分比
|
||||
if (this.isLockHeader) {
|
||||
this.headerProgress = this.headerProgress == 1 ? this.headerProgress : Math.max(progress, 1);
|
||||
cc.Component.EventHandler.emitEvents(this.headerEvents, this, { action: false, progress: this.headerProgress, stage: "lock" });
|
||||
} else {
|
||||
this.headerProgress = progress < this.headerProgress ? progress : this.headerProgress;
|
||||
cc.Component.EventHandler.emitEvents(this.headerEvents, this, { action: false, progress: this.headerProgress, stage: "release" });
|
||||
}
|
||||
} else if (offset < 0) {
|
||||
let progress = -offset < EPSILON ? 0 : -offset / this.footerOutOffset; //根据参数 footerOutOffset 计算当前下滑的办百分比
|
||||
if (this.isLockFooter) {
|
||||
this.footerProgress = this.footerProgress == 1 ? this.footerProgress : Math.max(progress, 1);
|
||||
cc.Component.EventHandler.emitEvents(this.footerEvents, this, { action: false, progress: this.footerProgress, stage: "lock" });
|
||||
} else {
|
||||
this.footerProgress = progress < this.footerProgress ? progress : this.footerProgress;
|
||||
cc.Component.EventHandler.emitEvents(this.footerEvents, this, { action: false, progress: this.footerProgress, stage: "release" });
|
||||
}
|
||||
} else if (offset == 0) {
|
||||
// 正常滑动时 如果没有锁定头和尾时 释放所有进度
|
||||
if (!this.isLockHeader && !this.isLockFooter) {
|
||||
this.clearProgress();
|
||||
}
|
||||
}
|
||||
}
|
||||
private clearProgress() {
|
||||
cc.Component.EventHandler.emitEvents(this.headerEvents, this, { action: false, progress: 0, stage: "release" });
|
||||
cc.Component.EventHandler.emitEvents(this.footerEvents, this, { action: false, progress: 0, stage: "release" });
|
||||
}
|
||||
private dispatchPageTurningEvent() {
|
||||
if (this.layout["_lastPageIndex"] === this.layout["_currPageIndex"]) return;
|
||||
this.layout["_lastPageIndex"] = this.layout["_currPageIndex"];
|
||||
cc.Component.EventHandler.emitEvents(this.layout.pageEvents, this, "page-turning");
|
||||
this.node.emit("page-turning", this);
|
||||
}
|
||||
|
||||
protected _handleReleaseLogic(touch: any) {
|
||||
if (this.layout.isPageView) {
|
||||
this._autoScrollToPage();
|
||||
if (this["_scrolling"]) {
|
||||
this["_scrolling"] = false;
|
||||
if (!this["_autoScrolling"]) {
|
||||
this["_dispatchEvent"](cc.ScrollView.EventType.SCROLL_ENDED);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super["_handleReleaseLogic"](touch);
|
||||
}
|
||||
|
||||
}
|
||||
protected _autoScrollToPage() {
|
||||
const bounceBackStarted = this["_startBounceBackIfNeeded"]();
|
||||
if (bounceBackStarted) {
|
||||
const bounceBackAmount = this["_getHowMuchOutOfBoundary"]();
|
||||
this["_clampDelta"](bounceBackAmount);
|
||||
if (bounceBackAmount.x > 0 || bounceBackAmount.y < 0) {
|
||||
if (this.layout.horizontal) {
|
||||
if (this.layout.horizontalAxisDirection == UISuperLayout.HorizontalAxisDirection.LEFT_TO_RIGHT) {
|
||||
this.layout["_currPageIndex"] = this.layout.itemTotal === 0 ? 0 : this.layout.itemTotal - 1;
|
||||
} else {
|
||||
this.layout["_currPageIndex"] = 0;
|
||||
}
|
||||
} else {
|
||||
if (this.layout.verticalAxisDirection == UISuperLayout.VerticalAxisDirection.TOP_TO_BOTTOM) {
|
||||
this.layout["_currPageIndex"] = this.layout.itemTotal === 0 ? 0 : this.layout.itemTotal - 1;
|
||||
} else {
|
||||
this.layout["_currPageIndex"] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bounceBackAmount.x < 0 || bounceBackAmount.y > 0) {
|
||||
if (this.layout.horizontal) {
|
||||
if (this.layout.horizontalAxisDirection == UISuperLayout.HorizontalAxisDirection.LEFT_TO_RIGHT) {
|
||||
this.layout["_currPageIndex"] = 0;
|
||||
} else {
|
||||
this.layout["_currPageIndex"] = this.layout.itemTotal === 0 ? 0 : this.layout.itemTotal - 1;
|
||||
}
|
||||
} else {
|
||||
if (this.layout.verticalAxisDirection == UISuperLayout.VerticalAxisDirection.TOP_TO_BOTTOM) {
|
||||
this.layout["_currPageIndex"] = 0;
|
||||
} else {
|
||||
this.layout["_currPageIndex"] = this.layout.itemTotal === 0 ? 0 : this.layout.itemTotal - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.layout.indicator) {
|
||||
this.layout.indicator["_changedState"]();
|
||||
}
|
||||
} else {
|
||||
const moveOffset = new cc.Vec2();
|
||||
// cc.Vec2.subtract(moveOffset, this._touchBeganPosition, this._touchEndPosition)
|
||||
moveOffset.x = this._touchBeganPosition.x - this._touchEndPosition.x;
|
||||
moveOffset.y = this._touchBeganPosition.y - this._touchEndPosition.y;
|
||||
|
||||
|
||||
const index = this.layout["_currPageIndex"];
|
||||
var nextIndex = index + this.getDragDirection(moveOffset);
|
||||
var timeInSecond = this.layout.pageTurningSpeed * Math.abs(index - nextIndex);
|
||||
if (this.layout.footerLoop) {
|
||||
if (nextIndex >= this.layout.itemTotal) {
|
||||
nextIndex = 0;
|
||||
}
|
||||
}
|
||||
if (this.layout.headerLoop) {
|
||||
if (nextIndex < 0) {
|
||||
nextIndex = this.layout.itemTotal - 1;
|
||||
}
|
||||
}
|
||||
const count = this.layout.itemTotal;
|
||||
if (nextIndex < count) {
|
||||
if (this.isScrollable(moveOffset, index, nextIndex)) {
|
||||
this.scrollToPage(nextIndex, timeInSecond);
|
||||
return;
|
||||
} else {
|
||||
const touchMoveVelocity = this["_calculateTouchMoveVelocity"]();
|
||||
if (this.isQuicklyScrollable(touchMoveVelocity)) {
|
||||
this.scrollToPage(nextIndex, timeInSecond);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.scrollToPage(index, timeInSecond);
|
||||
}
|
||||
}
|
||||
savePageIndex(idx: number) {
|
||||
if (idx < 0 || idx >= this.layout.itemTotal) {
|
||||
return false;
|
||||
}
|
||||
this.layout["_currPageIndex"] = idx;
|
||||
if (this.layout.indicator) {
|
||||
this.layout.indicator["_changedState"]();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
protected scrollToPage(idx: number, timeInSecond = 0.3) {
|
||||
if (idx < 0 || idx >= this.layout.itemTotal) {
|
||||
return;
|
||||
}
|
||||
if (this.savePageIndex(idx)) {
|
||||
this.layout.scrollToIndex(idx, timeInSecond);
|
||||
}
|
||||
}
|
||||
// 快速滑动
|
||||
protected isQuicklyScrollable(touchMoveVelocity: cc.Vec3) {
|
||||
if (this.horizontal) {
|
||||
if (Math.abs(touchMoveVelocity.x) > this.layout.autoPageTurningThreshold) {
|
||||
return true;
|
||||
}
|
||||
} else if (this.vertical) {
|
||||
if (Math.abs(touchMoveVelocity.y) > this.layout.autoPageTurningThreshold) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
protected getDragDirection(moveOffset: cc.Vec2) {
|
||||
if (this.horizontal) {
|
||||
if (moveOffset.x === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (this.layout.horizontalAxisDirection == UISuperLayout.HorizontalAxisDirection.LEFT_TO_RIGHT) {
|
||||
return (moveOffset.x > 0 ? this.layout.groupItemTotal : -this.layout.groupItemTotal);
|
||||
} else {
|
||||
return (moveOffset.x < 0 ? this.layout.groupItemTotal : -this.layout.groupItemTotal);
|
||||
}
|
||||
} else {
|
||||
// 由于滚动 Y 轴的原点在在右上角所以应该是小于 0
|
||||
if (moveOffset.y === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (this.layout.verticalAxisDirection == UISuperLayout.VerticalAxisDirection.TOP_TO_BOTTOM) {
|
||||
return (moveOffset.y < 0 ? this.layout.groupItemTotal : -this.layout.groupItemTotal);
|
||||
} else {
|
||||
return (moveOffset.y > 0 ? this.layout.groupItemTotal : -this.layout.groupItemTotal);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 是否超过自动滚动临界值
|
||||
protected isScrollable(offset: cc.Vec2, index: number, nextIndex: number) {
|
||||
const viewTrans = this.view;
|
||||
if (!viewTrans) {
|
||||
return false;
|
||||
}
|
||||
if (this.horizontal) {
|
||||
return Math.abs(offset.x) >= viewTrans.width * this.layout.scrollThreshold;
|
||||
} else if (this.vertical) {
|
||||
return Math.abs(offset.y) >= viewTrans.height * this.layout.scrollThreshold;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
protected transmitEvent(event: any, eventType: string) {
|
||||
var e = new cc.Event.EventTouch(event.getTouches(), event.bubbles);
|
||||
e.type = eventType;
|
||||
e.touch = event.touch;
|
||||
let target: any = event.target;
|
||||
target.parent.dispatchEvent(e);
|
||||
}
|
||||
private soonFinish() {
|
||||
this.isCallSoonFinish = true;
|
||||
this.layout["soonFinish"]();
|
||||
}
|
||||
protected _processAutoScrolling(dt: number) {
|
||||
let isAutoScrollBrake = this["_isNecessaryAutoScrollBrake"]();
|
||||
let brakingFactor = isAutoScrollBrake ? OUT_OF_BOUNDARY_BREAKING_FACTOR : 1;
|
||||
this["_autoScrollAccumulatedTime"] += dt * (1 / brakingFactor);
|
||||
|
||||
let percentage = Math.min(1, this["_autoScrollAccumulatedTime"] / this["_autoScrollTotalTime"]);
|
||||
if (this["_autoScrollAttenuate"]) {
|
||||
percentage = quintEaseOut(percentage);
|
||||
}
|
||||
|
||||
let newPosition = this["_autoScrollStartPosition"].add(this["_autoScrollTargetDelta"].mul(percentage));
|
||||
let reachedEnd = Math.abs(percentage - 1) <= EPSILON;
|
||||
|
||||
let fireEvent = Math.abs(percentage - 1) <= this["getScrollEndedEventTiming"]();
|
||||
if (fireEvent && !this["_isScrollEndedWithThresholdEventFired"]) {
|
||||
this["_dispatchEvent"]('scroll-ended-with-threshold');
|
||||
this["_isScrollEndedWithThresholdEventFired"] = true;
|
||||
}
|
||||
|
||||
if (this.elastic) {
|
||||
let brakeOffsetPosition = newPosition.sub(this["_autoScrollBrakingStartPosition"]);
|
||||
if (isAutoScrollBrake) {
|
||||
brakeOffsetPosition = brakeOffsetPosition.mul(brakingFactor);
|
||||
}
|
||||
newPosition = this["_autoScrollBrakingStartPosition"].add(brakeOffsetPosition);
|
||||
} else {
|
||||
let moveDelta = newPosition.sub(this.getContentPosition());
|
||||
let outOfBoundary = this["_getHowMuchOutOfBoundary"](moveDelta);
|
||||
if (!outOfBoundary.fuzzyEquals(cc.v2(0, 0), EPSILON)) {
|
||||
newPosition = newPosition.add(outOfBoundary);
|
||||
reachedEnd = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (reachedEnd) {
|
||||
this["_autoScrolling"] = false;
|
||||
}
|
||||
if (this.layout.autoCenter && !this.isCallSoonFinish && !this.isCustomScroll) {
|
||||
if (this["_autoScrollTotalTime"] < 2 || percentage >= 0.8) {
|
||||
this.soonFinish();
|
||||
}
|
||||
}
|
||||
let deltaMove = newPosition.sub(this.getContentPosition());
|
||||
this["_moveContent"](this["_clampDelta"](deltaMove), reachedEnd);
|
||||
this["_dispatchEvent"]('scrolling');
|
||||
if (!this["_autoScrolling"]) {
|
||||
this["_isBouncing"] = false;
|
||||
this["_scrolling"] = false;
|
||||
this["_dispatchEvent"]('scroll-ended');
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "dfb04646-c016-4594-b7b3-8d83fa7a925a",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
Reference in New Issue
Block a user