修复Vector2.zero引起的引用混乱问题

This commit is contained in:
yhh
2020-08-26 19:56:48 +08:00
parent 1997b3f348
commit e81f98ff17
33 changed files with 1663 additions and 4645 deletions

View File

@@ -25,8 +25,6 @@ module es {
public enabled: true;
/** 获取/设置日志显示或否 */
public showLog = false;
private _frameKey = 'frame';
private _logKey = 'log';
/** 每帧的日志 */
private _logs: FrameLog[];
/** 当前显示帧计数 */
@@ -85,108 +83,101 @@ module es {
*/
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;
if (isNaN(this._updateCount))
this._updateCount = 0;
let count = this._updateCount;
count += 1;
if (this.enabled && (1 < count && count < TimeRuler.maxSampleFrames))
return;
// 更新当前帧日志。
this._prevLog = this._logs[this.frameCount++ & 0x1];
this._curLog = this._logs[this.frameCount & 0x1];
// 更新当前帧日志。
this._prevLog = this._logs[this.frameCount++ & 0x1];
this._curLog = this._logs[this.frameCount & 0x1];
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];
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 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;
}
// 更新日志标记
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];
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;
// 重新打开在前一帧中没有调用结束标记的标记。
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;
}
this.stopwacth.reset();
this.stopwacth.start();
});
// 更新日志标记
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];
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;
}
this.stopwacth.reset();
this.stopwacth.start();
}
/**
* 开始测量时间。
* @param markerName
* @param color
* @param barIndex
*/
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 (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");
}
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");
}
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);
}
// 获取注册的标记
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;
});
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;
}
/**
@@ -195,28 +186,25 @@ module es {
* @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");
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 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 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).");
}
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.markers[markerIdx].endTime = this.stopwacth.getTime();
}
/**
@@ -241,31 +229,23 @@ module es {
*
*/
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.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].min = 0;
markerInfo.logs[i].max = 0;
markerInfo.logs[i].avg = 0;
markerInfo.logs[i].samples = 0;
}
});
markerInfo.logs[i].samples = 0;
}
});
}
public render(position: Vector2 = this._position, width: number = this.width) {
egret.localStorage.setItem(this._frameKey, "0");
if (!this.showLog)
return;

View File

@@ -1,55 +0,0 @@
const THREAD_ID = `${Math.floor(Math.random() * 1000)}-${Date.now()}`;
const nextTick = fn => {
setTimeout(fn, 0);
};
/**
* 利用共享区域实现快速锁
*/
class LockUtils {
private _keyX: string;
private _keyY: string;
private setItem;
private getItem;
private removeItem;
constructor(key) {
this._keyX = `mutex_key_${key}_X`;
this._keyY = `mutex_key_${key}_Y`;
this.setItem = egret.localStorage.setItem.bind(localStorage);
this.getItem = egret.localStorage.getItem.bind(localStorage);
this.removeItem = egret.localStorage.removeItem.bind(localStorage);
}
public lock() {
return new Promise((resolve, reject) => {
const fn = () => {
this.setItem(this._keyX, THREAD_ID);
if (!this.getItem(this._keyY) === null) {
// restart
nextTick(fn);
}
this.setItem(this._keyY, THREAD_ID);
if (this.getItem(this._keyX) !== THREAD_ID) {
// delay
setTimeout(() => {
if (this.getItem(this._keyY) !== THREAD_ID) {
// restart
nextTick(fn);
return;
}
// critical section
resolve();
this.removeItem(this._keyY);
}, 10);
} else {
resolve();
this.removeItem(this._keyY);
}
};
fn();
});
}
}

View File

@@ -0,0 +1,20 @@
module es {
export interface ITimer {
context: any;
/**
* 调用stop以停止此计时器再次运行。这对非重复计时器没有影响。
*/
stop();
/**
* 将计时器的运行时间重置为0
*/
reset();
/**
*
*/
getContext<T>(): T;
}
}

View File

@@ -0,0 +1,52 @@
module es {
export class Timer implements ITimer{
public context: any;
public _timeInSeconds: number = 0;
public _repeats: boolean = false;
public _onTime: (timer: ITimer) => void;
public _isDone: boolean = false;
public _elapsedTime: number = 0;
public getContext<T>(): T {
return this.context as T;
}
public reset() {
this._elapsedTime = 0;
}
public stop() {
this._isDone = true;
}
public tick(){
// 如果stop在tick之前被调用那么isDone将为true我们不应该再做任何事情
if (!this._isDone && this._elapsedTime > this._timeInSeconds){
this._elapsedTime -= this._timeInSeconds;
this._onTime(this);
if (!this._isDone && !this._repeats)
this._isDone = true;
}
this._elapsedTime += Time.deltaTime;
return this._isDone;
}
public initialize(timeInsSeconds: number, repeats: boolean, context: any, onTime: (timer: ITimer)=>void){
this._timeInSeconds = timeInsSeconds;
this._repeats = repeats;
this.context = context;
this._onTime = onTime;
}
/**
* 空出对象引用以便在js需要时GC可以清理它们的引用
*/
public unload(){
this.context = null;
this._onTime = null;
}
}
}

View File

@@ -0,0 +1,32 @@
module es {
/**
* 允许动作的延迟和重复执行
*/
export class TimerManager extends GlobalManager {
public _timers: Timer[] = [];
public update() {
for (let i = this._timers.length - 1; i >= 0; i --){
if (this._timers[i].tick()){
this._timers[i].unload();
this._timers.removeAt(i);
}
}
}
/**
* 调度一个一次性或重复的计时器,该计时器将调用已传递的动作
* @param timeInSeconds
* @param repeats
* @param context
* @param onTime
*/
public schedule(timeInSeconds: number, repeats: boolean, context: any, onTime: (timer: ITimer)=>void){
let timer = new Timer();
timer.initialize(timeInSeconds, repeats, context, onTime);
this._timers.push(timer);
return timer;
}
}
}