main/GameEngine.js
import { GameState } from 'GameState';
import { GameObject } from 'model/core/GameObject';
import { Message } from 'model/core/Message';
import { Graphic } from 'model/component/Graphic';
import { Sprite } from 'model/component/Sprite';
import { Canvas } from 'model/component/Canvas';
import { Body } from 'model/component/Body';
import { Audio } from 'model/component/Audio';
import { RenderService } from 'service/RenderService';
import { PhysicsService } from 'service/PhysicsService';
import { MessageService } from 'service/MessageService';
import { AudioService } from 'service/AudioService';
import { BrowserHandler } from 'handler/BrowserHandler';
import { KeyboardHandler } from 'handler/KeyboardHandler';
import { MouseHandler } from 'handler/MouseHandler';
import { Logger } from 'commons/Logger';
var _frameCounter = 0;
var _lastCycleTime = 0;
var _lastFrameCountTime = 0;
export class GameEngine {
constructor(container, width, height) {
this._logger = new Logger(GameEngine.name);
this._renderService = new RenderService(width, height, container.offsetWidth, container.offsetHeight);
this._physicsService = new PhysicsService({ x: 0, y: 10 }, true, PhysicsService.LISTENER.BEGIN_END_CONTACT);
this._messageService = new MessageService();
this._audioService = new AudioService();
container.appendChild(this._renderService.domElement);
this.browserHandler = new BrowserHandler(container);
this.keyboardHandler = new KeyboardHandler();
this.mouseHandler = new MouseHandler(this._renderService.domElement);
}
run() {
var now = Date.now();
_frameCounter++;
GameState.time += now - _lastCycleTime;
_lastCycleTime = now;
if (_lastFrameCountTime === 0) {
_lastFrameCountTime = GameState.time;
}
if ((GameState.time - _lastFrameCountTime) >= 1000) {
GameState.fps = _frameCounter;
_frameCounter = 0;
_lastFrameCountTime = GameState.time;
}
this._update(GameState.world);
if (GameState.loaded) {
this._physicsService.events.forEach(event => {
var goA = GameState.world.findChild(event.contact.GetFixtureA().GetUserData());
var goB = GameState.world.findChild(event.contact.GetFixtureB().GetUserData());
this._messageService.messages.push(new Message(goA, goB, new Date(), Message.TYPE.PHYSICS, event));
this._messageService.messages.push(new Message(goB, goA, new Date(), Message.TYPE.PHYSICS, event));
});
this._physicsService.simulate(GameState.fps);
this._renderService.render();
} else {
var resources = this._countResources(GameState.world);
if (resources > 0) {
var loadedResources = this._countLoadedResources(GameState.world);
var percentage = loadedResources ? (loadedResources / resources) : 0;
this._logger.info("loading: " + Math.round(percentage * 100) + "% (" + loadedResources + "/" + resources + ")");
GameState.loaded = percentage >= 1;
} else {
GameState.loaded = true;
}
}
requestAnimationFrame(this.run.bind(this));
}
_update(go) {
go.children.forEach(child => this._update(child));
go.components.forEach(component => {
if (component instanceof Graphic) {
this._renderService.update(component, go.position, go.rotation, go.scale);
} else if (component instanceof Body) {
this._physicsService.update(component, go);
} else if (component instanceof Audio) {
this._audioService.update(component);
}
});
if (GameState.loaded) {
this._messageService.update(go);
go.update();
}
}
_countResources(go) {
return go.components.reduce((acc, comp) => {
return (comp instanceof Sprite || comp instanceof Audio) ? acc + 1 : acc;
}, go.children.reduce((acc, child) => { return acc + this._countResources(child) }, 0));
}
_countLoadedResources(go) {
return go.components.reduce((acc, comp) => {
return (comp.loaded) ? acc + 1 : acc;
}, go.children.reduce((acc, child) => { return acc + this._countLoadedResources(child) }, 0));
}
}