[Init]Init commit

This commit is contained in:
kenyeh
2023-05-19 17:13:53 +08:00
parent f670fe1a11
commit 10690ac902
135 changed files with 59831 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
export interface IDisposer {
(): void
}
import { LocalEmitter } from "../external/LocalEmitter";
const { ccclass, property } = cc._decorator;
@ccclass
export default class BaseComp extends cc.Component {
_comp_id_: number = LocalEmitter.newCompId();
protected _pool: Array<IDisposer> = []
_frameCount = 0;
_frameLimit = 3;
canUpdate(){
this._frameCount++;
if(this._frameCount < this._frameLimit){
return false;
}
this._frameCount = 0;
return true;
}
getCompId() {
return this._comp_id_;
}
//注册监听
on(event: string, fn: Function) {
LocalEmitter.inst.on(this.getCompId(), event, fn);
}
//移除监听
off(event: string = null, fn: Function = null) {
LocalEmitter.inst.off(this.getCompId(), event, fn);
}
// 发送事件
emit(event: string = null, obj: any = null, obj2: any = null) {
LocalEmitter.inst.emit(event, obj, obj2);
}
initListener(config:{[key:string]:number}){
for(let key in config){
this.on(config[key].toString(), this[key].bind(this));
}
}
onDestroy() {
this.removeAllListeners();
}
removeAllListeners(){
LocalEmitter.inst.off(this.getCompId());
}
showPopWait(msg: string = "Vui lòng chờ..."): void {
LocalEmitter.inst.emit("showPopWait",{prompt:msg})
}
hidePopWait(): void {
LocalEmitter.inst.emit("hidePopWait")
}
mute(){
this._pool && this._pool.forEach((d) => d())
this._pool = [];
}
onDisable(){
this.mute();
}
onEnable(){
this.mute();
}
//加载图片资源
loadSpriteFrame(PrefabUrl, fun: Function): void {
cc.resources.load(PrefabUrl, cc.SpriteFrame, function (err, res) {
//检查资源加载
if (err) {
return
}
if (fun) {
fun(res)
}
})
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "a03bb1c4-40fd-4523-98d8-56698a9cd3cb",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}
+173
View File
@@ -0,0 +1,173 @@
/*
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
* @packageDocumentation
* @module ui
*/
import { CustomToggle } from './CustomToggleItem'
const { property, ccclass, help, executeInEditMode, executionOrder, menu } = cc._decorator
/**
* @en
* ToggleContainer is not a visible UI component but a way to modify the behavior of a set of Toggles. <br/>
* Toggles that belong to the same group could only have one of them to be switched on at a time.<br/>
* Note: All the first layer child node containing the toggle component will auto be added to the container.
*
* @zh
* ToggleGroup 不是一个可见的 UI 组件,它可以用来修改一组 Toggle 组件的行为。当一组 Toggle 属于同一个 ToggleGroup 的时候,<br/>
* 任何时候只能有一个 Toggle 处于选中状态。
*/
@ccclass
@executionOrder(110)
@menu('UI/CustomToggleGroup')
@executeInEditMode
export class CustomToggleGroup extends cc.Component {
@property(cc.Boolean)
protected _allowSwitchOff = false
/**
* @en
* If this setting is true, a toggle could be switched off and on when pressed.
* If it is false, it will make sure there is always only one toggle could be switched on
* and the already switched on toggle can't be switched off.
*
* @zh
* 如果这个设置为 true,那么 toggle 按钮在被点击的时候可以反复地被选中和未选中。
*/
@property({ tooltip: 'i18n:toggle_group.allowSwitchOff' })
get allowSwitchOff() {
return this._allowSwitchOff
}
set allowSwitchOff(value) {
this._allowSwitchOff = value
}
/**
* @en
* If Toggle is clicked, it will trigger event's handler.
*
* @zh
* Toggle 按钮的点击事件列表。
*/
@property({ type: [cc.Component.EventHandler], tooltip: 'i18n:toggle_group.check_events' })
public checkEvents: cc.Component.EventHandler[] = []
/**
* @en
* Read only property, return the toggle items array reference managed by ToggleContainer.
*
* @zh
* 只读属性,返回 toggleContainer 管理的 toggle 数组引用。
*/
get toggleItems() {
return this.node.children
.map((item) => {
const toggle = item.getComponent(CustomToggle)
if (toggle && toggle.enabled) {
return toggle
}
})
.filter(Boolean)
}
public onEnable() {
this.ensureValidState()
this.node.on(cc.Node.EventType.CHILD_ADDED, this.ensureValidState, this)
this.node.on(cc.Node.EventType.CHILD_REMOVED, this.ensureValidState, this)
}
public onDisable() {
this.node.off(cc.Node.EventType.CHILD_ADDED, this.ensureValidState, this)
this.node.off(cc.Node.EventType.CHILD_REMOVED, this.ensureValidState, this)
}
public activeToggles() {
return this.toggleItems.filter((x) => x!.isChecked)
}
public anyTogglesChecked() {
return !!this.toggleItems.find((x) => x!.isChecked)
}
/**
* @en
* Refresh the state of the managed toggles.
*
* @zh
* 刷新管理的 toggle 状态。
*
* @param toggle - 需要被更新的 toggle。
* @param emitEvent - 是否需要触发事件
*/
public notifyToggleCheck(toggle: CustomToggle, emitEvent = true) {
if (!this.enabledInHierarchy) {
return
}
for (let i = 0; i < this.toggleItems.length; i++) {
const item = this.toggleItems[i]!
if (item === toggle) {
continue
}
if (emitEvent) {
item.isChecked = false
} else {
item.setIsCheckedWithoutNotify(false)
}
}
if (this.checkEvents) {
cc.Component.EventHandler.emitEvents(this.checkEvents, toggle)
}
}
public ensureValidState() {
const toggles = this.toggleItems
if (!this._allowSwitchOff && !this.anyTogglesChecked() && toggles.length !== 0) {
const toggle = toggles[0]!
toggle.isChecked = true
this.notifyToggleCheck(toggle)
}
const activeToggles = this.activeToggles()
if (activeToggles.length > 1) {
const firstToggle = activeToggles[0]
for (let i = 0; i < activeToggles.length; ++i) {
const toggle = activeToggles[i]
if (toggle === firstToggle) {
continue
}
toggle!.isChecked = false
}
}
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "9e433cb7-86b6-4361-8b44-5e13446638fc",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}
+179
View File
@@ -0,0 +1,179 @@
/**
* @packageDocumentation
* @module ui
*/
import { CustomToggleGroup } from "./CustomToggleGroup"
const { property, ccclass, requireComponent, executionOrder, menu } = cc._decorator
export enum ToggleSwitchType {
active,
animation
}
/**
* @en
* The toggle component is a CheckBox, when it used together with a ToggleGroup,
* it could be treated as a RadioButton.
*
* @zh
* Toggle 是一个 CheckBox,当它和 ToggleGroup 一起使用的时候,可以变成 RadioButton。
*/
@ccclass
@executionOrder(110)
@menu('UI/CustomToggle')
export class CustomToggle extends cc.Component {
/**
* @en
* When this value is true, the check mark component will be enabled,
* otherwise the check mark component will be disabled.
*
* @zh
* 如果这个设置为 true,则 check mark 组件会处于 enabled 状态,否则处于 disabled 状态。
*/
@property
get isChecked() {
return this._isChecked
}
set isChecked(value) {
this._set(value)
}
set _resizeToTarget(value: boolean) {
// if (value) {
// this._resizeNodeToTargetNode();
// }
}
get _toggleContainer() {
const parent = this.node.parent!
if (parent instanceof cc.Node) {
return parent.getComponent(CustomToggleGroup)
}
return null
}
/**
* @en
* If Toggle is clicked, it will trigger event's handler.
*
* @zh
* Toggle 按钮的点击事件列表。
*/
@property({ type: [cc.Component.EventHandler], tooltip: 'i18n:toggle.check_events' })
public checkEvents: cc.Component.EventHandler[] = []
@property(cc.Boolean)
protected _isChecked = true
@property([cc.Node])
protected onNodeList: cc.Node[] = []
@property([cc.Node])
protected offNodeList: cc.Node[] = []
@property({ type: cc.Enum(ToggleSwitchType) })
toggleSwitchType: ToggleSwitchType = ToggleSwitchType.active
//是否關閉點擊事件
@property(cc.Boolean)
isDoNotEmitToggle = false
private toggleEventMap: Map<ToggleSwitchType, Function> = new Map([
[ToggleSwitchType.active, this.switchByActive.bind(this)],
[ToggleSwitchType.animation, this.switchByAnimation.bind(this)]
])
protected _internalToggle() {
if (this.isDoNotEmitToggle) {
return
}
this.isChecked = !this.isChecked
}
protected _set(value: boolean, emitEvent = true) {
if (this._isChecked == value) return
this._isChecked = value
const group = this._toggleContainer
if (group && group.enabled && this.enabled) {
if (value || (!group.anyTogglesChecked() && !group.allowSwitchOff)) {
this._isChecked = true
group.notifyToggleCheck(this as any, emitEvent)
}
}
this.playEffect()
if (emitEvent) {
this._emitToggleEvents()
}
}
//
public playEffect() {
this.toggleEventMap.get(this.toggleSwitchType)()
}
switchByActive() {
this.onNodeList.forEach((node) => {
node.active = this._isChecked
})
this.offNodeList.forEach((node) => {
node.active = !this._isChecked
})
}
switchByAnimation() { }
/**
* @en
* Set isChecked without invoking checkEvents.
*
* @zh
* 设置 isChecked 而不调用 checkEvents 回调。
*
* @param value - 是否被按下
*/
public setIsCheckedWithoutNotify(value: boolean) {
this._set(value, false)
}
onEnable() {
this.playEffect()
if (!CC_EDITOR || CC_PREVIEW) {
this.node.on(cc.Node.EventType.TOUCH_END, this._internalToggle, this)
}
}
onDisable() {
if (!CC_EDITOR || CC_PREVIEW) {
this.node.off(cc.Node.EventType.TOUCH_END, this._internalToggle, this)
}
}
public OnDestroy() {
const group = this._toggleContainer
if (group) {
group.ensureValidState()
}
}
protected _emitToggleEvents() {
this.node.emit("toggle", this)
if (this.checkEvents) {
cc.Component.EventHandler.emitEvents(this.checkEvents, this)
}
}
}
/**
* @en
* Note: This event is emitted from the node to which the component belongs.
*
* @zh
* 注意:此事件是从该组件所属的 Node 上面派发出来的,需要用 node.on 来监听。
* @event toggle
* @param {Event.EventCustom} event
* @param {Toggle} toggle - The Toggle component.
*/
+9
View File
@@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "c9005f79-10ad-41fb-8a54-3db4fd21e6c6",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}
+39
View File
@@ -0,0 +1,39 @@
import { LocalEmitter } from "./LocalEmitter";
const { ccclass, property } = cc._decorator;
@ccclass
export default class EmitterBase {
_comp_id_: number = LocalEmitter.newCompId();
getCompId() {
return this._comp_id_;
}
//注册监听
on(event: string, fn: Function) {
LocalEmitter.inst.on(this.getCompId(), event, fn);
}
//移除监听
off(event: string = null, fn: Function = null) {
LocalEmitter.inst.off(this.getCompId(), event, fn);
}
// 发送事件
emit(event: string = null, obj: any = null) {
LocalEmitter.inst.emit(event, obj);
}
removeAllListeners() {
LocalEmitter.inst.off(this.getCompId());
}
initListener(config:{[key:string]:number}){
for(let key in config){
this.on(config[key].toString(), this[key].bind(this));
}
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "88513ced-6c4a-41d1-a9b2-30b61f99e0a9",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}
+123
View File
@@ -0,0 +1,123 @@
/**
* class Emitter.
*
*/
export class LocalEmitter {
public static _instance: LocalEmitter = null;
public static get inst() {
if (LocalEmitter._instance == null) {
LocalEmitter._instance = new LocalEmitter();
}
return LocalEmitter._instance;
}
private static _g_comp_id: number = 1;
public static newCompId() {
return LocalEmitter._g_comp_id++;
}
/**
* callbacks for event.
*/
_callbacks = {};
_onceCallbacks = {};
/**
* Listen on the given `event` with `fn`.
*/
on(tag: number, event: string, fn: Function) {
let callbacks = this._callbacks[event];
if (null == callbacks) {
callbacks = this._callbacks[event] = {};
}
let calls = callbacks[tag];
if (null == calls) {
calls = callbacks[tag] = [];
}
calls.push(fn);
return this;
};
once(event: string, fn: Function) {
if(event == null){
return;
}
if(this._onceCallbacks[event] == null){
this._onceCallbacks[event] = [];
}
this._onceCallbacks[event].push(fn);
}
/**
* Remove the given callback for `event` or all
* registered callbacks.
*/
off(tag: number = null, event: string = null, fn: Function = null) {
// all
if (null == tag) {
this._callbacks = {};
return this;
}
if (null == event) {
for (let event in this._callbacks) {
delete this._callbacks[event][tag];
}
return this;
}
if (null == fn) {
if (null != this._callbacks[event]) {
delete this._callbacks[event][tag];
}
return this;
}
// specific event
let callbacks = this._callbacks[event];
if (!callbacks) return this;
let calls = callbacks[tag];
if (!calls) return this;
// remove specific handler
let i = calls.indexOf(fn);
if (~i) calls.splice(i, 1);
return this;
};
/**
* Emit `event` with the given args.
*
*/
emit(event: string, obj: any = null, obj2: any = null) {
let callbacks = this._callbacks[event];
let onceCallback = this._onceCallbacks[event];
if (null != callbacks) {
for (let id in callbacks) {
let calls = callbacks[id];
for (let i = 0, len = calls.length; i < len; ++i) {
calls[i].call(this, obj, obj2);
}
}
}
if (onceCallback != null) {
onceCallback.filter((callback)=>{
callback(null, obj, obj2);
})
delete this._onceCallbacks[event];
}
return this;
};
}
+9
View File
@@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "1f410cf5-01b4-48a2-af1c-5504f2293207",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}
+467
View File
@@ -0,0 +1,467 @@
const oneMinuteSeconds = 60
const onehourSeconds = oneMinuteSeconds * 60
const oneDaySeconds = onehourSeconds * 24
let forbiddenWords: string[] = undefined
export class Utils {
//是否空值
public static isNull(o: any): boolean {
let type = Object.prototype.toString.call(o);
return ("[object Null]" === type || "[object Undefined]" === type);
}
//是否字符串
public static isString(o: any): boolean {
return ("[object String]" === Object.prototype.toString.call(o));
}
//是否数字
public static isNumber(o: any): boolean {
return ("[object Number]" === Object.prototype.toString.call(o));
}
//是否数组
public static isArray(o: any): boolean {
return ("[object Array]" === Object.prototype.toString.call(o));
}
//是否字典
public static isObject(o: any): boolean {
return ("[object Object]" === Object.prototype.toString.call(o));
}
//是否方法
public static isFunction(o: any): boolean {
return ("[object Function]" === Object.prototype.toString.call(o));
}
//继承
public static inherit(base: Function, obj: Function) {
for (let key in base.prototype) {
obj.prototype[key] = base.prototype[key];
}
return obj;
}
//继承
public static queryUrl(url: string) {
let querys = {};
let index = url.indexOf("?")
cc.log(index)
if (index >= 0) {
let strs = url.substr(index + 1).split("&")
for (let i = 0, len = strs.length; i < len; i++) {
if (strs[i].indexOf("=") > 0) {
let params = strs[i].split("=");
if (params[0].trim() != "") {
querys[params[0]] = params[1];
}
}
}
}
return querys;
}
// 将base64字符串转换成图片
public static getSpritFrameFromBase64(base64: string): cc.SpriteFrame {
base64 = "data:image/jpeg;base64," + base64;
let img = new Image();
img.src = base64;
let texture = new cc.Texture2D();
texture.initWithElement(img);
texture.handleLoadedTexture();
return new cc.SpriteFrame(texture);
}
//生成uuid
public static uuid(length: number) {
let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
let uuid = [], i = 0;
let radix = chars.length;
if (length > 0) {
// Compact form
for (i = 0; i < length; i++) uuid[i] = chars[0 | Math.random() * radix];
} else {
// rfc4122, version 4 form
let r: number = 0;
// rfc4122 requires these characters
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';
// Fill in random data. At i==19 set the high bits of clock sequence as
// per rfc4122, sec. 4.1.5
for (i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random() * 16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
}
}
}
return uuid.join('');
}
//复制文本
public static onCopyText(copyText: string): boolean {
if (cc.sys.isBrowser) {
let input = document.createElement("input");
input.setAttribute("readonly", "readonly");
input.setAttribute("value", copyText);
input.style.position = "absolute";
input.style.left = "-9999px";
input.style.fontSize = "12pt"; // Prevent zooming on iOS
document.body.appendChild(input);
input.select();
input.setSelectionRange(0, 128);
let success = false;
try {
if (document.execCommand("Copy")) {
success = true;
}
} catch (e) {
console.log(e)
}
document.body.removeChild(input);
return success;
} else {
// if (Common.OpenFunction.COPYTEXT) {
// if (cc.sys.os == cc.sys.OS_ANDROID) {
// jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "JavaCopy", "(Ljava/lang/String;)V", copyText);
// return true
// }
// else if (cc.sys.os == cc.sys.OS_IOS) {
// let IOS_API = "AppController";
// jsb.reflection.callStaticMethod(IOS_API, "JavaCopy:", copyText);
// return true
// }
// }
}
return false
}
//复制文本
public static getCopyText(): string {
let copyText = ""
// if (Common.OpenFunction.COPYTEXT) {
// if (cc.sys.os == cc.sys.OS_ANDROID) {
// copyText = jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "getDuplicateContent", "()Ljava/lang/String;");
// }
// else if (cc.sys.os == cc.sys.OS_IOS) {
// let IOS_API = "AppController";
// copyText = jsb.reflection.callStaticMethod(IOS_API, "getDuplicateContent:", "");
// }
// }
return copyText
}
/**
* 尋找當前scrollView滑動百分比
* @param scrollView
*/
public static judgeScrollPercent(scrollView: cc.ScrollView) {
const offset = scrollView.getScrollOffset()
const maxOffset = scrollView.getMaxScrollOffset()
const offsetArray = [offset.x, offset.y]
const maxOffsetArray = [maxOffset.x, maxOffset.y, maxOffset.y]
const index = maxOffsetArray.indexOf(Math.max(...maxOffsetArray))
offsetArray[index] = Math.abs(offsetArray[index])
offsetArray[index] = offsetArray[index] < 0 ? 0 : offsetArray[index]
offsetArray[index] = offsetArray[index] > maxOffsetArray[index] ? maxOffsetArray[index] : offsetArray[index]
return offsetArray[index] / maxOffsetArray[index]
}
/**
* 轉換錢幣
*/
public static moneyUnitConvert(money: number) {
if (money < 1000) {
return money + ''
} else {
return money / 1000 + 'K'
}
}
/**
* 三位一撇
*/
public static numberWithCommas(number: number) {
let parts = number.toFixed(2).split('.')
let decimal = parts[1].slice();
for (let i = parts[1].length - 1; i >= 0; i--) {
if (parts[1][i] != '0') {
break;
}
else {
decimal = decimal.substr(0, i);
}
}
parts[1] = decimal;
return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',') + (parts[1] ? '.' + parts[1] : '')
}
/**
* 無條件捨去
*/
public static roundDown(number: number) {
return Number(String(number).split(".")[0])
}
public static deepClone(data: any) {
if (data === undefined || data === null) {
return data
}
return JSON.parse(JSON.stringify(data || {}))
}
/**
* 閃爍動畫
* @param node 閃爍節點
* @param duration 間隔
* @param repeat 重複次數(-1為無限)
* @param callBack 回調函式
*/
public static blink(node: cc.Node, duration: number, repeat = 0, endShow: boolean = true, callBack?: Function) {
// cc.log(`blick duration:${duration} repeat:${repeat}`);
node.active = true
cc.Tween.stopAllByTarget(node)
node.opacity = 0;
const show = endShow ? 255 : 0;
let action = cc.tween()
.to(duration, { opacity: 0 }, { easing: 'quadIn' })
.to(duration, { opacity: 255 }, { easing: 'quadOut' })
cc.tween(node).repeat(repeat, action).call(() => { node.opacity = show; callBack && callBack() }).start();
}
public static currencyFilter(value: number) {
if (value < 1000) {
return `${value}`
}
value = value - (value % 100)
return `${value / 1000}K`
}
public static getCanvasInParent(node: cc.Node): cc.Canvas {
if (!node) {
return undefined
}
let canvas = undefined
let parent = node.parent
while (!canvas) {
if (!parent) {
break
}
canvas = parent.getComponent(cc.Canvas)
parent = parent.parent
}
return canvas
}
public static clamp(val: number, min: number, max: number): number {
return val < min ? min : (val > max ? max : val)
}
public static copyString(str: string) {
const el = document.createElement('textarea')
el.value = str
el.setAttribute('readonly', '')
// el.style.contain = 'strict';
el.style.position = 'absolute'
el.style.left = '-9999px'
el.style.fontSize = '12pt' // Prevent zooming on iOS
const selection = getSelection()
let originalRange = null
if (selection.rangeCount > 0) {
originalRange = selection.getRangeAt(0)
}
document.body.appendChild(el)
el.select()
el.selectionStart = 0
el.selectionEnd = str.length
let success = false
try {
success = document.execCommand('copy')
} catch (err) { }
document.body.removeChild(el)
if (originalRange) {
selection.removeAllRanges()
selection.addRange(originalRange)
}
if (success) {
console.log('复制成功')
} else {
console.log('复制失败')
}
return success
}
public static setButtonInteractable(button: cc.Button, value: boolean) {
if (!button) {
return
}
button.interactable = value
}
public static changeNodeParent(node, parent) {
if (!node) {
cc.error("changeNodeParent node is null");
return;
}
if (!parent) {
cc.error("changeNodeParent parent is null");
return;
}
let pos = node.parent.convertToWorldSpaceAR(node.getPosition());
let changePos = parent.convertToNodeSpaceAR(pos);
node.parent = parent;
node.setPosition(changePos);
}
public static tweenNumberLabel(label: cc.Label, num: number, suffix: string = '') {
const currentNum = Number(label.string.replace(/,/g, '').replace(suffix, ''))
if (!Utils.isNumber(currentNum)) {
console.warn('label is not number:', label.string)
return
}
if (currentNum >= num) {
label.string = Utils.numberWithCommas(num) + suffix
return
}
const plusNum = num - currentNum
const betweenTime = 0.01
const count = 80
let currentCount = 0
label.unscheduleAllCallbacks()
label.schedule(
() => {
if (!label) {
return
}
currentCount += 1
label.string = Utils.numberWithCommas(Math.round(currentNum + (plusNum / count) * currentCount)) + suffix
if (currentCount === count) {
label.string = Utils.numberWithCommas(num) + suffix
}
},
betweenTime,
count - 1
)
}
public static tweenSpriteFillrange(sprite: cc.Sprite, percent: number) {
// cc.log("tweenSpriteFillrange ", percent)
let changeTotal = percent - sprite.fillRange;
const count = 80;
const betweenTime = 0.01
let per = changeTotal / count;
let curRange = sprite.fillRange;
sprite.unscheduleAllCallbacks();
sprite.schedule(() => {
curRange += per;
sprite.fillRange = curRange;
}, betweenTime, count - 1);
}
// 計算字符長度 (英文數字當成1 其他當成2)
public static countMultiLangStrLength(str: string): number {
const originalSize = str.length
const digitNLetter = str.replace(/[^a-zA-Z0-9]/g, '')
const englishSize = digitNLetter.length
const otherLength = (originalSize - digitNLetter.length) * 2
return englishSize + otherLength
}
public static formatNickname(str: string, maxLen = 6) {
let len = Utils.countMultiLangStrLength(str);
let subLen = len;
while (subLen > maxLen) {
str = str.substr(0, str.length - 1);
subLen = Utils.countMultiLangStrLength(str);
}
return len > 6 ? (str + "...") : str;
}
/**
* 數字換行(奇數上排數字大於下排, 偶數對半)
* @param numStr 欲轉換數字
* @param limitNum 幾位後要換行
*/
public static convertChipStr(numStr: string, limitNum: number = 3) {
const len = numStr.length
if (len > limitNum) {
const sliceLen = Math.ceil(len * 0.5)
return `${numStr.slice(0, sliceLen)}\n${numStr.slice(sliceLen)}`
} else {
return numStr
}
}
/** 發送訊息提示 */
public static showSendLog(eventName: string, message?: any) {
if (CC_DEBUG) {
message = message || {};
const time = this.convertTimestamp(new Date().getTime());
let data = JSON.parse(JSON.stringify(message)); // Deep Copy
console.log("%s %c %s", time, "background: Green; color: White;", "發送 " + eventName + " ", data);
}
}
/** 回傳訊息提示 */
public static showResponseLog(eventName: string, message?: any) {
if (CC_DEBUG) {
message = message || {};
const time = this.convertTimestamp(new Date().getTime());
let data = JSON.parse(JSON.stringify(message)); // Deep Copy
console.log("%s %c %s", time, "background: Green; color: White;", "回應 " + eventName + " ", data);
}
}
/** 廣播訊息提示 */
public static showPushLog(eventName: string, message: any) {
if (CC_DEBUG) {
message = message || {};
const time = this.convertTimestamp(new Date().getTime());
let data = JSON.parse(JSON.stringify(message)); // Deep Copy
console.log("%s %c %s", time, "background: Blue; color: White;", "廣播 " + eventName + " ", data);
}
}
private static convertTimestamp(value: number): string {
const t = new Date(value);
// const yyyy = t.getFullYear();
// const MM = t.getMonth() < 9 ? "0" + (t.getMonth()+1):t.getMonth()+1;
// const DD = t.getDate() < 10 ? "0" + t.getDate() : t.getDate();
const hh = t.getHours() < 10 ? "0" + t.getHours() : t.getHours();
const mm = t.getMinutes() < 10 ? "0" + t.getMinutes() : t.getMinutes()
const ss = t.getSeconds() < 10 ? "0" + t.getSeconds() : t.getSeconds()
return `${hh}:${mm}:${ss}`;
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "85b3afaa-64ef-46e6-9e0d-54055039a8a6",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}