...
@ -61,7 +61,11 @@ export class BezierCurveAnimation extends Component {
|
|||||||
tweenSwitchEvent = new cc.EventHandler();
|
tweenSwitchEvent = new cc.EventHandler();
|
||||||
|
|
||||||
/** 更新事件 */
|
/** 更新事件 */
|
||||||
@property({ displayName: '更新事件', tooltip: '(曲线Y_yN)', type: cc.EventHandler })
|
@property({
|
||||||
|
displayName: '更新事件',
|
||||||
|
tooltip: '(总曲线Y_yN, 当前缓动下标_indexN, 当前缓动曲线Y_yN)',
|
||||||
|
type: cc.EventHandler
|
||||||
|
})
|
||||||
updateEvent = new cc.EventHandler();
|
updateEvent = new cc.EventHandler();
|
||||||
|
|
||||||
/** 结束事件 */
|
/** 结束事件 */
|
||||||
@ -69,25 +73,36 @@ export class BezierCurveAnimation extends Component {
|
|||||||
endEvent = new cc.EventHandler();
|
endEvent = new cc.EventHandler();
|
||||||
/* --------------- private --------------- */
|
/* --------------- private --------------- */
|
||||||
/* ------------------------------- segmentation ------------------------------- */
|
/* ------------------------------- segmentation ------------------------------- */
|
||||||
/** 开始缓动 */
|
/**
|
||||||
startTween(): cc.Tween<any> {
|
* 开始缓动
|
||||||
|
* @param startIndexN_ 缓动开始下标
|
||||||
|
* @param endIndexN_ 缓动结束下标
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
startTween(startIndexN_?: number, endIndexN_ = (startIndexN_ ?? 0) + 1): cc.Tween<any> {
|
||||||
|
let tweenUnitAs = this.tweenUnitAs;
|
||||||
|
if (startIndexN_ !== undefined) {
|
||||||
|
tweenUnitAs = tweenUnitAs.slice(startIndexN_, endIndexN_);
|
||||||
|
}
|
||||||
/** 总时间(秒) */
|
/** 总时间(秒) */
|
||||||
let totalTimeSN = this.tweenUnitAs.reduce((preValue, currValue) => preValue + currValue.timeSN, 0);
|
let totalTimeSN = tweenUnitAs.reduce((preValue, currValue) => preValue + currValue.timeSN, 0);
|
||||||
/** 时间占比 */
|
/** 时间占比 */
|
||||||
let timeRatioNs: number[] = [];
|
let timeRatioNs: number[] = [];
|
||||||
{
|
{
|
||||||
let currN = 0;
|
let currN = 0;
|
||||||
this.tweenUnitAs.forEach((v, kN) => {
|
tweenUnitAs.forEach((v, kN) => {
|
||||||
let ratioN = v.timeSN / totalTimeSN;
|
let ratioN = v.timeSN / totalTimeSN;
|
||||||
currN += ratioN;
|
currN += ratioN;
|
||||||
timeRatioNs.push(currN);
|
timeRatioNs.push(currN);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/** 曲线函数 */
|
/** 曲线函数 */
|
||||||
let curveFS = this.tweenUnitAs.map((v) => {
|
let curveFS = tweenUnitAs.map((v) => {
|
||||||
if (v.customCurveB) {
|
if (v.customCurveB) {
|
||||||
let curve = new BezierCurve(v.controlPointV3S);
|
let curve = new BezierCurve(v.controlPointV3S);
|
||||||
return curve.point.bind(curve) as (kN: number) => number;
|
return (kN: number) => {
|
||||||
|
return curve.point(kN).y;
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return cc.easing[easingEnum[v.easing]].bind(cc.easing) as (kN: number) => number;
|
return cc.easing[easingEnum[v.easing]].bind(cc.easing) as (kN: number) => number;
|
||||||
}
|
}
|
||||||
@ -118,13 +133,17 @@ export class BezierCurveAnimation extends Component {
|
|||||||
/** 曲线位置 */
|
/** 曲线位置 */
|
||||||
let posN = (ratioN - lastTimeRatioN) / timeRangeN;
|
let posN = (ratioN - lastTimeRatioN) / timeRangeN;
|
||||||
/** 曲线位置 */
|
/** 曲线位置 */
|
||||||
let yN = curveFS[tweenIndexN](posN) * timeRangeN + lastTimeRatioN;
|
let yN = curveFS[tweenIndexN](posN);
|
||||||
|
let y2N = yN * timeRangeN + lastTimeRatioN;
|
||||||
// 缓动切换事件触发
|
// 缓动切换事件触发
|
||||||
if (lastTweenIndexN !== tweenIndexN) {
|
if (lastTweenIndexN !== tweenIndexN) {
|
||||||
this.tweenSwitchEvent?.emit([lastTweenIndexN]);
|
this.tweenSwitchEvent?.emit([lastTweenIndexN]);
|
||||||
}
|
}
|
||||||
|
if (y2N === undefined) {
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
// 更新事件触发
|
// 更新事件触发
|
||||||
this.updateEvent?.emit([yN]);
|
this.updateEvent?.emit([y2N, tweenIndexN, yN]);
|
||||||
// 更新缓动下标
|
// 更新缓动下标
|
||||||
lastTweenIndexN = tweenIndexN;
|
lastTweenIndexN = tweenIndexN;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { _decorator, Component, Node } from 'cc';
|
import { _decorator, Component, Node } from 'cc';
|
||||||
import * as cc from 'cc';
|
import * as cc from 'cc';
|
||||||
import { BezierCurveAnimation } from './BezierCurveAnimation';
|
import { BezierCurveAnimation } from './BezierCurveAnimation';
|
||||||
const { ccclass, property, requireComponent } = _decorator;
|
import { EDITOR } from 'cc/env';
|
||||||
|
const { ccclass, property, requireComponent, executeInEditMode } = _decorator;
|
||||||
|
|
||||||
/** 旋转抽奖方向 */
|
/** 旋转抽奖方向 */
|
||||||
export enum RollingLotteryDirection {
|
export enum RollingLotteryDirection {
|
||||||
@ -30,19 +31,27 @@ export class RollingLottery extends Component {
|
|||||||
/** transform 组件 */
|
/** transform 组件 */
|
||||||
private _uiTransform: cc.UITransform;
|
private _uiTransform: cc.UITransform;
|
||||||
/** 周长 */
|
/** 周长 */
|
||||||
private _perimeterN: number;
|
private _perimeterV3 = cc.v3();
|
||||||
/** 当前距离 */
|
|
||||||
private _currDistN = 0;
|
|
||||||
/** 总距离 */
|
/** 总距离 */
|
||||||
private _totalDistN: number;
|
private _totalDistV3: cc.Vec3;
|
||||||
/** 当前下标 */
|
/** 当前下标 */
|
||||||
private _currIndexN: number;
|
private _currIndexN = 0;
|
||||||
/** 子节点大小 */
|
/** 子节点大小 */
|
||||||
private _ItemSize: cc.Size;
|
private _ItemSize: cc.Size;
|
||||||
/** 运动状态 */
|
/** 滚动状态 */
|
||||||
private _scrollB = false;
|
private _scrollB = false;
|
||||||
|
/** 循环状态 */
|
||||||
|
private _loopScrollB = false;
|
||||||
|
/** 循环缓动 */
|
||||||
|
private _loopTween: cc.Tween<any>;
|
||||||
/** 自己矩形 */
|
/** 自己矩形 */
|
||||||
private _selfRect = cc.rect();
|
private _selfRect = cc.rect();
|
||||||
|
/** 上次曲线 Y */
|
||||||
|
private _lastCurveYN = 0;
|
||||||
|
/** 当前目标 */
|
||||||
|
private _currTargetN: number;
|
||||||
|
/** 当前缓动下标 */
|
||||||
|
private _currTweenN = 0;
|
||||||
/* --------------- 临时变量 --------------- */
|
/* --------------- 临时变量 --------------- */
|
||||||
private _tempM4 = cc.mat4();
|
private _tempM4 = cc.mat4();
|
||||||
private _temp2M4 = cc.mat4();
|
private _temp2M4 = cc.mat4();
|
||||||
@ -53,92 +62,175 @@ export class RollingLottery extends Component {
|
|||||||
this._initEvent();
|
this._initEvent();
|
||||||
}
|
}
|
||||||
/* ------------------------------- 功能 ------------------------------- */
|
/* ------------------------------- 功能 ------------------------------- */
|
||||||
/**
|
|
||||||
* 获取格子移动后距离
|
|
||||||
* @param currIndexN_ 当前格子下标
|
|
||||||
* @param targetIndexN_ 目标格子下标
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
private _getItemMovePos(currIndexN_: number, targetIndexN_: number): void {
|
|
||||||
/** 当前节点 */
|
|
||||||
let currNode = this.node.getChildByName(currIndexN_ + '');
|
|
||||||
/** 节点矩形 */
|
|
||||||
let currRect = this._getBoundingBoxToWorld(currNode);
|
|
||||||
/** 移动距离 */
|
|
||||||
let moveDistV3 = cc.v3(this._ItemSize.x, this._ItemSize.y).multiplyScalar(targetIndexN_ - currIndexN_);
|
|
||||||
/** 移动距离 */
|
|
||||||
let moveDistN: number;
|
|
||||||
if (this.dire === RollingLotteryDirection.HORIZONTAL) {
|
|
||||||
moveDistV3.y = 0;
|
|
||||||
moveDistN = moveDistV3.x;
|
|
||||||
} else {
|
|
||||||
moveDistV3.x = 0;
|
|
||||||
moveDistN = moveDistV3.y;
|
|
||||||
}
|
|
||||||
currRect.x += moveDistV3.x;
|
|
||||||
currRect.y += moveDistV3.y;
|
|
||||||
|
|
||||||
/** 终点坐标 */
|
|
||||||
let endPosV3 = this.node
|
|
||||||
.getChildByName(currIndexN_ + '')
|
|
||||||
.worldPosition.clone()
|
|
||||||
.add(moveDistV3);
|
|
||||||
/** 圈数 */
|
|
||||||
let circleN = Math.floor(moveDistN / this._perimeterN);
|
|
||||||
// /** 额外移动距离 */
|
|
||||||
// let extraMoveDistN = moveDistN - circleN * this._perimeterN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取在世界坐标系下的节点包围盒(不包含自身激活的子节点范围) */
|
/** 获取在世界坐标系下的节点包围盒(不包含自身激活的子节点范围) */
|
||||||
private _getBoundingBoxToWorld(node_: cc.Node): cc.Rect {
|
private _getBoundingBoxToWorld(node_: cc.Node): cc.Rect {
|
||||||
node_.getWorldMatrix(this._temp2M4);
|
let uiTransform = node_.getComponent(cc.UITransform);
|
||||||
cc.Mat4.fromRTS(this._tempM4, this.node.getRotation(), this.node.getPosition(), this.node.getScale());
|
cc.Mat4.fromRTS(this._tempM4, node_.getRotation(), node_.getPosition(), node_.getScale());
|
||||||
let width = this._uiTransform.contentSize.width;
|
const width = uiTransform.contentSize.width;
|
||||||
let height = this._uiTransform.contentSize.height;
|
const height = uiTransform.contentSize.height;
|
||||||
let rect = new cc.Rect(
|
const rect = cc.rect(-uiTransform.anchorPoint.x * width, -uiTransform.anchorPoint.y * height, width, height);
|
||||||
-this._uiTransform.anchorPoint.x * width,
|
|
||||||
-this._uiTransform.anchorPoint.y * height,
|
node_.parent.getWorldMatrix(this._temp2M4);
|
||||||
width,
|
|
||||||
height
|
|
||||||
);
|
|
||||||
cc.Mat4.multiply(this._temp2M4, this._temp2M4, this._tempM4);
|
cc.Mat4.multiply(this._temp2M4, this._temp2M4, this._tempM4);
|
||||||
rect.transformMat4(this._temp2M4);
|
rect.transformMat4(this._temp2M4);
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 检测参数节点是否与当前节点碰撞 */
|
/**
|
||||||
private _checkCollision(node_: cc.Node): boolean {
|
* 滚动子节点
|
||||||
let rect = this._getBoundingBoxToWorld(this.node);
|
* @param distV3_ 距离
|
||||||
let rect2 = this._getBoundingBoxToWorld(node_);
|
*/
|
||||||
// 增加保险范围
|
private _scrollChild(distV3_: cc.Vec3): void {
|
||||||
rect.width += rect.width * 0.5;
|
/** 当前节点矩形 */
|
||||||
rect.height += rect.height * 0.5;
|
let currNodeRect: cc.Rect;
|
||||||
rect.x -= rect.width * 0.25;
|
/** 更新节点坐标 */
|
||||||
rect.y -= rect.height * 0.25;
|
let updatePosB = false;
|
||||||
return rect.intersects(rect2);
|
/** 当前节点 UITransform */
|
||||||
|
let currTransform: cc.UITransform;
|
||||||
|
/** 头节点 */
|
||||||
|
let headNode = this.node.children[0];
|
||||||
|
/** 尾节点 */
|
||||||
|
let tailNode = this.node.children[this.node.children.length - 1];
|
||||||
|
/** 头节点矩形 */
|
||||||
|
let headNodeRect: cc.Rect;
|
||||||
|
/** 尾节点矩形 */
|
||||||
|
let tailNodeRect: cc.Rect;
|
||||||
|
|
||||||
|
// 左右滚动
|
||||||
|
if (this.dire === RollingLotteryDirection.HORIZONTAL) {
|
||||||
|
}
|
||||||
|
// 上下滚动
|
||||||
|
else {
|
||||||
|
// 从上往下滚动
|
||||||
|
if (distV3_.y < 0) {
|
||||||
|
this.node.children.forEach((v, kN) => {
|
||||||
|
currTransform = v.getComponent(cc.UITransform);
|
||||||
|
updatePosB = false;
|
||||||
|
currNodeRect = this._getBoundingBoxToWorld(v);
|
||||||
|
|
||||||
|
// 移动坐标
|
||||||
|
currNodeRect.y += distV3_.y;
|
||||||
|
|
||||||
|
// 相交则更新节点坐标
|
||||||
|
if (currNodeRect.intersects(this._selfRect)) {
|
||||||
|
updatePosB = true;
|
||||||
|
}
|
||||||
|
// 若不相交则超出范围
|
||||||
|
else {
|
||||||
|
// 若节点在上方则跳过更新
|
||||||
|
if (currNodeRect.yMin > this._selfRect.yMax) {
|
||||||
|
updatePosB = true;
|
||||||
|
} else {
|
||||||
|
// setTimeout 防止获取节点坐标错误、防止 setSiblingIndex 后遍历错误
|
||||||
|
setTimeout(() => {
|
||||||
|
// 切换位置到头节点上方
|
||||||
|
headNodeRect = this._getBoundingBoxToWorld(headNode);
|
||||||
|
v.worldPosition = cc.v3(
|
||||||
|
v.worldPosition.x,
|
||||||
|
headNodeRect.yMax + currNodeRect.height * currTransform.anchorY
|
||||||
|
);
|
||||||
|
|
||||||
|
// 更新 item
|
||||||
|
let indexN = Number(headNode.name) - 1;
|
||||||
|
v.name = indexN + '';
|
||||||
|
this.itemUpdateEvent.emit([v, indexN]);
|
||||||
|
|
||||||
|
// 更新 item 下标
|
||||||
|
headNode = v;
|
||||||
|
v.setSiblingIndex(0);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新节点坐标
|
||||||
|
if (updatePosB) {
|
||||||
|
v.worldPosition = cc.v3(
|
||||||
|
v.worldPosition.x,
|
||||||
|
currNodeRect.y + currNodeRect.height * currTransform.anchorY
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 从下往上滚动
|
||||||
|
else {
|
||||||
|
this.node.children.forEach((v, kN) => {
|
||||||
|
currTransform = v.getComponent(cc.UITransform);
|
||||||
|
updatePosB = false;
|
||||||
|
currNodeRect = this._getBoundingBoxToWorld(v);
|
||||||
|
|
||||||
|
// 移动坐标
|
||||||
|
currNodeRect.y += distV3_.y;
|
||||||
|
|
||||||
|
// 相交则更新节点坐标
|
||||||
|
if (currNodeRect.intersects(this._selfRect)) {
|
||||||
|
updatePosB = true;
|
||||||
|
}
|
||||||
|
// 若不相交则超出范围
|
||||||
|
else {
|
||||||
|
// 若节点在下方则跳过更新
|
||||||
|
if (this._selfRect.yMin > currNodeRect.yMax) {
|
||||||
|
updatePosB = true;
|
||||||
|
} else {
|
||||||
|
// setTimeout 防止获取节点坐标错误、防止 setSiblingIndex 后遍历错误
|
||||||
|
setTimeout(() => {
|
||||||
|
// 切换位置到尾节点下方
|
||||||
|
tailNodeRect = this._getBoundingBoxToWorld(tailNode);
|
||||||
|
v.worldPosition = cc.v3(
|
||||||
|
v.worldPosition.x,
|
||||||
|
tailNodeRect.yMin - currNodeRect.height * (1 - currTransform.anchorY)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 更新 item
|
||||||
|
let indexN = Number(tailNode.name) + 1;
|
||||||
|
v.name = indexN + '';
|
||||||
|
this.itemUpdateEvent.emit([v, indexN]);
|
||||||
|
|
||||||
|
// 更新 item 下标
|
||||||
|
tailNode = v;
|
||||||
|
v.setSiblingIndex(this.node.children.length - 1);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新节点坐标
|
||||||
|
if (updatePosB) {
|
||||||
|
v.worldPosition = cc.v3(
|
||||||
|
v.worldPosition.x,
|
||||||
|
currNodeRect.y + currNodeRect.height * currTransform.anchorY
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 更新运动距离 */
|
/** 更新运动距离 */
|
||||||
private _updateMoveDist(indexN_: number): void {
|
private _updateMoveDist(indexN_: number): void {
|
||||||
|
/** 当前节点 */
|
||||||
|
let currNode = this.node.getChildByName(this._currIndexN + '');
|
||||||
/** 间隔格子 */
|
/** 间隔格子 */
|
||||||
let intervalN = indexN_ - this._currIndexN;
|
let intervalN = indexN_ - this._currIndexN;
|
||||||
/** 格子距离 */
|
/** 格子距离 */
|
||||||
let boxDistN = this.dire === RollingLotteryDirection.HORIZONTAL ? this._ItemSize.width : this._ItemSize.height;
|
let boxDistN = this.dire === RollingLotteryDirection.HORIZONTAL ? this._ItemSize.width : this._ItemSize.height;
|
||||||
/** 超出当前格子距离 */
|
/** 当前格子距父节点(0, 0)的偏移坐标 */
|
||||||
let overDistN = this._currDistN - boxDistN * this._currIndexN;
|
let offsetDistV3 = this.node.worldPosition.clone().subtract(currNode.worldPosition);
|
||||||
// 设置总距离
|
// 设置总距离
|
||||||
this._totalDistN = intervalN * boxDistN - overDistN;
|
if (this.dire === RollingLotteryDirection.HORIZONTAL) {
|
||||||
|
this._totalDistV3 = cc.v3(intervalN * boxDistN + offsetDistV3.x);
|
||||||
|
} else {
|
||||||
|
this._totalDistV3 = cc.v3(0, intervalN * boxDistN + offsetDistV3.y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 更新数据 */
|
/** 更新数据 */
|
||||||
private _updateData(): void {
|
private _updateData(): void {
|
||||||
// 单圈长度
|
// 单圈长度
|
||||||
this._perimeterN = 0;
|
this._perimeterV3.set(cc.Vec3.ZERO);
|
||||||
|
let size: cc.Size;
|
||||||
this.node.children.forEach((v1) => {
|
this.node.children.forEach((v1) => {
|
||||||
this._perimeterN += v1.getComponent(cc.UITransform).height;
|
size = v1.getComponent(cc.UITransform).contentSize;
|
||||||
|
this._perimeterV3.add3f(size.x, size.y, 0);
|
||||||
});
|
});
|
||||||
// 重置距离
|
|
||||||
this._currDistN = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 初始化数据 */
|
/** 初始化数据 */
|
||||||
@ -147,29 +239,31 @@ export class RollingLottery extends Component {
|
|||||||
this._uiTransform = this.node.getComponent(cc.UITransform);
|
this._uiTransform = this.node.getComponent(cc.UITransform);
|
||||||
this._ItemSize = this.node.children[0].getComponent(cc.UITransform).contentSize.clone();
|
this._ItemSize = this.node.children[0].getComponent(cc.UITransform).contentSize.clone();
|
||||||
|
|
||||||
|
// 自己矩形
|
||||||
|
this._selfRect = this._getBoundingBoxToWorld(this.node);
|
||||||
|
|
||||||
// 设置更新事件
|
// 设置更新事件
|
||||||
this._curveComp.updateEvent.component = cc.js.getClassName(this);
|
this._curveComp.updateEvent.component = cc.js.getClassName(this);
|
||||||
this._curveComp.updateEvent.handler = 'updateEvent';
|
this._curveComp.updateEvent.handler = 'updateEvent';
|
||||||
|
this._curveComp.updateEvent.target = this.node;
|
||||||
|
|
||||||
// 设置结束事件
|
// 设置结束事件
|
||||||
this._curveComp.endEvent.component = cc.js.getClassName(this);
|
this._curveComp.endEvent.component = cc.js.getClassName(this);
|
||||||
this._curveComp.endEvent.handler = 'updateEvent';
|
this._curveComp.endEvent.handler = 'endEvent';
|
||||||
|
this._curveComp.endEvent.target = this.node;
|
||||||
// 更新当前距离
|
|
||||||
{
|
|
||||||
let distV3 = this.node.worldPosition.clone().subtract(this.node.children[0].worldPosition);
|
|
||||||
this._currDistN = this.dire === RollingLotteryDirection.HORIZONTAL ? distV3.x : distV3.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自己矩形
|
|
||||||
this._selfRect = this._getBoundingBoxToWorld(this.node);
|
|
||||||
|
|
||||||
this._updateData();
|
this._updateData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 初始化视图 */
|
/** 初始化视图 */
|
||||||
private _initView(): void {
|
private _initView(): void {
|
||||||
this.scroll(0);
|
// 重置子节点
|
||||||
|
this.node.children.forEach((v, kN) => {
|
||||||
|
v.name = kN + this._currIndexN + '';
|
||||||
|
this.itemUpdateEvent.emit([v, kN + this._currIndexN]);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.jump(this._currIndexN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 初始化事件 */
|
/** 初始化事件 */
|
||||||
@ -179,41 +273,105 @@ export class RollingLottery extends Component {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 循环滚动
|
* 循环滚动
|
||||||
* @param speedN_ 速度
|
* @param speedN_ 速度/秒
|
||||||
* @param timeSN_ 时间(秒),不填则一直滚动
|
* @param timeSN_ 时间(秒),不填则一直滚动
|
||||||
*/
|
*/
|
||||||
loop(speedN_: number, timeSN_?: number): void {}
|
loop(speedN_: number, timeSN_?: number): void {
|
||||||
|
if (this._scrollB) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._scrollB = true;
|
||||||
|
this._loopScrollB = true;
|
||||||
|
let distV3 = cc.v3();
|
||||||
|
this._loopTween = cc
|
||||||
|
.tween({ valueN: 0, lastValueN: 0 })
|
||||||
|
.repeatForever(
|
||||||
|
cc.tween().by(
|
||||||
|
1,
|
||||||
|
{
|
||||||
|
valueN: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onUpdate: (target?: any, ratioN?: number) => {
|
||||||
|
if (this.dire === RollingLotteryDirection.HORIZONTAL) {
|
||||||
|
distV3.x = (target.valueN - target.lastValueN) * speedN_;
|
||||||
|
} else {
|
||||||
|
distV3.y = (target.valueN - target.lastValueN) * speedN_;
|
||||||
|
}
|
||||||
|
this._scrollChild(distV3);
|
||||||
|
target.lastValueN = target.valueN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.start();
|
||||||
|
if (timeSN_ !== undefined) {
|
||||||
|
this.scheduleOnce(() => {
|
||||||
|
this._loopTween.stop();
|
||||||
|
this._loopTween = null;
|
||||||
|
this._loopScrollB = false;
|
||||||
|
}, timeSN_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 跳转到指定下标 */
|
||||||
|
jump(indexN_: number): void {
|
||||||
|
if (this._scrollB) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._scrollB = true;
|
||||||
|
|
||||||
|
// 更新移动距离
|
||||||
|
this._updateMoveDist(indexN_);
|
||||||
|
// 开始滚动
|
||||||
|
this._scrollChild(this._totalDistV3);
|
||||||
|
// 更新状态
|
||||||
|
this._currIndexN = indexN_;
|
||||||
|
this._scrollB = false;
|
||||||
|
}
|
||||||
|
|
||||||
/** 滚动到指定下标 */
|
/** 滚动到指定下标 */
|
||||||
scroll(indexN_: number, timeSN_?: number): void {
|
scroll(indexN_: number): void {
|
||||||
this._scrollB = true;
|
if (this._scrollB && !this._loopScrollB) {
|
||||||
this._updateMoveDist(indexN_);
|
return;
|
||||||
|
|
||||||
/** 移动距离 */
|
|
||||||
let moveDistN = this._totalDistN - this._currDistN;
|
|
||||||
|
|
||||||
// 直接跳转
|
|
||||||
if (!timeSN_) {
|
|
||||||
/** 圈数 */
|
|
||||||
let circleN = Math.floor(moveDistN / this._perimeterN);
|
|
||||||
/** 额外移动距离 */
|
|
||||||
let extraMoveDistN = moveDistN - circleN * this._perimeterN;
|
|
||||||
}
|
}
|
||||||
|
this._scrollB = true;
|
||||||
|
|
||||||
|
// 停止循环滚动
|
||||||
|
if (this._loopScrollB) {
|
||||||
|
this._loopTween.stop();
|
||||||
|
this._loopTween = null;
|
||||||
|
this._loopScrollB = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._currTargetN = indexN_;
|
||||||
|
this._lastCurveYN = 0;
|
||||||
|
// 更新移动距离
|
||||||
|
this._updateMoveDist(indexN_);
|
||||||
|
// 开始滚动
|
||||||
|
this._currTweenN = 0;
|
||||||
|
this._curveComp.startTween(this._currTweenN);
|
||||||
}
|
}
|
||||||
/* ------------------------------- 自定义事件 ------------------------------- */
|
/* ------------------------------- 自定义事件 ------------------------------- */
|
||||||
tweenSwitchEvent(indexN_: number): void {
|
updateEvent(yN_: number, indexN_: number, y2N_: number): void {
|
||||||
// cc.log('缓动切换', indexN_);
|
if (this.dire === RollingLotteryDirection.HORIZONTAL) {
|
||||||
|
} else {
|
||||||
|
this._scrollChild(cc.v3(0, (yN_ - this._lastCurveYN) * this._totalDistV3.y));
|
||||||
}
|
}
|
||||||
updateEvent(yN_: number): void {
|
this._lastCurveYN = yN_;
|
||||||
// cc.log('缓动更新', yN_);
|
if (yN_ === undefined) {
|
||||||
|
debugger;
|
||||||
}
|
}
|
||||||
endEvent(): void {
|
// cc.log('缓动更新', yN_, indexN_, y2N_, yN_ - this._lastCurveYN);
|
||||||
// cc.log('缓动结束');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 子节点更新 */
|
endEvent(): void {
|
||||||
childUpdate(node_: cc.Node, indexN_: number): void {
|
this._scrollB = false;
|
||||||
node_.getComponentInChildren(cc.Label).string = indexN_ + '';
|
// 继续缓动
|
||||||
|
this._currTweenN++;
|
||||||
|
if (this._currTweenN < this._curveComp.tweenUnitAs.length) {
|
||||||
|
this._curveComp.startTween(this._currTweenN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* ------------------------------- 节点事件 ------------------------------- */
|
/* ------------------------------- 节点事件 ------------------------------- */
|
||||||
private _nodeSiblingOrderChanged(): void {
|
private _nodeSiblingOrderChanged(): void {
|
||||||
|
2684
assets/main.scene
21
preview-template/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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.
|
61
preview-template/README.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# ccc-devtools v3.0.0
|
||||||
|
Cocos Creator 网页调试工具,运行时查看、修改节点树,实时更新节点属性,可视化缓存资源。
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
- 场景节点树实时显示,节点、组件属性实时显示更改
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 可视化缓存资源
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 标记场景中节点位置
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 输出节点、组件引用到控制台
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- cc控制台功能扩展
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 全局使用
|
||||||
|
|
||||||
|
Cocos Creator 3.0暂不支持全局使用
|
||||||
|
|
||||||
|
## 项目使用
|
||||||
|
|
||||||
|
- `cd PROJECT_PATH && git clone -b v3.0.0 https://github.com/potato47/ccc-devtools.git preview-template`
|
||||||
|
- 或者手动将本项目对应分支下载到项目目录后,将名字改为 `preview-template`
|
||||||
|
|
||||||
|
## 自定义
|
||||||
|
|
||||||
|
- 本项目使用了 vue 和 vuetify,可根据 [vuetify 文档](https://vuetifyjs.com/en/getting-started/quick-start/) 对页面进行修改
|
||||||
|
|
||||||
|
- 节点、组件显示属性可在 `config.js` 里配置,目前支持 text,number,textarea,color,bool 几种类型
|
||||||
|
|
||||||
|
## 需求、更新
|
||||||
|
|
||||||
|
https://github.com/potato47/ccc-devtools
|
||||||
|
|
||||||
|
如果没有更改源码,可直接在目录下 git pull
|
||||||
|
|
||||||
|
论坛讨论地址:https://forum.cocos.com/t/creator-20190201/71578
|
||||||
|
|
||||||
|
## 贡献指南
|
||||||
|
|
||||||
|
- 版本号命名规则 https://semver.org/lang/zh-CN/ ,简单来讲,新功能第二位加一,修复bug第三位加一
|
||||||
|
|
||||||
|
- 如果新增功能请在README中添加预览截图说明
|
||||||
|
|
||||||
|
- 记得更新version.json中的版本号
|
||||||
|
|
||||||
|
## 前人种树
|
||||||
|
|
||||||
|
- https://github.com/vuejs/vue
|
||||||
|
|
||||||
|
- https://github.com/vuetifyjs/vuetify
|
68
preview-template/config.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
const NEX_CONFIG = {
|
||||||
|
nodeSchema: {
|
||||||
|
node: {
|
||||||
|
title: 'Node',
|
||||||
|
key: 'cc.Node',
|
||||||
|
rows: [
|
||||||
|
{ name: 'Name', key: 'name', type: 'text' },
|
||||||
|
{ name: 'Position.X', parentKey: 'position', key: 'x', type: 'object_number', method: 'setPosition' },
|
||||||
|
{ name: 'Position.Y', parentKey: 'position', key: 'y', type: 'object_number', method: 'setPosition' },
|
||||||
|
{ name: 'Position.Z', parentKey: 'position', key: 'z', type: 'object_number', method: 'setPosition' },
|
||||||
|
{ name: 'Angle.X', parentKey: 'eulerAngles', key: 'x', type: 'object_number', method: 'setRotationFromEuler' },
|
||||||
|
{ name: 'Angle.Y', parentKey: 'eulerAngles', key: 'y', type: 'object_number', method: 'setRotationFromEuler' },
|
||||||
|
{ name: 'Angle.Z', parentKey: 'eulerAngles', key: 'z', type: 'object_number', method: 'setRotationFromEuler' },
|
||||||
|
{ name: 'Scale.X', parentKey: 'scale', key: 'x', type: 'object_number', method: 'setScale' },
|
||||||
|
{ name: 'Scale.Y', parentKey: 'scale', key: 'y', type: 'object_number', method: 'setScale' },
|
||||||
|
{ name: 'Scale.Z', parentKey: 'scale', key: 'z', type: 'object_number', method: 'setScale' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
componentsSchema: {
|
||||||
|
'cc.Camera': {
|
||||||
|
title: 'cc.Camera',
|
||||||
|
key: 'cc.Camera',
|
||||||
|
rows: [
|
||||||
|
{ name: 'ClearDepth', key: 'clearDepth', type: 'number' },
|
||||||
|
{ name: 'ClearColor', key: 'hex_clearColor', rawKey: 'clearColor', type: 'color' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'cc.DirectionalLight': {
|
||||||
|
title: 'cc.DirectionalLight',
|
||||||
|
key: 'cc.DirectionalLight',
|
||||||
|
rows: [
|
||||||
|
{ name: 'UseColorTemperature', key: 'useColorTemperature', type: 'bool' },
|
||||||
|
{ name: 'ColorTemperature', key: 'colorTemperature', type: 'number' },
|
||||||
|
{ name: 'Illuminance', key: 'illuminance', type: 'number' },
|
||||||
|
{ name: 'Color', key: 'hex_color', rawKey: 'color', type: 'color' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'cc.UITransform': {
|
||||||
|
key: 'cc.UITransform',
|
||||||
|
title: 'cc.UITransform',
|
||||||
|
rows: [
|
||||||
|
{ name: 'Width', key: 'width', type: 'number' },
|
||||||
|
{ name: 'Height', key: 'height', type: 'number' },
|
||||||
|
{ name: 'AnchorX', key: 'anchorX', type: 'number' },
|
||||||
|
{ name: 'AnchorY', key: 'anchorY', type: 'number' },
|
||||||
|
{ name: 'Priority', key: 'priority', type: 'number' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'cc.Sprite': {
|
||||||
|
key: 'cc.Sprite',
|
||||||
|
title: 'cc.Sprite',
|
||||||
|
rows: [
|
||||||
|
{ name: 'Color', key: 'hex_color', rawKey: 'color', type: 'color' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'cc.Label': {
|
||||||
|
title: 'cc.Label',
|
||||||
|
key: 'cc.Label',
|
||||||
|
rows: [
|
||||||
|
{ name: 'String', key: 'string', type: 'textarea' },
|
||||||
|
{ name: 'Font Size', key: 'fontSize', type: 'number' },
|
||||||
|
{ name: 'Line Height', key: 'lineHeight', type: 'number' },
|
||||||
|
{ name: 'Color', key: 'hex_color', rawKey: 'color', type: 'color' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
257
preview-template/custom.html
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
<link href="./libs/css/materialdesignicons.min.css" rel="stylesheet"
|
||||||
|
type="text/css">
|
||||||
|
<link href="./libs/css/vuetify.min.css" rel="stylesheet" type="text/css">
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<v-app id="app">
|
||||||
|
<v-app-bar app clipped-left color="gray" dense v-if="isShowTop">
|
||||||
|
<v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
|
||||||
|
<div id="recompiling"><span>Recompiling...</span></div>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<%- include(cocosToolBar, {config: config}) %>
|
||||||
|
<div class="toolbar">
|
||||||
|
<!-- <div class="toolbar disabled"> -->
|
||||||
|
<!-- <div class="item">
|
||||||
|
<select id="opts-device" value="<%=config.device%>">
|
||||||
|
<% Object.keys(devices).forEach((key) => {%>
|
||||||
|
<option value="<%=key%>"><%=devices[key].name%>(<%=devices[key].width%> X <%=devices[key].height%>)</option>
|
||||||
|
<% }) %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="item"><button id="btn-rotate" class="<%=config.rotate ? 'checked' : ''%>">Rotate</button></div>
|
||||||
|
<span style="font-size: small;" class="item">Debug Mode:</span>
|
||||||
|
<div class="item">
|
||||||
|
<select id="opts-debug-mode" value="<%=config.debugMode%>">
|
||||||
|
<option value="0">None</option>
|
||||||
|
<option value="1">Info</option>
|
||||||
|
<option value="2">Warn</option>
|
||||||
|
<option value="3">Error</option>
|
||||||
|
<option value="4">Info For Web Page</option>
|
||||||
|
<option value="5">Warn For Web Page</option>
|
||||||
|
<option value="6">Error For Web Page</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="item"><button id="btn-show-fps" class="<%=config.showFps ? 'checked' : ''%>">Show FPS</button></div>
|
||||||
|
<div class="item">
|
||||||
|
<span style="font-size: small;" class="item">FPS:</span><input id="input-set-fps" type="number" value="<%=config.fps%>" />
|
||||||
|
</div>
|
||||||
|
<div style="margin-right: 0;" class="item"><button id="btn-pause">Pause</button><button id="btn-step">Step</button></div>
|
||||||
|
<div class="item"><button id="btn-step" style="display: none;">Step</button></div> -->
|
||||||
|
<v-icon @click="openCocosDocs" small>mdi-cloud-search</v-icon>
|
||||||
|
<v-icon @click="openCocosForum" small>mdi-forum</v-icon>
|
||||||
|
<v-icon @click="openCacheDialog" small>mdi-table</v-icon>
|
||||||
|
<v-icon @click="openGithub" small>mdi-home</v-icon>
|
||||||
|
</div>
|
||||||
|
</v-app-bar>
|
||||||
|
|
||||||
|
<div v-if="!isShowTop">
|
||||||
|
<div id="recompiling"><span>Recompiling...</span></div>
|
||||||
|
<div class="toolbar">
|
||||||
|
<div class="item">
|
||||||
|
<select id="opts-device">
|
||||||
|
<option value="0">Default</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<v-btn id="btn-rotate" small height="25"><span style="color: #aaa;">Rotate</span></v-btn>
|
||||||
|
</div>
|
||||||
|
<span style="font-size: small;display: none;" class="item">Debug Mode:</span>
|
||||||
|
<div class="item" style="display: none;">
|
||||||
|
<select id="opts-debug-mode">
|
||||||
|
<option value="0">None</option>
|
||||||
|
<option value="1">Info</option>
|
||||||
|
<option value="2">Warn</option>
|
||||||
|
<option value="3">Error</option>
|
||||||
|
<option value="4">Info For Web Page</option>
|
||||||
|
<option value="5">Warn For Web Page</option>
|
||||||
|
<option value="6">Error For Web Page</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<v-btn id="btn-show-fps" small height="25"><span style="color: #aaa;">Show FPS</span></v-btn>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<span style="font-size: small;color: #aaa;" class="item">FPS:</span><input id="input-set-fps"
|
||||||
|
type="number" />
|
||||||
|
</div>
|
||||||
|
<div style="margin-right: 0px;" class="item">
|
||||||
|
<v-btn id="btn-pause" small height="25"><span style="color: #aaa;">Pause</span></v-btn>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<v-btn id="btn-step" style="display: none;" small height="25">
|
||||||
|
<span style="color: #aaa;">Step</span>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<v-btn id="btn-recompile" small height="25"><span style="color: #aaa;">Recompile</span></v-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-navigation-drawer v-model="drawer" app clipped fixed width="512" v-if="isShowTop">
|
||||||
|
<v-container style="height: 50%;overflow: auto;">
|
||||||
|
<v-text-field v-model="treeSearchText" dense label="Search Node or Component" dark flat solo-inverted
|
||||||
|
hide-details clearable clear-icon="mdi-close-circle-outline"></v-text-field>
|
||||||
|
<v-treeview :items="treeData" item-key="id" dense activatable :search="treeSearchText"
|
||||||
|
:active.sync="selectedNodes">
|
||||||
|
<template v-slot:label="{ item, active, open }">
|
||||||
|
<label v-if="item.active" style="color: white;">{{ item.name }}</label>
|
||||||
|
<label v-else style="color: gray;">{{ item.name }}</label>
|
||||||
|
</template>
|
||||||
|
</v-treeview>
|
||||||
|
</v-container>
|
||||||
|
<v-container style="border-top: 2px solid darkgray;height: 50%;overflow-y: auto;">
|
||||||
|
<template v-if="selectedNode && selectedNode.parent">
|
||||||
|
<!-- Node -->
|
||||||
|
<table style="width: 100%;color: white;" border="1">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="2" style="text-align: left; padding: 10px;">
|
||||||
|
<div class="float-left" style="display:inline-flex;">
|
||||||
|
<v-simple-checkbox v-model="selectedNode.active"></v-simple-checkbox>
|
||||||
|
<span style="margin-left: 10px;">{{ nodeSchema.title }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="float-right">
|
||||||
|
<v-icon style="margin-left: 10px;margin-right: 10px;" @click="drawNodeRect()">
|
||||||
|
mdi-adjust</v-icon>
|
||||||
|
<v-icon @click="outputNodeHandler()">mdi-send</v-icon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="row in nodeSchema.rows" :key="row.name">
|
||||||
|
<td style="padding: 10px;width: 40%;">{{ row.name }}</td>
|
||||||
|
<td style="width: 60%;">
|
||||||
|
<v-color-picker v-if="row.type == 'color'" class="ma-2" canvas-height="80" width="259"
|
||||||
|
v-model="selectedNode[row.key]"></v-color-picker>
|
||||||
|
<v-simple-checkbox v-else-if="row.type == 'bool'" v-model="selectedNode[row.key]"
|
||||||
|
style="padding: 10px;width: 100%;"></v-simple-checkbox>
|
||||||
|
<input v-else-if="row.type == 'object_number'" type="number" v-model.number="selectedNode[row.parentKey][row.key]"
|
||||||
|
style="padding: 10px;width: 100%;" @input="onSubPropInput(selectedNode, row)"></input>
|
||||||
|
<input v-else :type="row.type" v-model="selectedNode[row.key]"
|
||||||
|
style="padding: 10px;width: 100%;"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<!-- Components -->
|
||||||
|
<table v-for="component in componentsSchema" style="width: 100%;color: white;" border="1">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="2" style="text-align: left; padding: 10px;">
|
||||||
|
<div class="float-left" style="display:inline-flex;">
|
||||||
|
<v-simple-checkbox v-model="selectedNode[component.key].enabled">
|
||||||
|
</v-simple-checkbox>
|
||||||
|
<span style="margin-left: 10px;">{{ component.title }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="float-right">
|
||||||
|
<v-icon @click="outputComponentHandler(component.key)">mdi-send</v-icon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="row in component.rows" :key="row.key">
|
||||||
|
<td style="padding: 10px;width: 40%;">{{ row.name }}</td>
|
||||||
|
<td style="width: 60%;">
|
||||||
|
<v-color-picker v-if="row.type == 'color'" class="ma-2" canvas-height="80" width="259"
|
||||||
|
v-model="selectedNode[component.key][row.key]"></v-color-picker>
|
||||||
|
<textarea v-else-if="row.type == 'textarea'" rows="1"
|
||||||
|
v-model="selectedNode[component.key][row.key]" style="padding: 10px;width: 100%;">
|
||||||
|
</textarea>
|
||||||
|
<v-simple-checkbox v-else-if="row.type == 'bool'"
|
||||||
|
v-model="selectedNode[component.key][row.key]" style="padding: 10px;width: 100%;">
|
||||||
|
</v-simple-checkbox>
|
||||||
|
<input v-else-if="row.type == 'number'" type="number" v-model.number="selectedNode[component.key][row.key]"
|
||||||
|
style="padding: 10px;width: 100%;"></input>
|
||||||
|
<input v-else :type="row.type" v-model="selectedNode[component.key][row.key]"
|
||||||
|
style="padding: 10px;width: 100%;"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="selectedNode && !selectedNode.parent">
|
||||||
|
<!-- TODO:场景根节点 -->
|
||||||
|
</template>
|
||||||
|
</v-container>
|
||||||
|
</v-navigation-drawer>
|
||||||
|
|
||||||
|
<v-content>
|
||||||
|
<v-container fill-height>
|
||||||
|
<div id="content" class="content">
|
||||||
|
<div class="contentWrap">
|
||||||
|
<div id="GameDiv" class="wrapper">
|
||||||
|
<canvas id="GameCanvas"></canvas>
|
||||||
|
<div id="splash">
|
||||||
|
<div class="progress-bar stripes"><span></span></div>
|
||||||
|
</div>
|
||||||
|
<div id="bulletin">
|
||||||
|
<div id="sceneIsEmpty" class="inner"><%=tip_sceneIsEmpty%></div>
|
||||||
|
</div>
|
||||||
|
<div class="error" id="error">
|
||||||
|
<div class="title">Error <i>(Please open the console to see detailed errors)</i></div>
|
||||||
|
<div class="error-main"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="footer">
|
||||||
|
Created with <a href="https://www.cocos.com/products" target="_blank" title="Cocos Creator 3D">Cocos Creator 3D</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</v-container>
|
||||||
|
</v-content>
|
||||||
|
|
||||||
|
<v-dialog v-model="cacheDialog" persistent scrollable>
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>
|
||||||
|
{{ cacheTitle }}
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-text-field v-model="cacheSearchText" append-icon="mdi-magnify" label="Search" single-line
|
||||||
|
hide-details>
|
||||||
|
</v-text-field>
|
||||||
|
</v-card-title>
|
||||||
|
<v-divider></v-divider>
|
||||||
|
<v-card-text>
|
||||||
|
<v-data-table :headers="cacheHeaders" :items="cacheData" :search="cacheSearchText" :sort-by="['size']"
|
||||||
|
click:row="openGithub"
|
||||||
|
:sort-desc="[true]" :footer-props="{
|
||||||
|
showFirstLastPage: true,
|
||||||
|
firstIcon: 'mdi-chevron-double-left',
|
||||||
|
lastIcon: 'mdi-chevron-double-right',
|
||||||
|
}">
|
||||||
|
<template v-slot:item.size="{ item }">
|
||||||
|
{{ item.size == -1 ? '_' : (item.size +'MB') }}
|
||||||
|
</template>
|
||||||
|
<template v-slot:item.preview="{ item }">
|
||||||
|
<div style="height: 60px;display: flex;align-items: center;">
|
||||||
|
<img :src="window.location.protocol + '//' + window.location.host + '/' + item.preview"
|
||||||
|
style="max-height: 60px;max-width: 120px;" v-if="item.preview">
|
||||||
|
<template v-else>_</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</v-card-text>
|
||||||
|
<v-divider></v-divider>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-btn color="blue darken-1" text @click="cacheDialog = false">Close</v-btn>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-switch v-model="cacheOnlyTexture" label="只显示纹理"></v-switch>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
</v-app>
|
||||||
|
|
||||||
|
<script src="./libs/js/vue.min.js"></script>
|
||||||
|
<script src="./libs/js/vuetify.js"></script>
|
||||||
|
<script src="./config.js"></script>
|
||||||
|
<script src="./libs/js/cc-console-utils.js"></script>
|
||||||
|
<script src="./preview.js"></script>
|
||||||
|
|
||||||
|
<%- include(cocosTemplate, {}) %>
|
23
preview-template/index.ejs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="icon" href="./favicon.ico" />
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title><%=title%></title>
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width,user-scalable=no,initial-scale=1, minimum-scale=1,maximum-scale=1"
|
||||||
|
/>
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
<meta name="full-screen" content="yes" />
|
||||||
|
<meta name="screen-orientation" content="portrait" />
|
||||||
|
<meta name="x5-fullscreen" content="true" />
|
||||||
|
<meta name="360-fullscreen" content="true" />
|
||||||
|
<meta name="renderer" content="webkit" />
|
||||||
|
<meta name="force-rendering" content="webkit" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="./index.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%- include("./custom.html") %>
|
||||||
|
</body>
|
||||||
|
</html>
|
336
preview-template/libs/css/googlefonts.css
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
src: local('Roboto Thin'), local('Roboto-Thin'), url(../fonts/googlefonts-base.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
src: local('Roboto Thin'), local('Roboto-Thin'), url(../fonts/googlefonts-base.woff22) format('woff2');
|
||||||
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* greek-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
src: local('Roboto Thin'), local('Roboto-Thin'), url(../fonts/googlefonts-base.woff22) format('woff2');
|
||||||
|
unicode-range: U+1F00-1FFF;
|
||||||
|
}
|
||||||
|
/* greek */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
src: local('Roboto Thin'), local('Roboto-Thin'), url(../fonts/googlefonts-base.woff22) format('woff2');
|
||||||
|
unicode-range: U+0370-03FF;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
src: local('Roboto Thin'), local('Roboto-Thin'), url(../fonts/googlefonts-base.woff22) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
src: local('Roboto Thin'), local('Roboto-Thin'), url(../fonts/googlefonts-base.woff22) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
src: local('Roboto Thin'), local('Roboto-Thin'), url(../fonts/googlefonts-base.woff2format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* greek-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+1F00-1FFF;
|
||||||
|
}
|
||||||
|
/* greek */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0370-03FF;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/googlefonts-base.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/googlefonts-base.woff2format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/googlefonts-base.woff2format('woff2');
|
||||||
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* greek-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/googlefonts-base.woff2format('woff2');
|
||||||
|
unicode-range: U+1F00-1FFF;
|
||||||
|
}
|
||||||
|
/* greek */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/googlefonts-base.woff2format('woff2');
|
||||||
|
unicode-range: U+0370-03FF;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/googlefonts-base.woff2format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/googlefonts-base.woff2format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/googlefonts-base.woff2rmat('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* greek-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+1F00-1FFF;
|
||||||
|
}
|
||||||
|
/* greek */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0370-03FF;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/googlefonts-base.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* greek-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+1F00-1FFF;
|
||||||
|
}
|
||||||
|
/* greek */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0370-03FF;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/googlefonts-base.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
src: local('Roboto Black'), local('Roboto-Black'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
src: local('Roboto Black'), local('Roboto-Black'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
/* greek-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
src: local('Roboto Black'), local('Roboto-Black'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+1F00-1FFF;
|
||||||
|
}
|
||||||
|
/* greek */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
src: local('Roboto Black'), local('Roboto-Black'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0370-03FF;
|
||||||
|
}
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
src: local('Roboto Black'), local('Roboto-Black'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
src: local('Roboto Black'), local('Roboto-Black'), url(../fonts/googlefonts-base.woff2f2) format('woff2');
|
||||||
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
src: local('Roboto Black'), local('Roboto-Black'), url(../fonts/googlefonts-base.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
1
preview-template/libs/css/materialdesignicons.min.css
vendored
Normal file
8
preview-template/libs/css/vuetify.min.css
vendored
Normal file
BIN
preview-template/libs/fonts/googlefonts-base.woff2
Normal file
BIN
preview-template/libs/fonts/materialdesignicons-webfont.eot
Normal file
BIN
preview-template/libs/fonts/materialdesignicons-webfont.ttf
Normal file
BIN
preview-template/libs/fonts/materialdesignicons-webfont.woff
Normal file
BIN
preview-template/libs/fonts/materialdesignicons-webfont.woff2
Normal file
178
preview-template/libs/js/cc-console-utils.js
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
const initConsoleUtil = function () {
|
||||||
|
if (cc.tree) return;
|
||||||
|
cc.tree = function (key) {
|
||||||
|
let index = key || 0;
|
||||||
|
let treeNode = function (node) {
|
||||||
|
let nameStyle =
|
||||||
|
`color: ${node.parent === null || node.activeInHierarchy ? 'green' : 'grey'}; font-size: 14px;font-weight:bold`;
|
||||||
|
let propStyle =
|
||||||
|
`color: black; background: lightgrey;margin-left: 5px;border-radius:3px;padding: 0 3px;font-size: 10px;font-weight:bold`;
|
||||||
|
let indexStyle =
|
||||||
|
`color: orange; background: black;margin-left: 5px;border-radius:3px;padding:0 3px;fonrt-size: 10px;font-weight:bold;`
|
||||||
|
let nameValue = `%c${node.name}`;
|
||||||
|
let propValue =
|
||||||
|
`%c${node.position.x.toFixed(0) + ',' + node.position.y.toFixed(0)}`
|
||||||
|
let indexValue = `%c${index++}`;
|
||||||
|
if (node.children.length > 0) {
|
||||||
|
console.groupCollapsed(nameValue + propValue + indexValue, nameStyle,
|
||||||
|
propStyle, indexStyle);
|
||||||
|
for (let i = 0; i < node.children.length; i++) {
|
||||||
|
treeNode(node.children[i]);
|
||||||
|
}
|
||||||
|
console.groupEnd();
|
||||||
|
} else {
|
||||||
|
console.log(nameValue + propValue + indexValue, nameStyle, propStyle,
|
||||||
|
indexStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key) {
|
||||||
|
let node = cc.cat(key);
|
||||||
|
index = node['tempIndex'];
|
||||||
|
treeNode(node);
|
||||||
|
} else {
|
||||||
|
let scene = cc.director.getScene();
|
||||||
|
treeNode(scene);
|
||||||
|
}
|
||||||
|
return '属性依次为x,y,width,height,scale.使用cc.cat(id)查看详细属性.';
|
||||||
|
}
|
||||||
|
cc.cat = function (key) {
|
||||||
|
let index = 0;
|
||||||
|
let target;
|
||||||
|
let sortId = function (node) {
|
||||||
|
if (target) return;
|
||||||
|
if (cc.js.isNumber(key)) {
|
||||||
|
if (key === index++) {
|
||||||
|
target = node;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (key.toLowerCase() === node.name.toLowerCase()) {
|
||||||
|
target = node;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node.children.length > 0) {
|
||||||
|
for (let i = 0; i < node.children.length; i++) {
|
||||||
|
sortId(node.children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let scene = cc.director.getScene();
|
||||||
|
sortId(scene);
|
||||||
|
target['tempIndex'] = cc.js.isNumber(key) ? key : index;
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
cc.list = function (key) {
|
||||||
|
let targets = [];
|
||||||
|
let step = function (node) {
|
||||||
|
if (node.name.toLowerCase().indexOf(key.toLowerCase()) > -1) {
|
||||||
|
targets.push(node);
|
||||||
|
}
|
||||||
|
if (node.children.length > 0) {
|
||||||
|
for (let i = 0; i < node.children.length; i++) {
|
||||||
|
step(node.children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let scene = cc.director.getScene();
|
||||||
|
step(scene);
|
||||||
|
if (targets.length === 1) {
|
||||||
|
return targets[0];
|
||||||
|
} else {
|
||||||
|
return targets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cc.where = function (key) {
|
||||||
|
let target = key.name ? key : cc.cat(key);
|
||||||
|
if (!target) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let rect;
|
||||||
|
let transform = target.getComponent(cc.UITransformComponent);
|
||||||
|
if (transform) {
|
||||||
|
rect = getSelfBoundingBoxToWold(transform);
|
||||||
|
} else {
|
||||||
|
let worldPos = cc.v3();
|
||||||
|
target.getWorldPosition(worldPos);
|
||||||
|
rect = cc.rect(worldPos.x, worldPos.y, 0, 0);
|
||||||
|
}
|
||||||
|
let canvasNode = new cc.Node('Canvas');
|
||||||
|
let scene = cc.director.getScene();
|
||||||
|
scene.addChild(canvasNode);
|
||||||
|
canvasNode.addComponent(cc.Canvas);
|
||||||
|
let bgNode = new cc.Node();
|
||||||
|
let graphics = bgNode.addComponent(cc.GraphicsComponent);
|
||||||
|
let bgTransform = bgNode.addComponent(cc.UITransformComponent);
|
||||||
|
canvasNode.addChild(bgNode);
|
||||||
|
let centerPos = cc.v3(rect.center.x, rect.center.y, 0);
|
||||||
|
let localPos = cc.v3();
|
||||||
|
canvasNode.getComponent(cc.UITransformComponent).convertToNodeSpaceAR(centerPos, localPos);
|
||||||
|
bgNode.setPosition(localPos);
|
||||||
|
bgNode.layer = target.layer;
|
||||||
|
let isZeroSize = rect.width === 0 || rect.height === 0;
|
||||||
|
if (isZeroSize) {
|
||||||
|
graphics.circle(0, 0, 100);
|
||||||
|
graphics.fillColor = cc.Color.GREEN;
|
||||||
|
graphics.fill();
|
||||||
|
} else {
|
||||||
|
bgTransform.width = rect.width;
|
||||||
|
bgTransform.height = rect.height;
|
||||||
|
graphics.rect(-bgTransform.width / 2, -bgTransform.height / 2, bgTransform.width, bgTransform.height);
|
||||||
|
graphics.fillColor = new cc.Color().fromHEX('#E91E6390');
|
||||||
|
graphics.fill();
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
if (cc.isValid(canvasNode)) {
|
||||||
|
canvasNode.destroy();
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
cc.cache = function () {
|
||||||
|
let rawCacheData = cc.loader._cache;
|
||||||
|
let cacheData = [];
|
||||||
|
let totalTextureSize = 0;
|
||||||
|
for (let k in rawCacheData) {
|
||||||
|
let item = rawCacheData[k];
|
||||||
|
let preview = '';
|
||||||
|
let type = item.__classname__;
|
||||||
|
let formatSize = -1;
|
||||||
|
if (type === 'cc.Texture2D') {
|
||||||
|
let image = item.mipmaps[0]
|
||||||
|
preview = image.url;
|
||||||
|
let textureSize = image.width * image.height * ((image._native === '.jpg' ? 3 : 4) / 1024 / 1024);
|
||||||
|
totalTextureSize += textureSize;
|
||||||
|
// sizeStr = textureSize.toFixed(3) + 'M';
|
||||||
|
formatSize = Math.round(textureSize * 1000) / 1000;
|
||||||
|
}
|
||||||
|
cacheData.push({
|
||||||
|
type: type,
|
||||||
|
preview: preview,
|
||||||
|
id: item._uuid,
|
||||||
|
size: formatSize
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let cacheTitle = `缓存 [文件总数:${cacheData.length}][纹理缓存:${totalTextureSize.toFixed(2) + 'M'}]`;
|
||||||
|
return [cacheData, cacheTitle];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelfBoundingBoxToWold(transform) {
|
||||||
|
let _worldMatrix = cc.mat4();
|
||||||
|
if (transform.node.parent) {
|
||||||
|
transform.node.parent.getWorldMatrix(_worldMatrix);
|
||||||
|
let parentMat = _worldMatrix;
|
||||||
|
let _matrix = cc.mat4();
|
||||||
|
cc.Mat4.fromRTS(_matrix, transform.node.getRotation(), transform.node.getPosition(), transform.node.getScale());
|
||||||
|
const width = transform._contentSize.width;
|
||||||
|
const height = transform._contentSize.height;
|
||||||
|
const rect = cc.rect(-transform._anchorPoint.x * width, -transform._anchorPoint.y * height, width, height);
|
||||||
|
cc.Mat4.multiply(_worldMatrix, parentMat, _matrix);
|
||||||
|
rect.transformMat4(_worldMatrix);
|
||||||
|
return rect;
|
||||||
|
} else {
|
||||||
|
return transform.getBoundingBox();
|
||||||
|
}
|
||||||
|
}
|
6
preview-template/libs/js/vue.min.js
vendored
Normal file
41498
preview-template/libs/js/vuetify.js
Normal file
201
preview-template/preview.js
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
const app = new Vue({
|
||||||
|
el: '#app',
|
||||||
|
vuetify: new Vuetify({
|
||||||
|
theme: { dark: true }
|
||||||
|
}),
|
||||||
|
data: {
|
||||||
|
isShowTop: true,
|
||||||
|
drawer: false,
|
||||||
|
cacheDialog: false,
|
||||||
|
cacheTitle: '',
|
||||||
|
cacheHeaders: [
|
||||||
|
{ text: 'Type', value: 'type' },
|
||||||
|
{ text: 'Preivew', value: 'preview' },
|
||||||
|
{ text: 'ID', value: 'id' },
|
||||||
|
{ text: 'Size', value: 'size' },
|
||||||
|
],
|
||||||
|
cacheRawData: [],
|
||||||
|
cacheData: [],
|
||||||
|
cacheSearchText: null,
|
||||||
|
cacheOnlyTexture: true,
|
||||||
|
treeData: [],
|
||||||
|
selectedNodes: [],
|
||||||
|
intervalId: -1,
|
||||||
|
treeSearchText: null,
|
||||||
|
nodeSchema: {},
|
||||||
|
componentsSchema: [],
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (window.innerHeight === window.outerHeight) { // 手机端,chrome device模式
|
||||||
|
this.isShowTop = false;
|
||||||
|
}
|
||||||
|
this.waitCCInit().then(() => {
|
||||||
|
if (this.isShowTop) {
|
||||||
|
this.startUpdateTree();
|
||||||
|
}
|
||||||
|
initConsoleUtil();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
cacheOnlyTexture() {
|
||||||
|
this.updateCacheData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
treeFilter() {
|
||||||
|
return (item, search, textKey) => item[textKey].indexOf(search) > -1;
|
||||||
|
},
|
||||||
|
selectedNode() {
|
||||||
|
if (!this.selectedNodes.length) return undefined
|
||||||
|
let node = getNodeById(this.selectedNodes[0]);
|
||||||
|
if (node) {
|
||||||
|
let superPreLoad = node._onPreDestroy;
|
||||||
|
node._onPreDestroy = () => {
|
||||||
|
superPreLoad.apply(node);
|
||||||
|
if (this.selectedNodes.length > 0 && this.selectedNodes[0] === node._id) {
|
||||||
|
this.selectedNodes.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.nodeSchema = NEX_CONFIG.nodeSchema.node;
|
||||||
|
let componentsSchema = [];
|
||||||
|
for (let component of node._components) {
|
||||||
|
let schema = NEX_CONFIG.componentsSchema[component.__classname__];
|
||||||
|
if (schema) {
|
||||||
|
node[schema.key] = node.getComponent(schema.key);
|
||||||
|
for (let i = 0; i < schema.rows.length; i++) {
|
||||||
|
if (schema.rows[i].type === 'color') {
|
||||||
|
if (!node[schema.key][schema.rows[i].key]) {
|
||||||
|
cc.js.getset(node[schema.key], schema.rows[i].key, () => {
|
||||||
|
return '#' + node.getComponent(schema.key)[schema.rows[i].rawKey].toHEX('#rrggbb');
|
||||||
|
}, (hex) => {
|
||||||
|
node.getComponent(schema.key)[schema.rows[i].rawKey] = new cc.Color().fromHEX(hex);
|
||||||
|
}, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
schema = {
|
||||||
|
title: component.__classname__,
|
||||||
|
key: component.__classname__
|
||||||
|
};
|
||||||
|
node[schema.key] = node.getComponent(schema.key);
|
||||||
|
}
|
||||||
|
componentsSchema.push(schema);
|
||||||
|
}
|
||||||
|
this.componentsSchema = componentsSchema;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
waitCCInit() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let id = setInterval(() => {
|
||||||
|
if (window.cc) {
|
||||||
|
resolve();
|
||||||
|
clearInterval(id);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
refreshTree: function () {
|
||||||
|
if (!this.$data.drawer || !window.cc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let currentScene = cc.director.getScene();
|
||||||
|
if (!currentScene || !currentScene.children) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 包含场景根节点
|
||||||
|
// this.$data.treeData = [{ id: currentScene._id, name: 'Scene', active: currentScene.activeInHierarchy, open: true, children: getChildren(currentScene) }];
|
||||||
|
this.$data.treeData = getChildren(currentScene);
|
||||||
|
},
|
||||||
|
startUpdateTree: function () {
|
||||||
|
this.$data.intervalId = setInterval(() => {
|
||||||
|
this.refreshTree();
|
||||||
|
}, 200);
|
||||||
|
},
|
||||||
|
stopUpdateTree: function () {
|
||||||
|
clearInterval(this.$data.intervalId);
|
||||||
|
},
|
||||||
|
onSubPropInput: function (target, row) {
|
||||||
|
let value = target[row.parentKey][row.key];
|
||||||
|
if (typeof value === 'number' && !isNaN(value)) {
|
||||||
|
if (row.method === 'setRotationFromEuler') {
|
||||||
|
target.setRotationFromEuler(target.eulerAngles.x, target.eulerAngles.y, target.eulerAngles.z);
|
||||||
|
} else {
|
||||||
|
target[row.method](target[row.parentKey]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
outputNodeHandler(id) {
|
||||||
|
let i = 1;
|
||||||
|
while (window['temp' + i] !== undefined) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
window['temp' + i] = this.selectedNode;
|
||||||
|
console.log('temp' + i);
|
||||||
|
console.log(window['temp' + i]);
|
||||||
|
},
|
||||||
|
outputComponentHandler(component) {
|
||||||
|
let i = 1;
|
||||||
|
while (window['temp' + i] !== undefined) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
window['temp' + i] = this.selectedNode.getComponent(component);
|
||||||
|
console.log('temp' + i);
|
||||||
|
console.log(window['temp' + i]);
|
||||||
|
},
|
||||||
|
drawNodeRect() {
|
||||||
|
cc.where(this.selectedNode);
|
||||||
|
},
|
||||||
|
updateCacheData() {
|
||||||
|
if (this.$data.cacheOnlyTexture) {
|
||||||
|
this.$data.cacheData = this.$data.cacheRawData.filter(item => item.type === 'cc.Texture2D');
|
||||||
|
} else {
|
||||||
|
this.$data.cacheData = this.$data.cacheRawData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openCacheDialog() {
|
||||||
|
[this.$data.cacheRawData, this.$data.cacheTitle] = cc.cache();
|
||||||
|
this.updateCacheData();
|
||||||
|
this.$data.cacheDialog = true;
|
||||||
|
},
|
||||||
|
openGithub() {
|
||||||
|
window.open('https://github.com/potato47/ccc-devtools');
|
||||||
|
},
|
||||||
|
openCocosForum() {
|
||||||
|
window.open('https://forum.cocos.com/');
|
||||||
|
},
|
||||||
|
openCocosDocs() {
|
||||||
|
window.open('https://docs.cocos.com/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function getChildren(node) {
|
||||||
|
return node.children.map(child => {
|
||||||
|
let children = (child.children && child.children.length > 0) ? getChildren(child) : [];
|
||||||
|
return { id: child._id, name: child.name, active: child.activeInHierarchy, children };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNodeById(id) {
|
||||||
|
let target;
|
||||||
|
const search = function (node) {
|
||||||
|
if (node._id === id) {
|
||||||
|
target = node;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node.children.length) {
|
||||||
|
for (let i = 0; i < node.children.length; i++) {
|
||||||
|
if (!target) {
|
||||||
|
search(node.children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const scene = cc.director.getScene();
|
||||||
|
search(scene);
|
||||||
|
return target;
|
||||||
|
}
|
BIN
preview-template/screenshots/preview1.gif
Normal file
After Width: | Height: | Size: 849 KiB |
BIN
preview-template/screenshots/preview2.png
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
preview-template/screenshots/preview3.png
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
preview-template/screenshots/preview4.png
Normal file
After Width: | Height: | Size: 205 KiB |
BIN
preview-template/screenshots/preview5.png
Normal file
After Width: | Height: | Size: 189 KiB |
BIN
preview-template/screenshots/t1.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
preview-template/screenshots/t2.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
preview-template/screenshots/t3.png
Normal file
After Width: | Height: | Size: 211 KiB |