全部移动至es模块
This commit is contained in:
@@ -1,69 +1,71 @@
|
||||
/**
|
||||
* 支持标题安全区的布局类。
|
||||
*/
|
||||
class Layout {
|
||||
public clientArea: Rectangle;
|
||||
public safeArea: Rectangle;
|
||||
module es {
|
||||
/**
|
||||
* 支持标题安全区的布局类。
|
||||
*/
|
||||
export class Layout {
|
||||
public clientArea: Rectangle;
|
||||
public safeArea: Rectangle;
|
||||
|
||||
constructor(){
|
||||
this.clientArea = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
|
||||
this.safeArea = this.clientArea;
|
||||
constructor(){
|
||||
this.clientArea = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
|
||||
this.safeArea = this.clientArea;
|
||||
}
|
||||
|
||||
public place(size: Vector2, horizontalMargin: number, verticalMargine: number, alignment: Alignment){
|
||||
let rc = new Rectangle(0, 0, size.x, size.y);
|
||||
if ((alignment & Alignment.left) != 0){
|
||||
rc.x = this.clientArea.x + (this.clientArea.width * horizontalMargin);
|
||||
}else if((alignment & Alignment.right) != 0){
|
||||
rc.x = this.clientArea.x + (this.clientArea.width * (1 - horizontalMargin)) - rc.width;
|
||||
} else if((alignment & Alignment.horizontalCenter) != 0){
|
||||
rc.x = this.clientArea.x + (this.clientArea.width - rc.width) / 2 + (horizontalMargin * this.clientArea.width);
|
||||
}else{
|
||||
|
||||
}
|
||||
|
||||
if ((alignment & Alignment.top) != 0){
|
||||
rc.y = this.clientArea.y + (this.clientArea.height * verticalMargine);
|
||||
}else if((alignment & Alignment.bottom) != 0){
|
||||
rc.y = this.clientArea.y + (this.clientArea.height * (1 - verticalMargine)) - rc.height;
|
||||
} else if((alignment & Alignment.verticalCenter) != 0){
|
||||
rc.y = this.clientArea.y + (this.clientArea.height - rc.height) / 2 + (verticalMargine * this.clientArea.height);
|
||||
}else{
|
||||
|
||||
}
|
||||
|
||||
// 确保布局区域在安全区域内。
|
||||
if (rc.left < this.safeArea.left)
|
||||
rc.x = this.safeArea.left;
|
||||
|
||||
if (rc.right > this.safeArea.right)
|
||||
rc.x = this.safeArea.right - rc.width;
|
||||
|
||||
if (rc.top < this.safeArea.top)
|
||||
rc.y = this.safeArea.top;
|
||||
|
||||
if (rc.bottom > this.safeArea.bottom)
|
||||
rc.y = this.safeArea.bottom - rc.height;
|
||||
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
public place(size: Vector2, horizontalMargin: number, verticalMargine: number, alignment: Alignment){
|
||||
let rc = new Rectangle(0, 0, size.x, size.y);
|
||||
if ((alignment & Alignment.left) != 0){
|
||||
rc.x = this.clientArea.x + (this.clientArea.width * horizontalMargin);
|
||||
}else if((alignment & Alignment.right) != 0){
|
||||
rc.x = this.clientArea.x + (this.clientArea.width * (1 - horizontalMargin)) - rc.width;
|
||||
} else if((alignment & Alignment.horizontalCenter) != 0){
|
||||
rc.x = this.clientArea.x + (this.clientArea.width - rc.width) / 2 + (horizontalMargin * this.clientArea.width);
|
||||
}else{
|
||||
|
||||
}
|
||||
|
||||
if ((alignment & Alignment.top) != 0){
|
||||
rc.y = this.clientArea.y + (this.clientArea.height * verticalMargine);
|
||||
}else if((alignment & Alignment.bottom) != 0){
|
||||
rc.y = this.clientArea.y + (this.clientArea.height * (1 - verticalMargine)) - rc.height;
|
||||
} else if((alignment & Alignment.verticalCenter) != 0){
|
||||
rc.y = this.clientArea.y + (this.clientArea.height - rc.height) / 2 + (verticalMargine * this.clientArea.height);
|
||||
}else{
|
||||
|
||||
}
|
||||
|
||||
// 确保布局区域在安全区域内。
|
||||
if (rc.left < this.safeArea.left)
|
||||
rc.x = this.safeArea.left;
|
||||
|
||||
if (rc.right > this.safeArea.right)
|
||||
rc.x = this.safeArea.right - rc.width;
|
||||
|
||||
if (rc.top < this.safeArea.top)
|
||||
rc.y = this.safeArea.top;
|
||||
|
||||
if (rc.bottom > this.safeArea.bottom)
|
||||
rc.y = this.safeArea.bottom - rc.height;
|
||||
|
||||
return rc;
|
||||
export enum Alignment {
|
||||
none = 0,
|
||||
left = 1,
|
||||
right = 2,
|
||||
horizontalCenter = 4,
|
||||
top = 8,
|
||||
bottom = 16,
|
||||
verticalCenter = 32,
|
||||
topLeft = top | left,
|
||||
topRight = top | right,
|
||||
topCenter = top | horizontalCenter,
|
||||
bottomLeft = bottom | left,
|
||||
bottomRight = bottom | right,
|
||||
bottomCenter = bottom | horizontalCenter,
|
||||
centerLeft = verticalCenter | left,
|
||||
centerRight = verticalCenter | right,
|
||||
center = verticalCenter | horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
enum Alignment {
|
||||
none = 0,
|
||||
left = 1,
|
||||
right = 2,
|
||||
horizontalCenter = 4,
|
||||
top = 8,
|
||||
bottom = 16,
|
||||
verticalCenter = 32,
|
||||
topLeft = top | left,
|
||||
topRight = top | right,
|
||||
topCenter = top | horizontalCenter,
|
||||
bottomLeft = bottom | left,
|
||||
bottomRight = bottom | right,
|
||||
bottomCenter = bottom | horizontalCenter,
|
||||
centerLeft = verticalCenter | left,
|
||||
centerRight = verticalCenter | right,
|
||||
center = verticalCenter | horizontalCenter
|
||||
}
|
||||
@@ -1,349 +1,351 @@
|
||||
/**
|
||||
* 通过使用这个类,您可以直观地找到瓶颈和基本的CPU使用情况。
|
||||
*/
|
||||
class TimeRuler {
|
||||
/** 最大条数 8 */
|
||||
public static readonly maxBars = 8;
|
||||
/** */
|
||||
public static readonly maxSamples = 256;
|
||||
/** 每条的最大嵌套调用 */
|
||||
public static readonly maxNestCall = 32;
|
||||
/** 条的高度(以像素为单位) */
|
||||
public static readonly barHeight = 8;
|
||||
/** 最大显示帧 */
|
||||
public static readonly maxSampleFrames = 4;
|
||||
/** 持续时间(帧数)为采取抓拍日志。 */
|
||||
public static readonly logSnapDuration = 120;
|
||||
public static readonly barPadding = 2;
|
||||
public static readonly autoAdjustDelay = 30;
|
||||
public static Instance: TimeRuler;
|
||||
private _frameKey = 'frame';
|
||||
private _logKey = 'log';
|
||||
|
||||
/** 每帧的日志 */
|
||||
private _logs: FrameLog[];
|
||||
/** 当前显示帧计数 */
|
||||
private sampleFrames: number;
|
||||
/** 获取/设置目标样本帧。 */
|
||||
public targetSampleFrames: number;
|
||||
/** 获取/设置计时器标尺宽度。 */
|
||||
public width: number;
|
||||
public enabled: true;
|
||||
/** TimerRuler画的位置。 */
|
||||
private _position: Vector2;
|
||||
/** 上一帧日志 */
|
||||
private _prevLog: FrameLog;
|
||||
/** 当前帧日志 */
|
||||
private _curLog: FrameLog;
|
||||
/** 当前帧数量 */
|
||||
private frameCount: number;
|
||||
/** */
|
||||
private markers: MarkerInfo[] = [];
|
||||
/** 秒表用来测量时间。 */
|
||||
private stopwacth: stopwatch.Stopwatch = new stopwatch.Stopwatch();
|
||||
/** 从标记名映射到标记id的字典。 */
|
||||
private _markerNameToIdMap: Map<string, number> = new Map<string, number>();
|
||||
module es {
|
||||
/**
|
||||
* 你想在游戏开始时调用StartFrame更新方法。
|
||||
* 当游戏在固定时间步进模式下运行缓慢时,更新会多次调用。
|
||||
* 在这种情况下,我们应该忽略StartFrame调用。
|
||||
* 为此,我们只需一直跟踪StartFrame调用的次数,直到Draw被调用。
|
||||
* 通过使用这个类,您可以直观地找到瓶颈和基本的CPU使用情况。
|
||||
*/
|
||||
private _updateCount: number;
|
||||
/** */
|
||||
public showLog = false;
|
||||
private _frameAdjust: number;
|
||||
export class TimeRuler {
|
||||
/** 最大条数 8 */
|
||||
public static readonly maxBars = 8;
|
||||
/** */
|
||||
public static readonly maxSamples = 256;
|
||||
/** 每条的最大嵌套调用 */
|
||||
public static readonly maxNestCall = 32;
|
||||
/** 条的高度(以像素为单位) */
|
||||
public static readonly barHeight = 8;
|
||||
/** 最大显示帧 */
|
||||
public static readonly maxSampleFrames = 4;
|
||||
/** 持续时间(帧数)为采取抓拍日志。 */
|
||||
public static readonly logSnapDuration = 120;
|
||||
public static readonly barPadding = 2;
|
||||
public static readonly autoAdjustDelay = 30;
|
||||
public static Instance: TimeRuler;
|
||||
private _frameKey = 'frame';
|
||||
private _logKey = 'log';
|
||||
|
||||
constructor() {
|
||||
TimeRuler.Instance = this;
|
||||
this._logs = new Array<FrameLog>(2);
|
||||
for (let i = 0; i < this._logs.length; ++i)
|
||||
this._logs[i] = new FrameLog();
|
||||
/** 每帧的日志 */
|
||||
private _logs: FrameLog[];
|
||||
/** 当前显示帧计数 */
|
||||
private sampleFrames: number;
|
||||
/** 获取/设置目标样本帧。 */
|
||||
public targetSampleFrames: number;
|
||||
/** 获取/设置计时器标尺宽度。 */
|
||||
public width: number;
|
||||
public enabled: true;
|
||||
/** TimerRuler画的位置。 */
|
||||
private _position: Vector2;
|
||||
/** 上一帧日志 */
|
||||
private _prevLog: FrameLog;
|
||||
/** 当前帧日志 */
|
||||
private _curLog: FrameLog;
|
||||
/** 当前帧数量 */
|
||||
private frameCount: number;
|
||||
/** */
|
||||
private markers: MarkerInfo[] = [];
|
||||
/** 秒表用来测量时间。 */
|
||||
private stopwacth: stopwatch.Stopwatch = new stopwatch.Stopwatch();
|
||||
/** 从标记名映射到标记id的字典。 */
|
||||
private _markerNameToIdMap: Map<string, number> = new Map<string, number>();
|
||||
/**
|
||||
* 你想在游戏开始时调用StartFrame更新方法。
|
||||
* 当游戏在固定时间步进模式下运行缓慢时,更新会多次调用。
|
||||
* 在这种情况下,我们应该忽略StartFrame调用。
|
||||
* 为此,我们只需一直跟踪StartFrame调用的次数,直到Draw被调用。
|
||||
*/
|
||||
private _updateCount: number;
|
||||
/** */
|
||||
public showLog = false;
|
||||
private _frameAdjust: number;
|
||||
|
||||
this.sampleFrames = this.targetSampleFrames = 1;
|
||||
this.width = SceneManager.stage.stageWidth * 0.8;
|
||||
this.onGraphicsDeviceReset();
|
||||
}
|
||||
constructor() {
|
||||
TimeRuler.Instance = this;
|
||||
this._logs = new Array<FrameLog>(2);
|
||||
for (let i = 0; i < this._logs.length; ++i)
|
||||
this._logs[i] = new FrameLog();
|
||||
|
||||
private onGraphicsDeviceReset() {
|
||||
let layout = new Layout();
|
||||
this._position = layout.place(new Vector2(this.width, TimeRuler.barHeight), 0, 0.01, Alignment.bottomCenter).location;
|
||||
}
|
||||
this.sampleFrames = this.targetSampleFrames = 1;
|
||||
this.width = SceneManager.stage.stageWidth * 0.8;
|
||||
this.onGraphicsDeviceReset();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public startFrame() {
|
||||
// 当这个方法被多次调用时,我们跳过重置帧。
|
||||
let lock = new LockUtils(this._frameKey);
|
||||
lock.lock().then(() => {
|
||||
this._updateCount = parseInt(egret.localStorage.getItem(this._frameKey), 10);
|
||||
if (isNaN(this._updateCount))
|
||||
this._updateCount = 0;
|
||||
let count = this._updateCount;
|
||||
count += 1;
|
||||
egret.localStorage.setItem(this._frameKey, count.toString());
|
||||
if (this.enabled && (1 < count && count < TimeRuler.maxSampleFrames))
|
||||
return;
|
||||
private onGraphicsDeviceReset() {
|
||||
let layout = new Layout();
|
||||
this._position = layout.place(new Vector2(this.width, TimeRuler.barHeight), 0, 0.01, Alignment.bottomCenter).location;
|
||||
}
|
||||
|
||||
// 更新当前帧日志。
|
||||
this._prevLog = this._logs[this.frameCount++ & 0x1];
|
||||
this._curLog = this._logs[this.frameCount & 0x1];
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public startFrame() {
|
||||
// 当这个方法被多次调用时,我们跳过重置帧。
|
||||
let lock = new LockUtils(this._frameKey);
|
||||
lock.lock().then(() => {
|
||||
this._updateCount = parseInt(egret.localStorage.getItem(this._frameKey), 10);
|
||||
if (isNaN(this._updateCount))
|
||||
this._updateCount = 0;
|
||||
let count = this._updateCount;
|
||||
count += 1;
|
||||
egret.localStorage.setItem(this._frameKey, count.toString());
|
||||
if (this.enabled && (1 < count && count < TimeRuler.maxSampleFrames))
|
||||
return;
|
||||
|
||||
let endFrameTime = this.stopwacth.getTime();
|
||||
// 更新标记并创建日志。
|
||||
for (let barIndex = 0; barIndex < this._prevLog.bars.length; ++barIndex) {
|
||||
let prevBar = this._prevLog.bars[barIndex];
|
||||
let nextBar = this._curLog.bars[barIndex];
|
||||
// 更新当前帧日志。
|
||||
this._prevLog = this._logs[this.frameCount++ & 0x1];
|
||||
this._curLog = this._logs[this.frameCount & 0x1];
|
||||
|
||||
// 重新打开在前一帧中没有调用结束标记的标记。
|
||||
for (let nest = 0; nest < prevBar.nestCount; ++nest) {
|
||||
let markerIdx = prevBar.markerNests[nest];
|
||||
prevBar.markers[markerIdx].endTime = endFrameTime;
|
||||
nextBar.markerNests[nest] = nest;
|
||||
nextBar.markers[nest].markerId = prevBar.markers[markerIdx].markerId;
|
||||
nextBar.markers[nest].beginTime = 0;
|
||||
nextBar.markers[nest].endTime = -1;
|
||||
nextBar.markers[nest].color = prevBar.markers[markerIdx].color;
|
||||
}
|
||||
let endFrameTime = this.stopwacth.getTime();
|
||||
// 更新标记并创建日志。
|
||||
for (let barIndex = 0; barIndex < this._prevLog.bars.length; ++barIndex) {
|
||||
let prevBar = this._prevLog.bars[barIndex];
|
||||
let nextBar = this._curLog.bars[barIndex];
|
||||
|
||||
// 更新日志标记
|
||||
for (let markerIdx = 0; markerIdx < prevBar.markCount; ++markerIdx) {
|
||||
let duration = prevBar.markers[markerIdx].endTime - prevBar.markers[markerIdx].beginTime;
|
||||
let markerId = prevBar.markers[markerIdx].markerId;
|
||||
let m = this.markers[markerId];
|
||||
// 重新打开在前一帧中没有调用结束标记的标记。
|
||||
for (let nest = 0; nest < prevBar.nestCount; ++nest) {
|
||||
let markerIdx = prevBar.markerNests[nest];
|
||||
prevBar.markers[markerIdx].endTime = endFrameTime;
|
||||
nextBar.markerNests[nest] = nest;
|
||||
nextBar.markers[nest].markerId = prevBar.markers[markerIdx].markerId;
|
||||
nextBar.markers[nest].beginTime = 0;
|
||||
nextBar.markers[nest].endTime = -1;
|
||||
nextBar.markers[nest].color = prevBar.markers[markerIdx].color;
|
||||
}
|
||||
|
||||
m.logs[barIndex].color = prevBar.markers[markerIdx].color;
|
||||
if (!m.logs[barIndex].initialized) {
|
||||
m.logs[barIndex].min = duration;
|
||||
m.logs[barIndex].max = duration;
|
||||
m.logs[barIndex].avg = duration;
|
||||
m.logs[barIndex].initialized = true;
|
||||
} else {
|
||||
m.logs[barIndex].min = Math.min(m.logs[barIndex].min, duration);
|
||||
m.logs[barIndex].max = Math.min(m.logs[barIndex].max, duration);
|
||||
m.logs[barIndex].avg += duration;
|
||||
m.logs[barIndex].avg *= 0.5;
|
||||
// 更新日志标记
|
||||
for (let markerIdx = 0; markerIdx < prevBar.markCount; ++markerIdx) {
|
||||
let duration = prevBar.markers[markerIdx].endTime - prevBar.markers[markerIdx].beginTime;
|
||||
let markerId = prevBar.markers[markerIdx].markerId;
|
||||
let m = this.markers[markerId];
|
||||
|
||||
if (m.logs[barIndex].samples++ >= TimeRuler.logSnapDuration) {
|
||||
m.logs[barIndex].snapMin = m.logs[barIndex].min;
|
||||
m.logs[barIndex].snapMax = m.logs[barIndex].max;
|
||||
m.logs[barIndex].snapAvg = m.logs[barIndex].avg;
|
||||
m.logs[barIndex].samples = 0;
|
||||
m.logs[barIndex].color = prevBar.markers[markerIdx].color;
|
||||
if (!m.logs[barIndex].initialized) {
|
||||
m.logs[barIndex].min = duration;
|
||||
m.logs[barIndex].max = duration;
|
||||
m.logs[barIndex].avg = duration;
|
||||
m.logs[barIndex].initialized = true;
|
||||
} else {
|
||||
m.logs[barIndex].min = Math.min(m.logs[barIndex].min, duration);
|
||||
m.logs[barIndex].max = Math.min(m.logs[barIndex].max, duration);
|
||||
m.logs[barIndex].avg += duration;
|
||||
m.logs[barIndex].avg *= 0.5;
|
||||
|
||||
if (m.logs[barIndex].samples++ >= TimeRuler.logSnapDuration) {
|
||||
m.logs[barIndex].snapMin = m.logs[barIndex].min;
|
||||
m.logs[barIndex].snapMax = m.logs[barIndex].max;
|
||||
m.logs[barIndex].snapAvg = m.logs[barIndex].avg;
|
||||
m.logs[barIndex].samples = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nextBar.markCount = prevBar.nestCount;
|
||||
nextBar.nestCount = prevBar.nestCount;
|
||||
}
|
||||
|
||||
nextBar.markCount = prevBar.nestCount;
|
||||
nextBar.nestCount = prevBar.nestCount;
|
||||
}
|
||||
|
||||
this.stopwacth.reset();
|
||||
this.stopwacth.start();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始测量时间。
|
||||
* @param markerName
|
||||
* @param color
|
||||
*/
|
||||
public beginMark(markerName: string, color: number, barIndex: number = 0) {
|
||||
let lock = new LockUtils(this._frameKey);
|
||||
lock.lock().then(() => {
|
||||
if (barIndex < 0 || barIndex >= TimeRuler.maxBars)
|
||||
throw new Error("barIndex argument out of range");
|
||||
|
||||
let bar = this._curLog.bars[barIndex];
|
||||
if (bar.markCount >= TimeRuler.maxSamples) {
|
||||
throw new Error("exceeded sample count. either set larger number to timeruler.maxsaple or lower sample count");
|
||||
}
|
||||
|
||||
if (bar.nestCount >= TimeRuler.maxNestCall) {
|
||||
throw new Error("exceeded nest count. either set larger number to timeruler.maxnestcall or lower nest calls");
|
||||
}
|
||||
|
||||
// 获取注册的标记
|
||||
let markerId = this._markerNameToIdMap.get(markerName);
|
||||
if (isNaN(markerId)) {
|
||||
// 如果此标记未注册,则注册此标记。
|
||||
markerId = this.markers.length;
|
||||
this._markerNameToIdMap.set(markerName, markerId);
|
||||
}
|
||||
|
||||
bar.markerNests[bar.nestCount++] = bar.markCount;
|
||||
bar.markers[bar.markCount].markerId = markerId;
|
||||
bar.markers[bar.markCount].color = color;
|
||||
bar.markers[bar.markCount].beginTime = this.stopwacth.getTime();
|
||||
bar.markers[bar.markCount].endTime = -1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param markerName
|
||||
* @param barIndex
|
||||
*/
|
||||
public endMark(markerName: string, barIndex: number = 0) {
|
||||
let lock = new LockUtils(this._frameKey);
|
||||
lock.lock().then(() => {
|
||||
if (barIndex < 0 || barIndex >= TimeRuler.maxBars)
|
||||
throw new Error("barIndex argument out of range");
|
||||
|
||||
let bar = this._curLog.bars[barIndex];
|
||||
if (bar.nestCount <= 0) {
|
||||
throw new Error("call beginMark method before calling endMark method");
|
||||
}
|
||||
|
||||
let markerId = this._markerNameToIdMap.get(markerName);
|
||||
if (isNaN(markerId)) {
|
||||
throw new Error(`Marker ${markerName} is not registered. Make sure you specifed same name as you used for beginMark method`);
|
||||
}
|
||||
|
||||
let markerIdx = bar.markerNests[--bar.nestCount];
|
||||
if (bar.markers[markerIdx].markerId != markerId) {
|
||||
throw new Error("Incorrect call order of beginMark/endMark method. beginMark(A), beginMark(B), endMark(B), endMark(A) But you can't called it like beginMark(A), beginMark(B), endMark(A), endMark(B).");
|
||||
}
|
||||
|
||||
bar.markers[markerIdx].endTime = this.stopwacth.getTime();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取给定bar索引和标记名称的平均时间。
|
||||
* @param barIndex
|
||||
* @param markerName
|
||||
*/
|
||||
public getAverageTime(barIndex: number, markerName: string) {
|
||||
if (barIndex < 0 || barIndex >= TimeRuler.maxBars) {
|
||||
throw new Error("barIndex argument out of range");
|
||||
}
|
||||
let result = 0;
|
||||
let markerId = this._markerNameToIdMap.get(markerName);
|
||||
if (markerId) {
|
||||
result = this.markers[markerId].logs[barIndex].avg;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public resetLog() {
|
||||
let lock = new LockUtils(this._logKey);
|
||||
lock.lock().then(() => {
|
||||
let count = parseInt(egret.localStorage.getItem(this._logKey), 10);
|
||||
count += 1;
|
||||
egret.localStorage.setItem(this._logKey, count.toString());
|
||||
this.markers.forEach(markerInfo => {
|
||||
for (let i = 0; i < markerInfo.logs.length; ++i){
|
||||
markerInfo.logs[i].initialized = false;
|
||||
markerInfo.logs[i].snapMin = 0;
|
||||
markerInfo.logs[i].snapMax = 0;
|
||||
markerInfo.logs[i].snapAvg = 0;
|
||||
|
||||
markerInfo.logs[i].min = 0;
|
||||
markerInfo.logs[i].max = 0;
|
||||
markerInfo.logs[i].avg = 0;
|
||||
|
||||
markerInfo.logs[i].samples = 0;
|
||||
}
|
||||
this.stopwacth.reset();
|
||||
this.stopwacth.start();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public render(position: Vector2 = this._position, width: number = this.width){
|
||||
egret.localStorage.setItem(this._frameKey, "0");
|
||||
/**
|
||||
* 开始测量时间。
|
||||
* @param markerName
|
||||
* @param color
|
||||
*/
|
||||
public beginMark(markerName: string, color: number, barIndex: number = 0) {
|
||||
let lock = new LockUtils(this._frameKey);
|
||||
lock.lock().then(() => {
|
||||
if (barIndex < 0 || barIndex >= TimeRuler.maxBars)
|
||||
throw new Error("barIndex argument out of range");
|
||||
|
||||
if (!this.showLog)
|
||||
return;
|
||||
let bar = this._curLog.bars[barIndex];
|
||||
if (bar.markCount >= TimeRuler.maxSamples) {
|
||||
throw new Error("exceeded sample count. either set larger number to timeruler.maxsaple or lower sample count");
|
||||
}
|
||||
|
||||
let height = 0;
|
||||
let maxTime = 0;
|
||||
this._prevLog.bars.forEach(bar => {
|
||||
if (bar.markCount > 0){
|
||||
height += TimeRuler.barHeight + TimeRuler.barPadding * 2;
|
||||
maxTime = Math.max(maxTime, bar.markers[bar.markCount - 1].endTime);
|
||||
if (bar.nestCount >= TimeRuler.maxNestCall) {
|
||||
throw new Error("exceeded nest count. either set larger number to timeruler.maxnestcall or lower nest calls");
|
||||
}
|
||||
|
||||
// 获取注册的标记
|
||||
let markerId = this._markerNameToIdMap.get(markerName);
|
||||
if (isNaN(markerId)) {
|
||||
// 如果此标记未注册,则注册此标记。
|
||||
markerId = this.markers.length;
|
||||
this._markerNameToIdMap.set(markerName, markerId);
|
||||
}
|
||||
|
||||
bar.markerNests[bar.nestCount++] = bar.markCount;
|
||||
bar.markers[bar.markCount].markerId = markerId;
|
||||
bar.markers[bar.markCount].color = color;
|
||||
bar.markers[bar.markCount].beginTime = this.stopwacth.getTime();
|
||||
bar.markers[bar.markCount].endTime = -1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param markerName
|
||||
* @param barIndex
|
||||
*/
|
||||
public endMark(markerName: string, barIndex: number = 0) {
|
||||
let lock = new LockUtils(this._frameKey);
|
||||
lock.lock().then(() => {
|
||||
if (barIndex < 0 || barIndex >= TimeRuler.maxBars)
|
||||
throw new Error("barIndex argument out of range");
|
||||
|
||||
let bar = this._curLog.bars[barIndex];
|
||||
if (bar.nestCount <= 0) {
|
||||
throw new Error("call beginMark method before calling endMark method");
|
||||
}
|
||||
|
||||
let markerId = this._markerNameToIdMap.get(markerName);
|
||||
if (isNaN(markerId)) {
|
||||
throw new Error(`Marker ${markerName} is not registered. Make sure you specifed same name as you used for beginMark method`);
|
||||
}
|
||||
|
||||
let markerIdx = bar.markerNests[--bar.nestCount];
|
||||
if (bar.markers[markerIdx].markerId != markerId) {
|
||||
throw new Error("Incorrect call order of beginMark/endMark method. beginMark(A), beginMark(B), endMark(B), endMark(A) But you can't called it like beginMark(A), beginMark(B), endMark(A), endMark(B).");
|
||||
}
|
||||
|
||||
bar.markers[markerIdx].endTime = this.stopwacth.getTime();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取给定bar索引和标记名称的平均时间。
|
||||
* @param barIndex
|
||||
* @param markerName
|
||||
*/
|
||||
public getAverageTime(barIndex: number, markerName: string) {
|
||||
if (barIndex < 0 || barIndex >= TimeRuler.maxBars) {
|
||||
throw new Error("barIndex argument out of range");
|
||||
}
|
||||
let result = 0;
|
||||
let markerId = this._markerNameToIdMap.get(markerName);
|
||||
if (markerId) {
|
||||
result = this.markers[markerId].logs[barIndex].avg;
|
||||
}
|
||||
})
|
||||
|
||||
const frameSpan = 1 / 60 * 1000;
|
||||
let sampleSpan = this.sampleFrames * frameSpan;
|
||||
|
||||
if (maxTime > sampleSpan){
|
||||
this._frameAdjust = Math.max(0, this._frameAdjust) + 1;
|
||||
}else{
|
||||
this._frameAdjust = Math.min(0, this._frameAdjust) - 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (Math.max(this._frameAdjust) > TimeRuler.autoAdjustDelay){
|
||||
this.sampleFrames = Math.min(TimeRuler.maxSampleFrames, this.sampleFrames);
|
||||
this.sampleFrames = Math.max(this.targetSampleFrames, (maxTime / frameSpan) + 1);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public resetLog() {
|
||||
let lock = new LockUtils(this._logKey);
|
||||
lock.lock().then(() => {
|
||||
let count = parseInt(egret.localStorage.getItem(this._logKey), 10);
|
||||
count += 1;
|
||||
egret.localStorage.setItem(this._logKey, count.toString());
|
||||
this.markers.forEach(markerInfo => {
|
||||
for (let i = 0; i < markerInfo.logs.length; ++i){
|
||||
markerInfo.logs[i].initialized = false;
|
||||
markerInfo.logs[i].snapMin = 0;
|
||||
markerInfo.logs[i].snapMax = 0;
|
||||
markerInfo.logs[i].snapAvg = 0;
|
||||
|
||||
this._frameAdjust = 0;
|
||||
markerInfo.logs[i].min = 0;
|
||||
markerInfo.logs[i].max = 0;
|
||||
markerInfo.logs[i].avg = 0;
|
||||
|
||||
markerInfo.logs[i].samples = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let msToPs = width / sampleSpan;
|
||||
let startY = position.y - (height - TimeRuler.barHeight);
|
||||
let y = startY;
|
||||
public render(position: Vector2 = this._position, width: number = this.width){
|
||||
egret.localStorage.setItem(this._frameKey, "0");
|
||||
|
||||
// TODO: draw
|
||||
if (!this.showLog)
|
||||
return;
|
||||
|
||||
let height = 0;
|
||||
let maxTime = 0;
|
||||
this._prevLog.bars.forEach(bar => {
|
||||
if (bar.markCount > 0){
|
||||
height += TimeRuler.barHeight + TimeRuler.barPadding * 2;
|
||||
maxTime = Math.max(maxTime, bar.markers[bar.markCount - 1].endTime);
|
||||
}
|
||||
})
|
||||
|
||||
const frameSpan = 1 / 60 * 1000;
|
||||
let sampleSpan = this.sampleFrames * frameSpan;
|
||||
|
||||
if (maxTime > sampleSpan){
|
||||
this._frameAdjust = Math.max(0, this._frameAdjust) + 1;
|
||||
}else{
|
||||
this._frameAdjust = Math.min(0, this._frameAdjust) - 1;
|
||||
}
|
||||
|
||||
if (Math.max(this._frameAdjust) > TimeRuler.autoAdjustDelay){
|
||||
this.sampleFrames = Math.min(TimeRuler.maxSampleFrames, this.sampleFrames);
|
||||
this.sampleFrames = Math.max(this.targetSampleFrames, (maxTime / frameSpan) + 1);
|
||||
|
||||
this._frameAdjust = 0;
|
||||
}
|
||||
|
||||
let msToPs = width / sampleSpan;
|
||||
let startY = position.y - (height - TimeRuler.barHeight);
|
||||
let y = startY;
|
||||
|
||||
// TODO: draw
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志信息
|
||||
*/
|
||||
export class FrameLog {
|
||||
public bars: MarkerCollection[];
|
||||
|
||||
constructor() {
|
||||
this.bars = new Array<MarkerCollection>(TimeRuler.maxBars);
|
||||
this.bars.fill(new MarkerCollection(), 0, TimeRuler.maxBars);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记的集合
|
||||
*/
|
||||
export class MarkerCollection {
|
||||
public markers: Marker[] = new Array<Marker>(TimeRuler.maxSamples);
|
||||
public markCount: number = 0;
|
||||
public markerNests: number[] = new Array<number>(TimeRuler.maxNestCall);
|
||||
public nestCount: number = 0;
|
||||
|
||||
constructor(){
|
||||
this.markers.fill(new Marker(), 0, TimeRuler.maxSamples);
|
||||
this.markerNests.fill(0, 0, TimeRuler.maxNestCall);
|
||||
}
|
||||
}
|
||||
|
||||
export class Marker {
|
||||
public markerId: number = 0;
|
||||
public beginTime: number = 0;
|
||||
public endTime: number = 0;
|
||||
public color: number = 0x000000;
|
||||
}
|
||||
|
||||
export class MarkerInfo {
|
||||
public name: string;
|
||||
public logs: MarkerLog[] = new Array<MarkerLog>(TimeRuler.maxBars);
|
||||
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
this.logs.fill(new MarkerLog(), 0, TimeRuler.maxBars);
|
||||
}
|
||||
}
|
||||
|
||||
export class MarkerLog {
|
||||
public snapMin: number = 0;
|
||||
public snapMax: number = 0;
|
||||
public snapAvg: number = 0;
|
||||
public min: number = 0;
|
||||
public max: number = 0;
|
||||
public avg: number = 0;
|
||||
public samples: number = 0;
|
||||
public color: number = 0x000000;
|
||||
public initialized: boolean = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志信息
|
||||
*/
|
||||
class FrameLog {
|
||||
public bars: MarkerCollection[];
|
||||
|
||||
constructor() {
|
||||
this.bars = new Array<MarkerCollection>(TimeRuler.maxBars);
|
||||
this.bars.fill(new MarkerCollection(), 0, TimeRuler.maxBars);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记的集合
|
||||
*/
|
||||
class MarkerCollection {
|
||||
public markers: Marker[] = new Array<Marker>(TimeRuler.maxSamples);
|
||||
public markCount: number = 0;
|
||||
public markerNests: number[] = new Array<number>(TimeRuler.maxNestCall);
|
||||
public nestCount: number = 0;
|
||||
|
||||
constructor(){
|
||||
this.markers.fill(new Marker(), 0, TimeRuler.maxSamples);
|
||||
this.markerNests.fill(0, 0, TimeRuler.maxNestCall);
|
||||
}
|
||||
}
|
||||
|
||||
class Marker {
|
||||
public markerId: number = 0;
|
||||
public beginTime: number = 0;
|
||||
public endTime: number = 0;
|
||||
public color: number = 0x000000;
|
||||
}
|
||||
|
||||
class MarkerInfo {
|
||||
public name: string;
|
||||
public logs: MarkerLog[] = new Array<MarkerLog>(TimeRuler.maxBars);
|
||||
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
this.logs.fill(new MarkerLog(), 0, TimeRuler.maxBars);
|
||||
}
|
||||
}
|
||||
|
||||
class MarkerLog {
|
||||
public snapMin: number = 0;
|
||||
public snapMax: number = 0;
|
||||
public snapAvg: number = 0;
|
||||
public min: number = 0;
|
||||
public max: number = 0;
|
||||
public avg: number = 0;
|
||||
public samples: number = 0;
|
||||
public color: number = 0x000000;
|
||||
public initialized: boolean = false;
|
||||
}
|
||||
@@ -1,41 +1,43 @@
|
||||
class ContentManager {
|
||||
protected loadedAssets: Map<string, any> = new Map<string, any>();
|
||||
module es {
|
||||
export class ContentManager {
|
||||
protected loadedAssets: Map<string, any> = new Map<string, any>();
|
||||
|
||||
/** 异步加载资源 */
|
||||
public loadRes(name: string, local: boolean = true): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let res = this.loadedAssets.get(name);
|
||||
if (res) {
|
||||
resolve(res);
|
||||
return;
|
||||
}
|
||||
/** 异步加载资源 */
|
||||
public loadRes(name: string, local: boolean = true): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let res = this.loadedAssets.get(name);
|
||||
if (res) {
|
||||
resolve(res);
|
||||
return;
|
||||
}
|
||||
|
||||
if (local) {
|
||||
RES.getResAsync(name).then((data) => {
|
||||
this.loadedAssets.set(name, data);
|
||||
resolve(data);
|
||||
}).catch((err) => {
|
||||
console.error("资源加载错误:", name, err);
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
RES.getResByUrl(name).then((data) => {
|
||||
this.loadedAssets.set(name, data);
|
||||
resolve(data);
|
||||
}).catch((err) => {
|
||||
console.error("资源加载错误:", name, err);
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
if (local) {
|
||||
RES.getResAsync(name).then((data) => {
|
||||
this.loadedAssets.set(name, data);
|
||||
resolve(data);
|
||||
}).catch((err) => {
|
||||
console.error("资源加载错误:", name, err);
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
RES.getResByUrl(name).then((data) => {
|
||||
this.loadedAssets.set(name, data);
|
||||
resolve(data);
|
||||
}).catch((err) => {
|
||||
console.error("资源加载错误:", name, err);
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this.loadedAssets.forEach(value => {
|
||||
let assetsToRemove = value;
|
||||
assetsToRemove.dispose();
|
||||
});
|
||||
|
||||
this.loadedAssets.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this.loadedAssets.forEach(value => {
|
||||
let assetsToRemove = value;
|
||||
assetsToRemove.dispose();
|
||||
});
|
||||
|
||||
this.loadedAssets.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +1,61 @@
|
||||
/** 各种辅助方法来辅助绘图 */
|
||||
class DrawUtils {
|
||||
public static drawLine(shape: egret.Shape, start: Vector2, end: Vector2, color: number, thickness: number = 1){
|
||||
this.drawLineAngle(shape, start, MathHelper.angleBetweenVectors(start, end), Vector2.distance(start, end), color, thickness);
|
||||
}
|
||||
|
||||
public static drawLineAngle(shape: egret.Shape, start: Vector2, radians: number, length: number, color: number, thickness = 1){
|
||||
shape.graphics.beginFill(color);
|
||||
shape.graphics.drawRect(start.x, start.y, 1, 1);
|
||||
shape.graphics.endFill();
|
||||
|
||||
shape.scaleX = length;
|
||||
shape.scaleY = thickness;
|
||||
shape.$anchorOffsetX = 0;
|
||||
shape.$anchorOffsetY = 0;
|
||||
shape.rotation = radians;
|
||||
}
|
||||
|
||||
public static drawHollowRect(shape: egret.Shape, rect: Rectangle, color: number, thickness = 1){
|
||||
this.drawHollowRectR(shape, rect.x, rect.y, rect.width, rect.height, color, thickness);
|
||||
}
|
||||
|
||||
public static drawHollowRectR(shape: egret.Shape, x: number, y: number, width: number, height: number, color: number, thickness = 1){
|
||||
let tl = new Vector2(x, y).round();
|
||||
let tr = new Vector2(x + width, y).round();
|
||||
let br = new Vector2(x + width, y + height).round();
|
||||
let bl = new Vector2(x, y + height).round();
|
||||
|
||||
this.drawLine(shape, tl, tr, color, thickness);
|
||||
this.drawLine(shape, tr, br, color, thickness);
|
||||
this.drawLine(shape, br, bl, color, thickness);
|
||||
this.drawLine(shape, bl, tl, color, thickness);
|
||||
}
|
||||
|
||||
public static drawPixel(shape: egret.Shape, position: Vector2, color: number, size: number = 1){
|
||||
let destRect = new Rectangle(position.x, position.y, size, size);
|
||||
if (size != 1){
|
||||
destRect.x -= size * 0.5;
|
||||
destRect.y -= size * 0.5;
|
||||
module es {
|
||||
/** 各种辅助方法来辅助绘图 */
|
||||
export class DrawUtils {
|
||||
public static drawLine(shape: egret.Shape, start: Vector2, end: Vector2, color: number, thickness: number = 1){
|
||||
this.drawLineAngle(shape, start, MathHelper.angleBetweenVectors(start, end), Vector2.distance(start, end), color, thickness);
|
||||
}
|
||||
|
||||
shape.graphics.beginFill(color);
|
||||
shape.graphics.drawRect(destRect.x, destRect.y, destRect.width, destRect.height);
|
||||
shape.graphics.endFill();
|
||||
}
|
||||
public static drawLineAngle(shape: egret.Shape, start: Vector2, radians: number, length: number, color: number, thickness = 1){
|
||||
shape.graphics.beginFill(color);
|
||||
shape.graphics.drawRect(start.x, start.y, 1, 1);
|
||||
shape.graphics.endFill();
|
||||
|
||||
public static getColorMatrix(color: number): egret.ColorMatrixFilter{
|
||||
let colorMatrix = [
|
||||
1, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
];
|
||||
colorMatrix[0] = Math.floor(color / 256 / 256) / 255;
|
||||
colorMatrix[6] = Math.floor(color / 256 % 256) / 255;
|
||||
colorMatrix[12] = color % 256 / 255;
|
||||
return new egret.ColorMatrixFilter(colorMatrix);
|
||||
shape.scaleX = length;
|
||||
shape.scaleY = thickness;
|
||||
shape.$anchorOffsetX = 0;
|
||||
shape.$anchorOffsetY = 0;
|
||||
shape.rotation = radians;
|
||||
}
|
||||
|
||||
public static drawHollowRect(shape: egret.Shape, rect: Rectangle, color: number, thickness = 1){
|
||||
this.drawHollowRectR(shape, rect.x, rect.y, rect.width, rect.height, color, thickness);
|
||||
}
|
||||
|
||||
public static drawHollowRectR(shape: egret.Shape, x: number, y: number, width: number, height: number, color: number, thickness = 1){
|
||||
let tl = new Vector2(x, y).round();
|
||||
let tr = new Vector2(x + width, y).round();
|
||||
let br = new Vector2(x + width, y + height).round();
|
||||
let bl = new Vector2(x, y + height).round();
|
||||
|
||||
this.drawLine(shape, tl, tr, color, thickness);
|
||||
this.drawLine(shape, tr, br, color, thickness);
|
||||
this.drawLine(shape, br, bl, color, thickness);
|
||||
this.drawLine(shape, bl, tl, color, thickness);
|
||||
}
|
||||
|
||||
public static drawPixel(shape: egret.Shape, position: Vector2, color: number, size: number = 1){
|
||||
let destRect = new Rectangle(position.x, position.y, size, size);
|
||||
if (size != 1){
|
||||
destRect.x -= size * 0.5;
|
||||
destRect.y -= size * 0.5;
|
||||
}
|
||||
|
||||
shape.graphics.beginFill(color);
|
||||
shape.graphics.drawRect(destRect.x, destRect.y, destRect.width, destRect.height);
|
||||
shape.graphics.endFill();
|
||||
}
|
||||
|
||||
public static getColorMatrix(color: number): egret.ColorMatrixFilter{
|
||||
let colorMatrix = [
|
||||
1, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
];
|
||||
colorMatrix[0] = Math.floor(color / 256 / 256) / 255;
|
||||
colorMatrix[6] = Math.floor(color / 256 % 256) / 255;
|
||||
colorMatrix[12] = color % 256 / 255;
|
||||
return new egret.ColorMatrixFilter(colorMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,69 @@
|
||||
/**
|
||||
* 用于事件管理
|
||||
*/
|
||||
class Emitter<T> {
|
||||
private _messageTable: Map<T, FuncPack[]>;
|
||||
|
||||
constructor(){
|
||||
this._messageTable = new Map<T, FuncPack[]>();
|
||||
}
|
||||
|
||||
module es {
|
||||
/**
|
||||
* 开始监听项
|
||||
* @param eventType 监听类型
|
||||
* @param handler 监听函数
|
||||
* @param context 监听上下文
|
||||
* 用于包装事件的一个小类
|
||||
*/
|
||||
public addObserver(eventType: T, handler: Function, context: any){
|
||||
let list: FuncPack[] = this._messageTable.get(eventType);
|
||||
if (!list){
|
||||
list = [];
|
||||
this._messageTable.set(eventType, list);
|
||||
export class FuncPack {
|
||||
/** 函数 */
|
||||
public func: Function;
|
||||
/** 上下文 */
|
||||
public context: any;
|
||||
|
||||
constructor(func: Function, context: any){
|
||||
this.func = func;
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 用于事件管理
|
||||
*/
|
||||
export class Emitter<T> {
|
||||
private _messageTable: Map<T, FuncPack[]>;
|
||||
|
||||
constructor(){
|
||||
this._messageTable = new Map<T, FuncPack[]>();
|
||||
}
|
||||
|
||||
if (list.contains(handler))
|
||||
console.warn("您试图添加相同的观察者两次");
|
||||
list.push(new FuncPack(handler, context));
|
||||
}
|
||||
/**
|
||||
* 开始监听项
|
||||
* @param eventType 监听类型
|
||||
* @param handler 监听函数
|
||||
* @param context 监听上下文
|
||||
*/
|
||||
public addObserver(eventType: T, handler: Function, context: any){
|
||||
let list: FuncPack[] = this._messageTable.get(eventType);
|
||||
if (!list){
|
||||
list = [];
|
||||
this._messageTable.set(eventType, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除监听项
|
||||
* @param eventType 事件类型
|
||||
* @param handler 事件函数
|
||||
*/
|
||||
public removeObserver(eventType: T, handler: Function){
|
||||
let messageData = this._messageTable.get(eventType);
|
||||
let index = messageData.findIndex(data => data.func == handler);
|
||||
if (index != -1)
|
||||
messageData.removeAt(index);
|
||||
}
|
||||
if (list.contains(handler))
|
||||
console.warn("您试图添加相同的观察者两次");
|
||||
list.push(new FuncPack(handler, context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发该事件
|
||||
* @param eventType 事件类型
|
||||
* @param data 事件数据
|
||||
*/
|
||||
public emit(eventType: T, data?: any){
|
||||
let list: FuncPack[] = this._messageTable.get(eventType);
|
||||
if (list){
|
||||
for (let i = list.length - 1; i >= 0; i --)
|
||||
list[i].func.call(list[i].context, data);
|
||||
/**
|
||||
* 移除监听项
|
||||
* @param eventType 事件类型
|
||||
* @param handler 事件函数
|
||||
*/
|
||||
public removeObserver(eventType: T, handler: Function){
|
||||
let messageData = this._messageTable.get(eventType);
|
||||
let index = messageData.findIndex(data => data.func == handler);
|
||||
if (index != -1)
|
||||
messageData.removeAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发该事件
|
||||
* @param eventType 事件类型
|
||||
* @param data 事件数据
|
||||
*/
|
||||
public emit(eventType: T, data?: any){
|
||||
let list: FuncPack[] = this._messageTable.get(eventType);
|
||||
if (list){
|
||||
for (let i = list.length - 1; i >= 0; i --)
|
||||
list[i].func.call(list[i].context, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于包装事件的一个小类
|
||||
*/
|
||||
class FuncPack {
|
||||
/** 函数 */
|
||||
public func: Function;
|
||||
/** 上下文 */
|
||||
public context: any;
|
||||
|
||||
constructor(func: Function, context: any){
|
||||
this.func = func;
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,48 @@
|
||||
class GlobalManager {
|
||||
public static globalManagers: GlobalManager[] = [];
|
||||
private _enabled: boolean;
|
||||
module es {
|
||||
export class GlobalManager {
|
||||
public static globalManagers: GlobalManager[] = [];
|
||||
private _enabled: boolean;
|
||||
|
||||
public get enabled(){
|
||||
return this._enabled;
|
||||
}
|
||||
public set enabled(value: boolean){
|
||||
this.setEnabled(value);
|
||||
}
|
||||
public setEnabled(isEnabled: boolean){
|
||||
if (this._enabled != isEnabled){
|
||||
this._enabled = isEnabled;
|
||||
if (this._enabled){
|
||||
this.onEnabled();
|
||||
} else {
|
||||
this.onDisabled();
|
||||
public get enabled(){
|
||||
return this._enabled;
|
||||
}
|
||||
public set enabled(value: boolean){
|
||||
this.setEnabled(value);
|
||||
}
|
||||
public setEnabled(isEnabled: boolean){
|
||||
if (this._enabled != isEnabled){
|
||||
this._enabled = isEnabled;
|
||||
if (this._enabled){
|
||||
this.onEnabled();
|
||||
} else {
|
||||
this.onDisabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public onEnabled(){}
|
||||
public onEnabled(){}
|
||||
|
||||
public onDisabled(){}
|
||||
public onDisabled(){}
|
||||
|
||||
public update(){}
|
||||
public update(){}
|
||||
|
||||
public static registerGlobalManager(manager: GlobalManager){
|
||||
this.globalManagers.push(manager);
|
||||
manager.enabled = true;
|
||||
}
|
||||
|
||||
public static unregisterGlobalManager(manager: GlobalManager){
|
||||
this.globalManagers.remove(manager);
|
||||
manager.enabled = false;
|
||||
}
|
||||
|
||||
public static getGlobalManager<T extends GlobalManager>(type){
|
||||
for (let i = 0; i < this.globalManagers.length; i ++){
|
||||
if (this.globalManagers[i] instanceof type)
|
||||
return this.globalManagers[i] as T;
|
||||
public static registerGlobalManager(manager: GlobalManager){
|
||||
this.globalManagers.push(manager);
|
||||
manager.enabled = true;
|
||||
}
|
||||
|
||||
return null;
|
||||
public static unregisterGlobalManager(manager: GlobalManager){
|
||||
this.globalManagers.remove(manager);
|
||||
manager.enabled = false;
|
||||
}
|
||||
|
||||
public static getGlobalManager<T extends GlobalManager>(type){
|
||||
for (let i = 0; i < this.globalManagers.length; i ++){
|
||||
if (this.globalManagers[i] instanceof type)
|
||||
return this.globalManagers[i] as T;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,147 +1,149 @@
|
||||
class TouchState {
|
||||
public x = 0;
|
||||
public y = 0;
|
||||
public touchPoint: number = -1;
|
||||
public touchDown: boolean = false;
|
||||
public get position(){
|
||||
return new Vector2(this.x, this.y);
|
||||
}
|
||||
|
||||
public reset(){
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.touchDown = false;
|
||||
this.touchPoint = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Input {
|
||||
private static _init: boolean = false;
|
||||
private static _stage: egret.Stage;
|
||||
private static _previousTouchState: TouchState = new TouchState();
|
||||
private static _gameTouchs: TouchState[] = [];
|
||||
private static _resolutionOffset: Vector2 = new Vector2();
|
||||
private static _resolutionScale: Vector2 = Vector2.one;
|
||||
private static _touchIndex: number = 0;
|
||||
private static _totalTouchCount: number = 0;
|
||||
/** 返回第一个触摸点的坐标 */
|
||||
public static get touchPosition(){
|
||||
if (!this._gameTouchs[0])
|
||||
return Vector2.zero;
|
||||
return this._gameTouchs[0].position;
|
||||
}
|
||||
/** 获取最大触摸数 */
|
||||
public static get maxSupportedTouch(){
|
||||
return this._stage.maxTouches;
|
||||
}
|
||||
/**
|
||||
* 设置最大触摸数
|
||||
*/
|
||||
public static set maxSupportedTouch(value: number){
|
||||
this._stage.maxTouches = value;
|
||||
this.initTouchCache();
|
||||
}
|
||||
/** 获取缩放值 默认为1 */
|
||||
public static get resolutionScale(){
|
||||
return this._resolutionScale;
|
||||
}
|
||||
/** 当前触摸点数量 */
|
||||
public static get totalTouchCount(){
|
||||
return this._totalTouchCount;
|
||||
}
|
||||
/**
|
||||
* 触摸列表 存放最大个数量触摸点信息
|
||||
* 可通过判断touchPoint是否为-1 来确定是否为有触摸
|
||||
* 通过判断touchDown 判断触摸点是否有按下
|
||||
*/
|
||||
public static get gameTouchs(){
|
||||
return this._gameTouchs;
|
||||
}
|
||||
|
||||
/** 获取第一个触摸点距离上次距离的增量 */
|
||||
public static get touchPositionDelta(){
|
||||
let delta = Vector2.subtract(this.touchPosition, this._previousTouchState.position);
|
||||
if (delta.length() > 0){
|
||||
this.setpreviousTouchState(this._gameTouchs[0]);
|
||||
module es {
|
||||
export class TouchState {
|
||||
public x = 0;
|
||||
public y = 0;
|
||||
public touchPoint: number = -1;
|
||||
public touchDown: boolean = false;
|
||||
public get position(){
|
||||
return new Vector2(this.x, this.y);
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
public static initialize(stage: egret.Stage){
|
||||
if (this._init)
|
||||
return;
|
||||
|
||||
this._init = true;
|
||||
this._stage = stage;
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.touchBegin, this);
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.touchMove, this);
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_END, this.touchEnd, this);
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_CANCEL, this.touchEnd, this);
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_RELEASE_OUTSIDE, this.touchEnd, this);
|
||||
|
||||
this.initTouchCache();
|
||||
}
|
||||
|
||||
private static initTouchCache(){
|
||||
this._totalTouchCount = 0;
|
||||
this._touchIndex = 0;
|
||||
this._gameTouchs.length = 0;
|
||||
for (let i = 0; i < this.maxSupportedTouch; i ++){
|
||||
this._gameTouchs.push(new TouchState());
|
||||
public reset(){
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.touchDown = false;
|
||||
this.touchPoint = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static touchBegin(evt: egret.TouchEvent){
|
||||
if (this._touchIndex < this.maxSupportedTouch){
|
||||
this._gameTouchs[this._touchIndex].touchPoint = evt.touchPointID;
|
||||
this._gameTouchs[this._touchIndex].touchDown = evt.touchDown;
|
||||
this._gameTouchs[this._touchIndex].x = evt.stageX;
|
||||
this._gameTouchs[this._touchIndex].y = evt.stageY;
|
||||
if (this._touchIndex == 0){
|
||||
export class Input {
|
||||
private static _init: boolean = false;
|
||||
private static _stage: egret.Stage;
|
||||
private static _previousTouchState: TouchState = new TouchState();
|
||||
private static _gameTouchs: TouchState[] = [];
|
||||
private static _resolutionOffset: Vector2 = new Vector2();
|
||||
private static _resolutionScale: Vector2 = Vector2.one;
|
||||
private static _touchIndex: number = 0;
|
||||
private static _totalTouchCount: number = 0;
|
||||
/** 返回第一个触摸点的坐标 */
|
||||
public static get touchPosition(){
|
||||
if (!this._gameTouchs[0])
|
||||
return Vector2.zero;
|
||||
return this._gameTouchs[0].position;
|
||||
}
|
||||
/** 获取最大触摸数 */
|
||||
public static get maxSupportedTouch(){
|
||||
return this._stage.maxTouches;
|
||||
}
|
||||
/**
|
||||
* 设置最大触摸数
|
||||
*/
|
||||
public static set maxSupportedTouch(value: number){
|
||||
this._stage.maxTouches = value;
|
||||
this.initTouchCache();
|
||||
}
|
||||
/** 获取缩放值 默认为1 */
|
||||
public static get resolutionScale(){
|
||||
return this._resolutionScale;
|
||||
}
|
||||
/** 当前触摸点数量 */
|
||||
public static get totalTouchCount(){
|
||||
return this._totalTouchCount;
|
||||
}
|
||||
/**
|
||||
* 触摸列表 存放最大个数量触摸点信息
|
||||
* 可通过判断touchPoint是否为-1 来确定是否为有触摸
|
||||
* 通过判断touchDown 判断触摸点是否有按下
|
||||
*/
|
||||
public static get gameTouchs(){
|
||||
return this._gameTouchs;
|
||||
}
|
||||
|
||||
/** 获取第一个触摸点距离上次距离的增量 */
|
||||
public static get touchPositionDelta(){
|
||||
let delta = Vector2.subtract(this.touchPosition, this._previousTouchState.position);
|
||||
if (delta.length() > 0){
|
||||
this.setpreviousTouchState(this._gameTouchs[0]);
|
||||
}
|
||||
this._touchIndex ++;
|
||||
this._totalTouchCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
private static touchMove(evt: egret.TouchEvent){
|
||||
if (evt.touchPointID == this._gameTouchs[0].touchPoint){
|
||||
this.setpreviousTouchState(this._gameTouchs[0]);
|
||||
return delta;
|
||||
}
|
||||
|
||||
let touchIndex = this._gameTouchs.findIndex(touch => touch.touchPoint == evt.touchPointID);
|
||||
if (touchIndex != -1){
|
||||
let touchData = this._gameTouchs[touchIndex];
|
||||
touchData.x = evt.stageX;
|
||||
touchData.y = evt.stageY;
|
||||
}
|
||||
}
|
||||
public static initialize(stage: egret.Stage){
|
||||
if (this._init)
|
||||
return;
|
||||
|
||||
private static touchEnd(evt: egret.TouchEvent){
|
||||
let touchIndex = this._gameTouchs.findIndex(touch => touch.touchPoint == evt.touchPointID);
|
||||
if (touchIndex != -1){
|
||||
let touchData = this._gameTouchs[touchIndex];
|
||||
touchData.reset();
|
||||
if (touchIndex == 0)
|
||||
this._previousTouchState.reset();
|
||||
this._totalTouchCount --;
|
||||
if (this.totalTouchCount == 0){
|
||||
this._touchIndex = 0;
|
||||
this._init = true;
|
||||
this._stage = stage;
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.touchBegin, this);
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.touchMove, this);
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_END, this.touchEnd, this);
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_CANCEL, this.touchEnd, this);
|
||||
this._stage.addEventListener(egret.TouchEvent.TOUCH_RELEASE_OUTSIDE, this.touchEnd, this);
|
||||
|
||||
this.initTouchCache();
|
||||
}
|
||||
|
||||
private static initTouchCache(){
|
||||
this._totalTouchCount = 0;
|
||||
this._touchIndex = 0;
|
||||
this._gameTouchs.length = 0;
|
||||
for (let i = 0; i < this.maxSupportedTouch; i ++){
|
||||
this._gameTouchs.push(new TouchState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static setpreviousTouchState(touchState: TouchState){
|
||||
this._previousTouchState = new TouchState();
|
||||
this._previousTouchState.x = touchState.position.x;
|
||||
this._previousTouchState.y = touchState.position.y;
|
||||
this._previousTouchState.touchPoint = touchState.touchPoint;
|
||||
this._previousTouchState.touchDown = touchState.touchDown;
|
||||
}
|
||||
private static touchBegin(evt: egret.TouchEvent){
|
||||
if (this._touchIndex < this.maxSupportedTouch){
|
||||
this._gameTouchs[this._touchIndex].touchPoint = evt.touchPointID;
|
||||
this._gameTouchs[this._touchIndex].touchDown = evt.touchDown;
|
||||
this._gameTouchs[this._touchIndex].x = evt.stageX;
|
||||
this._gameTouchs[this._touchIndex].y = evt.stageY;
|
||||
if (this._touchIndex == 0){
|
||||
this.setpreviousTouchState(this._gameTouchs[0]);
|
||||
}
|
||||
this._touchIndex ++;
|
||||
this._totalTouchCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
public static scaledPosition(position: Vector2){
|
||||
let scaledPos = new Vector2(position.x - this._resolutionOffset.x, position.y - this._resolutionOffset.y);
|
||||
return Vector2.multiply(scaledPos, this.resolutionScale);
|
||||
private static touchMove(evt: egret.TouchEvent){
|
||||
if (evt.touchPointID == this._gameTouchs[0].touchPoint){
|
||||
this.setpreviousTouchState(this._gameTouchs[0]);
|
||||
}
|
||||
|
||||
let touchIndex = this._gameTouchs.findIndex(touch => touch.touchPoint == evt.touchPointID);
|
||||
if (touchIndex != -1){
|
||||
let touchData = this._gameTouchs[touchIndex];
|
||||
touchData.x = evt.stageX;
|
||||
touchData.y = evt.stageY;
|
||||
}
|
||||
}
|
||||
|
||||
private static touchEnd(evt: egret.TouchEvent){
|
||||
let touchIndex = this._gameTouchs.findIndex(touch => touch.touchPoint == evt.touchPointID);
|
||||
if (touchIndex != -1){
|
||||
let touchData = this._gameTouchs[touchIndex];
|
||||
touchData.reset();
|
||||
if (touchIndex == 0)
|
||||
this._previousTouchState.reset();
|
||||
this._totalTouchCount --;
|
||||
if (this.totalTouchCount == 0){
|
||||
this._touchIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static setpreviousTouchState(touchState: TouchState){
|
||||
this._previousTouchState = new TouchState();
|
||||
this._previousTouchState.x = touchState.position.x;
|
||||
this._previousTouchState.y = touchState.position.y;
|
||||
this._previousTouchState.touchPoint = touchState.touchPoint;
|
||||
this._previousTouchState.touchDown = touchState.touchDown;
|
||||
}
|
||||
|
||||
public static scaledPosition(position: Vector2){
|
||||
let scaledPos = new Vector2(position.x - this._resolutionOffset.x, position.y - this._resolutionOffset.y);
|
||||
return Vector2.multiply(scaledPos, this.resolutionScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,56 @@
|
||||
/**
|
||||
* 可以用于列表池的简单类
|
||||
*/
|
||||
class ListPool {
|
||||
private static readonly _objectQueue = [];
|
||||
|
||||
module es {
|
||||
/**
|
||||
* 预热缓存,使用最大的cacheCount对象填充缓存
|
||||
* @param cacheCount
|
||||
* 可以用于列表池的简单类
|
||||
*/
|
||||
public static warmCache(cacheCount: number){
|
||||
cacheCount -= this._objectQueue.length;
|
||||
if (cacheCount > 0){
|
||||
for (let i = 0; i < cacheCount; i ++){
|
||||
this._objectQueue.unshift([]);
|
||||
export class ListPool {
|
||||
private static readonly _objectQueue = [];
|
||||
|
||||
/**
|
||||
* 预热缓存,使用最大的cacheCount对象填充缓存
|
||||
* @param cacheCount
|
||||
*/
|
||||
public static warmCache(cacheCount: number){
|
||||
cacheCount -= this._objectQueue.length;
|
||||
if (cacheCount > 0){
|
||||
for (let i = 0; i < cacheCount; i ++){
|
||||
this._objectQueue.unshift([]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将缓存修剪为cacheCount项目
|
||||
* @param cacheCount
|
||||
*/
|
||||
public static trimCache(cacheCount){
|
||||
while (cacheCount > this._objectQueue.length)
|
||||
this._objectQueue.shift();
|
||||
}
|
||||
/**
|
||||
* 将缓存修剪为cacheCount项目
|
||||
* @param cacheCount
|
||||
*/
|
||||
public static trimCache(cacheCount){
|
||||
while (cacheCount > this._objectQueue.length)
|
||||
this._objectQueue.shift();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
*/
|
||||
public static clearCache(){
|
||||
this._objectQueue.length = 0;
|
||||
}
|
||||
/**
|
||||
* 清除缓存
|
||||
*/
|
||||
public static clearCache(){
|
||||
this._objectQueue.length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果可以的话,从堆栈中弹出一个项
|
||||
*/
|
||||
public static obtain<T>(): T[] {
|
||||
if (this._objectQueue.length > 0)
|
||||
return this._objectQueue.shift();
|
||||
/**
|
||||
* 如果可以的话,从堆栈中弹出一个项
|
||||
*/
|
||||
public static obtain<T>(): T[] {
|
||||
if (this._objectQueue.length > 0)
|
||||
return this._objectQueue.shift();
|
||||
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 将项推回堆栈
|
||||
* @param obj
|
||||
*/
|
||||
public static free<T>(obj: Array<T>){
|
||||
this._objectQueue.unshift(obj);
|
||||
obj.length = 0;
|
||||
/**
|
||||
* 将项推回堆栈
|
||||
* @param obj
|
||||
*/
|
||||
public static free<T>(obj: Array<T>){
|
||||
this._objectQueue.unshift(obj);
|
||||
obj.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
/**
|
||||
* 用于管理一对对象的简单DTO
|
||||
*/
|
||||
class Pair<T> {
|
||||
public first: T;
|
||||
public second: T;
|
||||
module es {
|
||||
/**
|
||||
* 用于管理一对对象的简单DTO
|
||||
*/
|
||||
export class Pair<T> {
|
||||
public first: T;
|
||||
public second: T;
|
||||
|
||||
constructor(first: T, second: T){
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
constructor(first: T, second: T){
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public clear(){
|
||||
this.first = this.second = null;
|
||||
}
|
||||
public clear(){
|
||||
this.first = this.second = null;
|
||||
}
|
||||
|
||||
public equals(other: Pair<T>){
|
||||
return this.first == other.first && this.second == other.second;
|
||||
public equals(other: Pair<T>){
|
||||
return this.first == other.first && this.second == other.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
class RectangleExt {
|
||||
/**
|
||||
* 计算两个矩形的并集。结果将是一个包含其他两个的矩形。
|
||||
* @param first
|
||||
* @param point
|
||||
*/
|
||||
public static union(first: Rectangle, point: Vector2){
|
||||
let rect = new Rectangle(point.x, point.y, 0, 0);
|
||||
// let rectResult = first.union(rect);
|
||||
let result = new Rectangle();
|
||||
result.x = Math.min(first.x, rect.x);
|
||||
result.y = Math.min(first.y, rect.y);
|
||||
result.width = Math.max(first.right, rect.right) - result.x;
|
||||
result.height = Math.max(first.bottom, result.bottom) - result.y;
|
||||
return result;
|
||||
module es {
|
||||
export class RectangleExt {
|
||||
/**
|
||||
* 计算两个矩形的并集。结果将是一个包含其他两个的矩形。
|
||||
* @param first
|
||||
* @param point
|
||||
*/
|
||||
public static union(first: Rectangle, point: Vector2){
|
||||
let rect = new Rectangle(point.x, point.y, 0, 0);
|
||||
// let rectResult = first.union(rect);
|
||||
let result = new Rectangle();
|
||||
result.x = Math.min(first.x, rect.x);
|
||||
result.y = Math.min(first.y, rect.y);
|
||||
result.width = Math.max(first.right, rect.right) - result.x;
|
||||
result.height = Math.max(first.bottom, result.bottom) - result.y;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,111 +1,113 @@
|
||||
/**
|
||||
* 三角剖分
|
||||
*/
|
||||
class Triangulator {
|
||||
/**
|
||||
* 最后一次三角调用中使用的点列表的三角形列表项的索引
|
||||
*/
|
||||
public triangleIndices: number[] = [];
|
||||
|
||||
private _triPrev: number[] = new Array<number>(12);
|
||||
private _triNext: number[] = new Array<number>(12);
|
||||
|
||||
module es {
|
||||
/**
|
||||
* 计算一个三角形列表,该列表完全覆盖给定点集所包含的区域。如果点不是CCW,则将arePointsCCW参数传递为false
|
||||
* @param points 定义封闭路径的点列表
|
||||
* @param arePointsCCW
|
||||
* 三角剖分
|
||||
*/
|
||||
public triangulate(points: Vector2[], arePointsCCW: boolean = true){
|
||||
let count = points.length;
|
||||
export class Triangulator {
|
||||
/**
|
||||
* 最后一次三角调用中使用的点列表的三角形列表项的索引
|
||||
*/
|
||||
public triangleIndices: number[] = [];
|
||||
|
||||
// 设置前一个链接和下一个链接
|
||||
this.initialize(count);
|
||||
private _triPrev: number[] = new Array<number>(12);
|
||||
private _triNext: number[] = new Array<number>(12);
|
||||
|
||||
// 非三角的多边形断路器
|
||||
let iterations = 0;
|
||||
/**
|
||||
* 计算一个三角形列表,该列表完全覆盖给定点集所包含的区域。如果点不是CCW,则将arePointsCCW参数传递为false
|
||||
* @param points 定义封闭路径的点列表
|
||||
* @param arePointsCCW
|
||||
*/
|
||||
public triangulate(points: Vector2[], arePointsCCW: boolean = true){
|
||||
let count = points.length;
|
||||
|
||||
// 从0开始
|
||||
let index = 0;
|
||||
// 设置前一个链接和下一个链接
|
||||
this.initialize(count);
|
||||
|
||||
// 继续移除所有的三角形,直到只剩下一个三角形
|
||||
while (count > 3 && iterations < 500){
|
||||
iterations ++;
|
||||
// 非三角的多边形断路器
|
||||
let iterations = 0;
|
||||
|
||||
let isEar = true;
|
||||
let a = points[this._triPrev[index]];
|
||||
let b = points[index];
|
||||
let c = points[this._triNext[index]];
|
||||
// 从0开始
|
||||
let index = 0;
|
||||
|
||||
if (Vector2Ext.isTriangleCCW(a, b, c)){
|
||||
let k = this._triNext[this._triNext[index]];
|
||||
do {
|
||||
if (Triangulator.testPointTriangle(points[k], a, b, c)){
|
||||
isEar = false;
|
||||
break;
|
||||
}
|
||||
// 继续移除所有的三角形,直到只剩下一个三角形
|
||||
while (count > 3 && iterations < 500){
|
||||
iterations ++;
|
||||
|
||||
k = this._triNext[k];
|
||||
} while (k != this._triPrev[index]);
|
||||
}else{
|
||||
isEar = false;
|
||||
let isEar = true;
|
||||
let a = points[this._triPrev[index]];
|
||||
let b = points[index];
|
||||
let c = points[this._triNext[index]];
|
||||
|
||||
if (Vector2Ext.isTriangleCCW(a, b, c)){
|
||||
let k = this._triNext[this._triNext[index]];
|
||||
do {
|
||||
if (Triangulator.testPointTriangle(points[k], a, b, c)){
|
||||
isEar = false;
|
||||
break;
|
||||
}
|
||||
|
||||
k = this._triNext[k];
|
||||
} while (k != this._triPrev[index]);
|
||||
}else{
|
||||
isEar = false;
|
||||
}
|
||||
|
||||
if (isEar){
|
||||
this.triangleIndices.push(this._triPrev[index]);
|
||||
this.triangleIndices.push(index);
|
||||
this.triangleIndices.push(this._triNext[index]);
|
||||
|
||||
// 删除vert通过重定向相邻vert的上一个和下一个链接,从而减少vertext计数
|
||||
this._triNext[this._triPrev[index]] = this._triNext[index];
|
||||
this._triPrev[this._triNext[index]] = this._triPrev[index];
|
||||
count --;
|
||||
|
||||
// 接下来访问前一个vert
|
||||
index = this._triPrev[index];
|
||||
}else{
|
||||
index = this._triNext[index];
|
||||
}
|
||||
}
|
||||
|
||||
if (isEar){
|
||||
this.triangleIndices.push(this._triPrev[index]);
|
||||
this.triangleIndices.push(index);
|
||||
this.triangleIndices.push(this._triNext[index]);
|
||||
this.triangleIndices.push(this._triPrev[index]);
|
||||
this.triangleIndices.push(index);
|
||||
this.triangleIndices.push(this._triNext[index]);
|
||||
|
||||
// 删除vert通过重定向相邻vert的上一个和下一个链接,从而减少vertext计数
|
||||
this._triNext[this._triPrev[index]] = this._triNext[index];
|
||||
this._triPrev[this._triNext[index]] = this._triPrev[index];
|
||||
count --;
|
||||
if (!arePointsCCW)
|
||||
this.triangleIndices.reverse();
|
||||
}
|
||||
|
||||
// 接下来访问前一个vert
|
||||
index = this._triPrev[index];
|
||||
}else{
|
||||
index = this._triNext[index];
|
||||
private initialize(count: number){
|
||||
this.triangleIndices.length = 0;
|
||||
|
||||
if (this._triNext.length < count){
|
||||
this._triNext.reverse();
|
||||
this._triNext = new Array<number>(Math.max(this._triNext.length * 2, count));
|
||||
}
|
||||
if (this._triPrev.length < count){
|
||||
this._triPrev.reverse();
|
||||
this._triPrev = new Array<number>(Math.max(this._triPrev.length * 2, count));
|
||||
}
|
||||
|
||||
for (let i = 0; i < count;i ++){
|
||||
this._triPrev[i] = i - 1;
|
||||
this._triNext[i] = i + 1;
|
||||
}
|
||||
|
||||
this._triPrev[0] = count - 1;
|
||||
this._triNext[count - 1] = 0;
|
||||
}
|
||||
|
||||
this.triangleIndices.push(this._triPrev[index]);
|
||||
this.triangleIndices.push(index);
|
||||
this.triangleIndices.push(this._triNext[index]);
|
||||
public static testPointTriangle(point: Vector2, a: Vector2, b: Vector2, c: Vector2): boolean{
|
||||
if (Vector2Ext.cross(Vector2.subtract(point, a), Vector2.subtract(b, a)) < 0)
|
||||
return false;
|
||||
|
||||
if (!arePointsCCW)
|
||||
this.triangleIndices.reverse();
|
||||
}
|
||||
if (Vector2Ext.cross(Vector2.subtract(point, b), Vector2.subtract(c, b)) < 0)
|
||||
return false;
|
||||
|
||||
private initialize(count: number){
|
||||
this.triangleIndices.length = 0;
|
||||
if (Vector2Ext.cross(Vector2.subtract(point, c), Vector2.subtract(a, c)) < 0)
|
||||
return false;
|
||||
|
||||
if (this._triNext.length < count){
|
||||
this._triNext.reverse();
|
||||
this._triNext = new Array<number>(Math.max(this._triNext.length * 2, count));
|
||||
}
|
||||
if (this._triPrev.length < count){
|
||||
this._triPrev.reverse();
|
||||
this._triPrev = new Array<number>(Math.max(this._triPrev.length * 2, count));
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let i = 0; i < count;i ++){
|
||||
this._triPrev[i] = i - 1;
|
||||
this._triNext[i] = i + 1;
|
||||
}
|
||||
|
||||
this._triPrev[0] = count - 1;
|
||||
this._triNext[count - 1] = 0;
|
||||
}
|
||||
|
||||
public static testPointTriangle(point: Vector2, a: Vector2, b: Vector2, c: Vector2): boolean{
|
||||
if (Vector2Ext.cross(Vector2.subtract(point, a), Vector2.subtract(b, a)) < 0)
|
||||
return false;
|
||||
|
||||
if (Vector2Ext.cross(Vector2.subtract(point, b), Vector2.subtract(c, b)) < 0)
|
||||
return false;
|
||||
|
||||
if (Vector2Ext.cross(Vector2.subtract(point, c), Vector2.subtract(a, c)) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +1,60 @@
|
||||
class Vector2Ext {
|
||||
/**
|
||||
* 检查三角形是CCW还是CW
|
||||
* @param a
|
||||
* @param center
|
||||
* @param c
|
||||
*/
|
||||
public static isTriangleCCW(a: Vector2, center: Vector2, c: Vector2) {
|
||||
return this.cross(Vector2.subtract(center, a), Vector2.subtract(c, center)) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算二维伪叉乘点(Perp(u), v)
|
||||
* @param u
|
||||
* @param v
|
||||
*/
|
||||
public static cross(u: Vector2, v: Vector2) {
|
||||
return u.y * v.x - u.x * v.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回与传入向量垂直的向量
|
||||
* @param first
|
||||
* @param second
|
||||
*/
|
||||
public static perpendicular(first: Vector2, second: Vector2) {
|
||||
return new Vector2(-1 * (second.y - first.y), second.x - first.x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vector2的临时解决方案
|
||||
* 标准化把向量弄乱了
|
||||
* @param vec
|
||||
*/
|
||||
public static normalize(vec: Vector2) {
|
||||
let magnitude = Math.sqrt((vec.x * vec.x) + (vec.y * vec.y));
|
||||
if (magnitude > MathHelper.Epsilon) {
|
||||
vec = Vector2.divide(vec, new Vector2(magnitude));
|
||||
} else {
|
||||
vec.x = vec.y = 0;
|
||||
module es {
|
||||
export class Vector2Ext {
|
||||
/**
|
||||
* 检查三角形是CCW还是CW
|
||||
* @param a
|
||||
* @param center
|
||||
* @param c
|
||||
*/
|
||||
public static isTriangleCCW(a: Vector2, center: Vector2, c: Vector2) {
|
||||
return this.cross(Vector2.subtract(center, a), Vector2.subtract(c, center)) < 0;
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
/**
|
||||
* 计算二维伪叉乘点(Perp(u), v)
|
||||
* @param u
|
||||
* @param v
|
||||
*/
|
||||
public static cross(u: Vector2, v: Vector2) {
|
||||
return u.y * v.x - u.x * v.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过指定的矩阵对Vector2的数组中的向量应用变换,并将结果放置在另一个数组中。
|
||||
* @param sourceArray
|
||||
* @param sourceIndex
|
||||
* @param matrix
|
||||
* @param destinationArray
|
||||
* @param destinationIndex
|
||||
* @param length
|
||||
*/
|
||||
public static transformA(sourceArray: Vector2[], sourceIndex: number, matrix: Matrix2D,
|
||||
destinationArray: Vector2[], destinationIndex: number, length: number) {
|
||||
/**
|
||||
* 返回与传入向量垂直的向量
|
||||
* @param first
|
||||
* @param second
|
||||
*/
|
||||
public static perpendicular(first: Vector2, second: Vector2) {
|
||||
return new Vector2(-1 * (second.y - first.y), second.x - first.x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vector2的临时解决方案
|
||||
* 标准化把向量弄乱了
|
||||
* @param vec
|
||||
*/
|
||||
public static normalize(vec: Vector2) {
|
||||
let magnitude = Math.sqrt((vec.x * vec.x) + (vec.y * vec.y));
|
||||
if (magnitude > MathHelper.Epsilon) {
|
||||
vec = Vector2.divide(vec, new Vector2(magnitude));
|
||||
} else {
|
||||
vec.x = vec.y = 0;
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过指定的矩阵对Vector2的数组中的向量应用变换,并将结果放置在另一个数组中。
|
||||
* @param sourceArray
|
||||
* @param sourceIndex
|
||||
* @param matrix
|
||||
* @param destinationArray
|
||||
* @param destinationIndex
|
||||
* @param length
|
||||
*/
|
||||
public static transformA(sourceArray: Vector2[], sourceIndex: number, matrix: Matrix2D,
|
||||
destinationArray: Vector2[], destinationIndex: number, length: number) {
|
||||
for (let i = 0; i < length; i ++){
|
||||
let position = sourceArray[sourceIndex + i];
|
||||
let destination = destinationArray[destinationIndex + i];
|
||||
@@ -61,25 +62,26 @@ class Vector2Ext {
|
||||
destination.y = (position.x * matrix.m12) + (position.y * matrix.m22) + matrix.m32;
|
||||
destinationArray[destinationIndex + i] = destination;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static transformR(position: Vector2, matrix: Matrix2D){
|
||||
let x = (position.x * matrix.m11) + (position.y * matrix.m21) + matrix.m31;
|
||||
let y = (position.x * matrix.m12) + (position.y * matrix.m22) + matrix.m32;
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
public static transformR(position: Vector2, matrix: Matrix2D){
|
||||
let x = (position.x * matrix.m11) + (position.y * matrix.m21) + matrix.m31;
|
||||
let y = (position.x * matrix.m12) + (position.y * matrix.m22) + matrix.m32;
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过指定的矩阵对Vector2的数组中的所有向量应用变换,并将结果放到另一个数组中。
|
||||
* @param sourceArray
|
||||
* @param matrix
|
||||
* @param destinationArray
|
||||
*/
|
||||
public static transform(sourceArray: Vector2[], matrix: Matrix2D, destinationArray: Vector2[]) {
|
||||
this.transformA(sourceArray, 0, matrix, destinationArray, 0, sourceArray.length);
|
||||
}
|
||||
/**
|
||||
* 通过指定的矩阵对Vector2的数组中的所有向量应用变换,并将结果放到另一个数组中。
|
||||
* @param sourceArray
|
||||
* @param matrix
|
||||
* @param destinationArray
|
||||
*/
|
||||
public static transform(sourceArray: Vector2[], matrix: Matrix2D, destinationArray: Vector2[]) {
|
||||
this.transformA(sourceArray, 0, matrix, destinationArray, 0, sourceArray.length);
|
||||
}
|
||||
|
||||
public static round(vec: Vector2){
|
||||
return new Vector2(Math.round(vec.x), Math.round(vec.y));
|
||||
public static round(vec: Vector2){
|
||||
return new Vector2(Math.round(vec.x), Math.round(vec.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user