fixed fps tracking in game loop
This commit is contained in:
parent
d9a87b2727
commit
15dd74f45e
|
@ -32,7 +32,7 @@ export default class BoidDemo extends Scene {
|
|||
this.viewport.enableZoom();
|
||||
|
||||
// Create a bunch of boids
|
||||
for(let i = 0; i < 100; i++){
|
||||
for(let i = 0; i < 200; i++){
|
||||
let boid = this.add.graphic(Boid, layer, new Vec2(this.worldSize.x*Math.random(), this.worldSize.y*Math.random()));
|
||||
boid.fb = new FlockBehavior(this, boid, this.boids, 75, 50);
|
||||
boid.setSize(5, 5);
|
||||
|
|
|
@ -45,12 +45,25 @@ export default class QuadTree<T extends Region & Unique> implements Collection {
|
|||
this.capacity = capacity ? capacity : 10;
|
||||
|
||||
// If we're at the bottom of the tree, don't set a max size
|
||||
if(this.maxDepth === 0){
|
||||
if(this.maxDepth === 1){
|
||||
this.capacity = Infinity;
|
||||
}
|
||||
|
||||
this.divided = false;
|
||||
this.items = new Array();
|
||||
|
||||
// Create all of the children for this quadtree if there are any
|
||||
if(this.maxDepth > 1){
|
||||
let x = this.boundary.x;
|
||||
let y = this.boundary.y;
|
||||
let hw = this.boundary.hw;
|
||||
let hh = this.boundary.hh;
|
||||
|
||||
this.nw = new QuadTree(new Vec2(x-hw/2, y-hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity);
|
||||
this.ne = new QuadTree(new Vec2(x+hw/2, y-hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity);
|
||||
this.sw = new QuadTree(new Vec2(x-hw/2, y+hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity);
|
||||
this.se = new QuadTree(new Vec2(x+hw/2, y+hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,7 +84,6 @@ export default class QuadTree<T extends Region & Unique> implements Collection {
|
|||
// We aren't divided, but are at capacity - divide
|
||||
this.subdivide();
|
||||
this.deferInsert(item);
|
||||
this.divided = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,16 +185,7 @@ export default class QuadTree<T extends Region & Unique> implements Collection {
|
|||
* Divides this quadtree up into 4 smaller ones - called through insert.
|
||||
*/
|
||||
protected subdivide(): void {
|
||||
let x = this.boundary.x;
|
||||
let y = this.boundary.y;
|
||||
let hw = this.boundary.hw;
|
||||
let hh = this.boundary.hh;
|
||||
|
||||
this.nw = new QuadTree(new Vec2(x-hw/2, y-hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity);
|
||||
this.ne = new QuadTree(new Vec2(x+hw/2, y-hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity);
|
||||
this.sw = new QuadTree(new Vec2(x-hw/2, y+hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity);
|
||||
this.se = new QuadTree(new Vec2(x+hw/2, y+hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity);
|
||||
|
||||
this.divided = true;
|
||||
this.distributeItems();
|
||||
}
|
||||
|
||||
|
@ -239,11 +242,16 @@ export default class QuadTree<T extends Region & Unique> implements Collection {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the items in this quadtree
|
||||
*/
|
||||
clear(): void {
|
||||
delete this.nw;
|
||||
delete this.ne;
|
||||
delete this.sw;
|
||||
delete this.se;
|
||||
if(this.nw){
|
||||
this.nw.clear();
|
||||
this.ne.clear();
|
||||
this.sw.clear();
|
||||
this.se.clear();
|
||||
}
|
||||
|
||||
for(let item in this.items){
|
||||
delete this.items[item];
|
||||
|
|
|
@ -9,26 +9,46 @@ import SceneManager from "../Scene/SceneManager";
|
|||
import AudioManager from "../Sound/AudioManager";
|
||||
|
||||
export default class GameLoop {
|
||||
// The amount of time to spend on a physics step
|
||||
private maxFPS: number;
|
||||
/** The max allowed update fps.*/
|
||||
private maxUpdateFPS: number;
|
||||
|
||||
/** The timestep for each update. This is the deltaT passed to update calls. */
|
||||
private simulationTimestep: number;
|
||||
|
||||
// The time when the last frame was drawn
|
||||
private lastFrameTime: number;
|
||||
/** The amount of time we are yet to simulate. */
|
||||
private frameDelta: number;
|
||||
|
||||
// The current frame of the game
|
||||
/** The time when the last frame was drawn. */
|
||||
private lastFrameTime: number;
|
||||
|
||||
/** The minimum time we want to wait between game frames. */
|
||||
private minFrameDelay: number;
|
||||
|
||||
/** The current frame of the game. */
|
||||
private frame: number;
|
||||
|
||||
// Keeping track of the fps
|
||||
private runningFrameSum: number;
|
||||
private numFramesInSum: number;
|
||||
private maxFramesInSum: number;
|
||||
private fps: number;
|
||||
/** The actual fps of the game. */
|
||||
private fps: number;
|
||||
|
||||
/** The time between fps measurement updates. */
|
||||
private fpsUpdateInterval: number;
|
||||
|
||||
private started: boolean;
|
||||
private running: boolean;
|
||||
private frameDelta: number;
|
||||
/** The time of the last fps update. */
|
||||
private lastFpsUpdate: number;
|
||||
|
||||
/** The number of frames since the last fps update was done. */
|
||||
private framesSinceLastFpsUpdate: number;
|
||||
|
||||
/** The status of whether or not the game loop has started. */
|
||||
private started: boolean;
|
||||
|
||||
/** The status of whether or not the game loop is currently running. */
|
||||
private running: boolean;
|
||||
|
||||
/** The panic state of the game. True if we have too many update frames in a single render. */
|
||||
private panic: boolean;
|
||||
|
||||
/** The number of update steps this iteration of the game loop. */
|
||||
private numUpdateSteps: number;
|
||||
|
||||
// Game canvas and its width and height
|
||||
|
@ -51,16 +71,23 @@ export default class GameLoop {
|
|||
// Typecast the config object to a GameConfig object
|
||||
let gameConfig = config ? <GameConfig>config : new GameConfig();
|
||||
|
||||
this.maxFPS = 60;
|
||||
this.simulationTimestep = Math.floor(1000/this.maxFPS);
|
||||
this.maxUpdateFPS = 60;
|
||||
this.simulationTimestep = Math.floor(1000/this.maxUpdateFPS);
|
||||
this.frameDelta = 0;
|
||||
this.lastFrameTime = 0;
|
||||
this.minFrameDelay = 0;
|
||||
this.frame = 0;
|
||||
this.runningFrameSum = 0;
|
||||
this.numFramesInSum = 0;
|
||||
this.maxFramesInSum = 30;
|
||||
this.fps = this.maxFPS;
|
||||
|
||||
this.fps = this.maxUpdateFPS; // Initialize the fps to the max allowed fps
|
||||
this.fpsUpdateInterval = 1000;
|
||||
this.lastFpsUpdate = 0;
|
||||
this.framesSinceLastFpsUpdate = 0;
|
||||
this.started = false;
|
||||
this.running = false;
|
||||
this.panic = false;
|
||||
this.numUpdateSteps = 0;
|
||||
|
||||
// Set the max fps to 60fps
|
||||
// this.setMaxFPS(60);
|
||||
|
||||
// Get the game canvas and give it a background color
|
||||
this.GAME_CANVAS = <HTMLCanvasElement>document.getElementById("game-canvas");
|
||||
|
@ -103,9 +130,13 @@ export default class GameLoop {
|
|||
* Changes the maximum allowed physics framerate of the game
|
||||
* @param initMax
|
||||
*/
|
||||
setMaxFPS(initMax: number): void {
|
||||
this.maxFPS = initMax;
|
||||
this.simulationTimestep = Math.floor(1000/this.maxFPS);
|
||||
setMaxUpdateFPS(initMax: number): void {
|
||||
this.maxUpdateFPS = initMax;
|
||||
this.simulationTimestep = Math.floor(1000/this.maxUpdateFPS);
|
||||
}
|
||||
|
||||
setMaxFPS(maxFPS: number): void {
|
||||
this.minFrameDelay = 1000/maxFPS;
|
||||
}
|
||||
|
||||
getSceneManager(): SceneManager {
|
||||
|
@ -116,15 +147,10 @@ export default class GameLoop {
|
|||
* Updates the frame count and sum of time for the framerate of the game
|
||||
* @param timestep
|
||||
*/
|
||||
private updateFrameCount(timestep: number): void {
|
||||
this.frame += 1;
|
||||
this.numFramesInSum += 1;
|
||||
this.runningFrameSum += timestep;
|
||||
if(this.numFramesInSum >= this.maxFramesInSum){
|
||||
this.fps = 1000 * this.numFramesInSum / this.runningFrameSum;
|
||||
this.numFramesInSum = 0;
|
||||
this.runningFrameSum = 0;
|
||||
}
|
||||
private updateFPS(timestamp: number): void {
|
||||
this.fps = 0.9 * this.framesSinceLastFpsUpdate * 1000 / (timestamp - this.lastFpsUpdate) +(1 - 0.9) * this.fps;
|
||||
this.lastFpsUpdate = timestamp;
|
||||
this.framesSinceLastFpsUpdate = 0;
|
||||
|
||||
Debug.log("fps", "FPS: " + this.fps.toFixed(1));
|
||||
}
|
||||
|
@ -150,6 +176,8 @@ export default class GameLoop {
|
|||
this.render();
|
||||
|
||||
this.lastFrameTime = timestamp;
|
||||
this.lastFpsUpdate = timestamp;
|
||||
this.framesSinceLastFpsUpdate = 0;
|
||||
|
||||
window.requestAnimationFrame(this.doFrame);
|
||||
}
|
||||
|
@ -163,14 +191,22 @@ export default class GameLoop {
|
|||
window.requestAnimationFrame(this.doFrame);
|
||||
|
||||
// If we are trying to update too soon, return and do nothing
|
||||
if(timestamp < this.lastFrameTime + this.simulationTimestep){
|
||||
if(timestamp < this.lastFrameTime + this.minFrameDelay){
|
||||
return
|
||||
}
|
||||
|
||||
// Currently, update and draw are synced - eventually it would probably be good to desync these
|
||||
this.frameDelta = timestamp - this.lastFrameTime;
|
||||
this.frameDelta += timestamp - this.lastFrameTime;
|
||||
this.lastFrameTime = timestamp;
|
||||
|
||||
// Update the estimate of the framerate
|
||||
if(timestamp > this.lastFpsUpdate + this.fpsUpdateInterval){
|
||||
this.updateFPS(timestamp);
|
||||
}
|
||||
|
||||
this.frame++;
|
||||
this.framesSinceLastFpsUpdate++;
|
||||
|
||||
// Update while we can (This will present problems if we leave the window)
|
||||
this.numUpdateSteps = 0;
|
||||
while(this.frameDelta >= this.simulationTimestep){
|
||||
|
@ -181,9 +217,6 @@ export default class GameLoop {
|
|||
if(this.numUpdateSteps > 100){
|
||||
this.panic = true;
|
||||
}
|
||||
|
||||
// Update the frame of the game
|
||||
this.updateFrameCount(this.simulationTimestep);
|
||||
}
|
||||
|
||||
// Updates are done, draw
|
||||
|
|
|
@ -95,7 +95,7 @@ export default class MainScene extends Scene {
|
|||
let i = 0;
|
||||
let fps = [15, 30, 60];
|
||||
cycleFramerateButton.onClick = () => {
|
||||
this.game.setMaxFPS(fps[i]);
|
||||
this.game.setMaxUpdateFPS(fps[i]);
|
||||
i = (i + 1) % 3;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ export default class SecondScene extends Scene {
|
|||
let i = 0;
|
||||
let fps = [15, 30, 60];
|
||||
cycleFramerateButton.onClick = () => {
|
||||
this.game.setMaxFPS(fps[i]);
|
||||
this.game.setMaxUpdateFPS(fps[i]);
|
||||
i = (i + 1) % 3;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user