333 lines
8.7 KiB
JavaScript

"use strict";
import Entity from "./entity.js";
import Vector2D from "./vector2d.js";
import KeyboardInput from "./keyboardinput.js";
import GamepadInput from "./gamepadinput.js";
class Game extends Entity {
constructor (config) {
super(); // Call entity constructor
config = config || {};
config.fullscreen = config.fullscreen || {};
config.inputs = config.inputs || {};
// Required params
if (config.canvas) {
this.canvas = config.canvas;
} else {
throw new Error("MomentumEngine.Classes.Game must be constructed with a canvas");
}
if (config.width) {
this.width = config.width;
} else {
throw new Error("MomentumEngine.Classes.Game must be constructed with canvas width");
}
if (config.height) {
this.height = config.height;
} else {
throw new Error("MomentumEngine.Classes.Game must be constructed with canvas height");
}
this.scale = 1;
// Optional params
this.desiredFps = config.desiredFps || 60;
this.fixFrameRate = !!config.fixFrameRate;
this.fullScreenNativeResolution = !!config.fullscreen.nativeResolution;
if (config.fixRatio) {
let deviceRatio = window.devicePixelRatio,
backingStoreRatio = 0;
// Unfortunately Ejecta requires calling getContext last, so we cannot get the backingStorePixelRatio. So for Ejecta's case, we set it to 1, and call getContext later.
if (typeof ejecta !== "undefined") {
backingStoreRatio = 1;
} else {
this.context = this.canvas.getContext("2d");
backingStoreRatio = this.context.webkitBackingStorePixelRatio ||
this.context.mozBackingStorePixelRatio ||
this.context.msBackingStorePixelRatio ||
this.context.oBackingStorePixelRatio ||
this.context.backingStorePixelRatio || 1;
}
this.scale = deviceRatio / backingStoreRatio;
this._deviceRatio = deviceRatio;
this.canvas.width = this.width * this.scale;
this.canvas.height = this.height * this.scale;
this.canvas.style.width = `${this.width}px`;
this.canvas.style.height = `${this.height}px`;
// Calculate fullscreen settings
if (config.fullscreen.nativeResolution) {
this._fullScreenXScaling = screen.width / this.width;
this._fullScreenYScaling = screen.height / this.height;
} else {
this._fullScreenXScaling = 1;
this._fullScreenYScaling = 1;
}
this._fullScreenXPos = 0;
this._fullScreenYPos = 0;
if (config.fullscreen.maintainAspectRatio) {
if (this._fullScreenXScaling > this._fullScreenYScaling) {
this._fullScreenXScaling = this._fullScreenYScaling;
this._fullScreenXPos = (screen.width - (this.width * this._fullScreenXScaling)) / 2;
} else {
this._fullScreenYScaling = this._fullScreenXScaling;
this._fullScreenYPos = (screen.height - (this.height * this._fullScreenYScaling)) / 2;
}
}
console.log(this._fullScreenXScaling);
console.log(this._fullScreenYScaling);
console.log(this._fullScreenXPos);
console.log(this._fullScreenYPos);
// Call getContext last for Ejecta only.
if (typeof ejecta !== "undefined") {
this.context = this.canvas.getContext("2d");
}
this.context.scale(this._deviceRatio, this._deviceRatio);
} else {
this.canvas.width = this.width;
this.canvas.height = this.height;
this.context = this.canvas.getContext("2d");
}
if (typeof this.context.imageSmoothingEnabled !== "undefined") {
this.context.imageSmoothingEnabled = config.imageSmoothing || false;
}
// Initialize defaults
this.frameCounter = 0;
// Initialize input methods
this.inputs = {};
if (config.inputs.keyboard) {
this.inputs.keyboard = new KeyboardInput(this);
}
if (config.inputs.gamepad) {
this.inputs.gamepad = new GamepadInput(this);
}
this._game = this;
this._lastFrameTimestamp = 0;
this._lastFrameTotalRenders = 0;
this._wantPause = true;
this._fullScreenLastFrame = false;
}
setCamera (x, y) {
if (x instanceof Vector2D) {
let pos = x.clone();
pos.x = -pos.x;
pos.y = -pos.y;
this.pos = pos;
} else {
this.pos.x = -x;
this.pos.y = -y;
}
}
step (delta) {
this.frameCounter++;
this._preStep();
this._updateEntity(delta);
this._renderEntity();
this._updateInputs(); // NK: This happens at the end for reasons
}
_updateInputs () {
for (let input in this.inputs) {
if (this.inputs[input].update) {
this.inputs[input].update();
}
}
}
_preStep () {
if (this.isFullScreen) {
if (this._fullScreenLastFrame == false) {
this.canvas.style.width = `${screen.width}px`;
this.canvas.style.height = `${screen.height}px`;
if (this.fullScreenNativeResolution) {
this.canvas.width = screen.width * this.scale;
this.canvas.height = screen.height * this.scale;
this.context.scale(this._deviceRatio, this._deviceRatio);
}
}
this._fullScreenLastFrame = true;
} else {
if (this._fullScreenLastFrame == true) {
this.canvas.style.width = `${this.width}px`;
this.canvas.style.height = `${this.height}px`;
this.canvas.width = this.width * this.scale;
this.canvas.height = this.height * this.scale;
this.context.scale(this._deviceRatio, this._deviceRatio);
}
this._fullScreenLastFrame = false;
}
}
start () {
var self = this; // NK: Hate doing this...better way plz?
if (self._wantPause) {
self._wantPause = false;
} else {
console.log("MomentumEngine.Classes.Game.start called, game instance is already started");
return false; // Game is already running
}
self._wantPause = false;
let requestFrame = (() => {
return (window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / self.desiredFps);
});
})();
self._lastFrameTimestamp = +(new Date());
self.startTime = self._lastFrameTimestamp;
var loop = function () {
if (self._wantPause) {
return;
}
let currentTimestamp = +(new Date()),
delta = currentTimestamp - self._lastFrameTimestamp;
if (self.fixFrameRate) {
delta = 1000 / self.desiredFps;
}
//delta = Math.min(delta, 1000 / self.desiredFps);
self._lastFrameTimestamp = currentTimestamp;
self._lastFrameTotalRenders = 0;
self.step(delta);
requestFrame(loop);
};
loop();
return true;
}
pause () {
if (!this._wantPause) {
this._wantPause = true;
return true;
} else {
console.log("MomentumEngine.Classes.Game.pause called, game instance is already paused");
return false;
}
}
toggleFullScreen () {
if (!document.mozFullScreen && !document.webkitFullScreen) {
if (this.canvas.mozRequestFullScreen) {
this.canvas.mozRequestFullScreen();
} else {
this.canvas.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
}
} else {
if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else {
document.webkitCancelFullScreen();
}
}
}
get isFullScreen () {
return document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
}
}
export default Game;