Tidied up ES6 and ES5 options

This commit is contained in:
Nathan Kunicki 2015-12-21 16:36:31 +00:00
parent 7ff89a21b9
commit ea2c197c5c
15 changed files with 366 additions and 163 deletions

View File

@ -1,129 +0,0 @@
"use strict";
window.onload = function () {
var pong = new MomentumEngine.Game({
canvas: document.getElementById("game"),
width: 640,
height: 360,
fixRatio: true,
desiredFps: 60,
inputs: {
keyboard: true
}
});
var multiply = pong.width / 640;
// All of these are instances of MomentumEngine.Entity;
var mainScene = pong.createChildEntity(),
ball = mainScene.createChildEntity(),
leftPaddle = mainScene.createChildEntity(),
rightPaddle = mainScene.createChildEntity();
// Wipe the screen
pong.render = function () {
pong.context.fillStyle = "rgba(0, 0, 0, 1)";
pong.context.fillRect(0, 0, pong.width, pong.height);
return true;
};
// Update and render the ball
ball.state.pos = new MomentumEngine.Vector2D(pong.width / 2, pong.height / 2); // Current ball position;
ball.state.width = multiply * 10;
ball.state.height = multiply * 10;
ball.state.vector = new MomentumEngine.Vector2D(0.1, 0.05); // Current ball vector
ball.update = function () {
this.state.pos.add(this.state.vector.clone().multiply(pong.lastFrameDelta));
if ((this.state.pos.x + 5 > pong.width) || (this.state.pos.x - 5 < 0)) {
//this.state.vector.multiply(1.1);
this.state.vector.x = -this.state.vector.x;
}
if ((this.state.pos.y + 5 > pong.height) || (this.state.pos.y - 5 < 0)) {
//this.state.vector.multiply(1.1);
this.state.vector.y = -this.state.vector.y;
}
};
ball.render = function () {
pong.context.fillStyle = "rgba(255, 255, 255, 1)";
pong.context.fillRect(ball.state.pos.x - (ball.state.width / 2), ball.state.pos.y - (ball.state.height / 2), ball.state.width, ball.state.height);
};
// Update and render the left paddle
leftPaddle.state.left = multiply * 10;
leftPaddle.state.top = multiply * 10;
leftPaddle.state.width = multiply * 10;
leftPaddle.state.height = multiply * 70;
leftPaddle.update = function () {
if (pong.inputs.keyboard.isPressed(pong.consts.keys.CHAR_Q) || pong.inputs.keyboard.isPressed(pong.consts.keys.UP)) {
leftPaddle.state.top -= (0.5 * pong.lastFrameDelta);
}
if (pong.inputs.keyboard.isPressed(pong.consts.keys.CHAR_A) || pong.inputs.keyboard.isPressed(pong.consts.keys.DOWN)) {
leftPaddle.state.top += (0.5 * pong.lastFrameDelta);
}
if (leftPaddle.state.top > pong.height - (multiply * 80)) {
leftPaddle.state.top = pong.height - (multiply * 80);
}
if (leftPaddle.state.top < (multiply * 10)) {
leftPaddle.state.top = (multiply * 10);
}
};
leftPaddle.render = function () {
pong.context.fillStyle = "rgba(255, 255, 255, 1)";
pong.context.fillRect(leftPaddle.state.left, leftPaddle.state.top, leftPaddle.state.width, leftPaddle.state.height);
};
// Render the right paddle
rightPaddle.state.left = pong.width - (multiply * 10 * 2);
rightPaddle.state.top = multiply * 10;
rightPaddle.state.width = multiply * 10;
rightPaddle.state.height = multiply * 70;
rightPaddle.update = function () {
if (pong.inputs.keyboard.isPressed(pong.consts.keys.CHAR_O)) {
rightPaddle.state.top -= (0.5 * pong.lastFrameDelta);
}
if (pong.inputs.keyboard.isPressed(pong.consts.keys.CHAR_L)) {
rightPaddle.state.top += (0.5 * pong.lastFrameDelta);
}
if (rightPaddle.state.top > pong.height - (multiply * 80)) {
rightPaddle.state.top = pong.height - (multiply * 80);
}
if (rightPaddle.state.top < (multiply * 10)) {
rightPaddle.state.top = (multiply * 10);
}
};
rightPaddle.render = function () {
pong.context.fillStyle = "rgba(255, 255, 255, 1)";
pong.context.fillRect(rightPaddle.state.left, rightPaddle.state.top, rightPaddle.state.width, rightPaddle.state.height);
};
pong.start();
};

119
examples/pong/pong.js Normal file
View File

@ -0,0 +1,119 @@
"use strict";
window.onload = function () {
var KeyConsts = MomentumEngine.Consts.Input.Keys;
var width = 640,
height = 360,
baseSize = width / 64;
var pong = new MomentumEngine.Classes.Game({
canvas: document.getElementById("game"),
width: width,
height: height,
fixRatio: true,
desiredFps: 60,
inputs: {
keyboard: true
}
});
// Colors
var white = new MomentumEngine.Classes.Color(255, 255, 255),
black = new MomentumEngine.Classes.Color(0, 0, 0);
// All of these are instances of MomentumEngine.Entity;
var mainScene = new MomentumEngine.Classes.Rect(0, 0, width, height, black),
ball = new MomentumEngine.Classes.Rect((width / 2) - (baseSize / 2), (height / 2) - (baseSize / 2), baseSize, baseSize, white),
leftPaddle = new MomentumEngine.Classes.Rect(baseSize, baseSize, baseSize, baseSize * 7, white),
rightPaddle = new MomentumEngine.Classes.Rect(width - (baseSize * 2), baseSize, baseSize, baseSize * 7, white);
// Create scene graph
pong.addChildEntity(mainScene);
mainScene.addChildEntity(ball);
mainScene.addChildEntity(leftPaddle);
mainScene.addChildEntity(rightPaddle);
// Update and render the ball
ball.state.speed = new MomentumEngine.Classes.Vector2D(0.1, 0.05); // Current ball speed
ball.update = function () {
this.pos.add(this.state.speed.clone().multiply(pong.lastFrameDelta));
if ((this.pos.x + baseSize > width) || (this.pos.x < 0)) {
this.state.speed.x = -this.state.speed.x;
}
if ((this.pos.y + baseSize > height) || (this.pos.y < 0)) {
this.state.speed.y = -this.state.speed.y;
}
};
// Update and render the left paddle
leftPaddle.update = function () {
if (pong.inputs.keyboard.isPressed(KeyConsts.CHAR_Q) || pong.inputs.keyboard.isPressed(KeyConsts.UP)) {
leftPaddle.pos.y -= (0.5 * pong.lastFrameDelta);
}
if (pong.inputs.keyboard.isPressed(KeyConsts.CHAR_A) || pong.inputs.keyboard.isPressed(KeyConsts.DOWN)) {
leftPaddle.pos.y += (0.5 * pong.lastFrameDelta);
}
if (leftPaddle.pos.y > height - (baseSize * 8)) {
leftPaddle.pos.y = height - (baseSize * 8);
}
if (leftPaddle.pos.y < baseSize) {
leftPaddle.pos.y = baseSize;
}
if (leftPaddle.isColliding(ball) && ball.state.speed.x < 0) {
ball.state.speed.x = -ball.state.speed.x;
console.log(ball.state.speed.length());
}
};
// Render the right paddle
rightPaddle.update = function () {
if (pong.inputs.keyboard.isPressed(KeyConsts.CHAR_O)) {
rightPaddle.pos.y -= (0.5 * pong.lastFrameDelta);
}
if (pong.inputs.keyboard.isPressed(KeyConsts.CHAR_L)) {
rightPaddle.pos.y += (0.5 * pong.lastFrameDelta);
}
if (rightPaddle.pos.y > height - (baseSize * 8)) {
rightPaddle.pos.y = height - (baseSize * 8);
}
if (rightPaddle.pos.y < baseSize) {
rightPaddle.pos.y = baseSize;
}
if (rightPaddle.isColliding(ball) && ball.state.speed.x > 0) {
ball.state.speed.x = -ball.state.speed.x;
}
};
pong.start();
};

View File

@ -25,14 +25,16 @@ var build = function (options, callback) {
} }
webpack({ webpack({
entry: path.join(__dirname, "src", "index.js"), entry: {
"es5": path.join(__dirname, "src", "es5.js")
},
bail: !options.watch, bail: !options.watch,
watch: options.watch, watch: options.watch,
devtool: "source-map", devtool: "source-map",
plugins: plugins, plugins: plugins,
output: { output: {
path: path.join(__dirname, "dist"), path: path.join(__dirname, "dist"),
filename: "es5.js" filename: "[name].js"
}, },
module: { module: {
loaders: [{ loaders: [{

View File

@ -2,7 +2,7 @@
"name": "momentumengine", "name": "momentumengine",
"version": "0.0.1", "version": "0.0.1",
"description": "An ES6 game and animation engine.", "description": "An ES6 game and animation engine.",
"main": "src/index.js", "main": "src/es6.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },

27
src/classes/color.js Normal file
View File

@ -0,0 +1,27 @@
class Color {
constructor (r, g, b, a) {
this.r = r || 0;
this.g = g || 0;
this.b = b || 0;
this.a = a || 1;
}
toString () {
return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a})`;
}
toHex () {
return `#${((r << 16) | (g << 8) | b).toString(16)}`;
}
}
export default Color;

View File

@ -1,17 +1,31 @@
"use strict"; "use strict";
import Vector2D from "./vector2d.js";
class Entity { class Entity {
constructor () { constructor (x, y) {
this.pos = new Vector2D(x || 0, y || 0);
this.state = {}; this.state = {};
this.children = []; this.children = [];
this._calculatedPos = this.pos.clone();
this._lastCalculated = 0;
this._game = null;
this._parent = null;
} }
createChildEntity () { createChildEntity () {
let child = new Entity(); let child = new Entity();
child._updateGame(this._game);
child._parent = this;
this.children.push(child); this.children.push(child);
return child; return child;
@ -19,10 +33,13 @@ class Entity {
} }
addChildEntity (entity) { addChildEntity (child) {
this.children.push(entity); child._updateGame(this._game);
return entity; child._parent = this;
this.children.push(child);
return child;
} }
@ -32,6 +49,45 @@ class Entity {
} }
_recalculatePos () {
// NK: This should be called within "render", not "update". The purpose of this function is to calculate the true position of the entity relative to all its parents. It does this recursively, calling the _recalculatePos method all the way back up the tree and continuously adding the results together.
// Note there is a limiter, where the last calculated frame is stored, so that if the position has already been calculated for that node in this particular frame, the cached result is used rather than recalculating.
if (this._game && this._lastCalculated < this._game.frameCounter) {
if (this._parent) {
let parentPos = this._parent._recalculatePos();
this._calculatedPos.x = this.pos.x + parentPos.x;
this._calculatedPos.y = this.pos.y + parentPos.y;
} else {
this._calculatedPos.x = this.pos.x;
this._calculatedPos.y = this.pos.y;
}
this._lastCalculated = this._game.frameCounter;
}
return this._calculatedPos;
}
_updateGame (game) {
this._game = game;
this.children.forEach((child) => {
child._updateGame(game);
});
}
_updateEntity () { _updateEntity () {
if ((this.update && this.update()) || (typeof this.update === "undefined")) { if ((this.update && this.update()) || (typeof this.update === "undefined")) {

View File

@ -1,7 +1,7 @@
"use strict"; "use strict";
import Entity from "./entity.js"; import Entity from "./entity.js";
import KeyboardInput, {keyConsts} from "./keyboardinput.js"; import KeyboardInput from "./keyboardinput.js";
class Game extends Entity { class Game extends Entity {
@ -89,15 +89,12 @@ class Game extends Entity {
this.lastFrameDelta = 0; this.lastFrameDelta = 0;
this.frameCounter = 0; this.frameCounter = 0;
this.consts = {
keys: keyConsts
};
this.inputs = {}; this.inputs = {};
if (config.inputs.keyboard) { if (config.inputs.keyboard) {
this.inputs.keyboard = new KeyboardInput(this); this.inputs.keyboard = new KeyboardInput(this);
} }
this._game = this;
this._lastFrameTimestamp = 0; this._lastFrameTimestamp = 0;
this._wantPause = true; this._wantPause = true;
@ -117,7 +114,7 @@ class Game extends Entity {
self._wantPause = false; self._wantPause = false;
var requestFrame = (function () { var requestFrame = (() => {
return (window.requestAnimationFrame || return (window.requestAnimationFrame ||
window.webkitRequestAnimationFrame || window.webkitRequestAnimationFrame ||
@ -139,9 +136,7 @@ class Game extends Entity {
self.lastFrameDelta = currentTimestamp - self._lastFrameTimestamp; self.lastFrameDelta = currentTimestamp - self._lastFrameTimestamp;
self._lastFrameTimestamp = currentTimestamp; self._lastFrameTimestamp = currentTimestamp;
if (self.lastFrameDelta > (1000 / self.desiredFps)) { self.lastFrameDelta = Math.min(self.lastFrameDelta, 1000 / self.desiredFps);
self.lastFrameDelta = (1000 / self.desiredFps);
}
if (self._wantPause) { if (self._wantPause) {
return; return;

View File

@ -1,7 +1,7 @@
"use strict"; "use strict";
const keyConsts = { const KeyConsts = {
SPACE: 32, SPACE: 32,
BACKSPACE: 8, BACKSPACE: 8,
TAB: 9, TAB: 9,
@ -137,4 +137,4 @@ class KeyboardInput {
export default KeyboardInput; export default KeyboardInput;
export {keyConsts}; export {KeyConsts};

52
src/classes/rect.js Normal file
View File

@ -0,0 +1,52 @@
"use strict";
import Entity from "./entity.js";
import Vector2D from "./vector2d.js";
import CollisionMethods from "../libs/collisionmethods.js";
class Rect extends Entity {
constructor (x, y, width, height, color) {
super(x, y);
this.size = new Vector2D(width, height);
this.color = color;
}
isColliding (entity) {
if (entity instanceof Rect) {
return CollisionMethods.AABB(this, entity);
}
}
render () {
this._recalculatePos();
if (this._game) {
this._game.context.fillStyle = this.color;
this._game.context.fillRect(this._calculatedPos.x, this._calculatedPos.y, this.size.x, this.size.y);
return true;
} else {
return false;
}
}
}
export default Rect;

View File

@ -72,7 +72,7 @@ class Vector2D {
dot (val) { dot (val) {
return this.x * val.x + this.y * val.y; return (this.x * val.x + this.y * val.y);
} }
@ -96,11 +96,21 @@ class Vector2D {
} }
degrees () {
return (Math.atan(this.x, this.y) * 180);
}
toArray () { toArray () {
return [this.x, this.y]; return [this.x, this.y];
} }
toString () {
return `[${this.x}},${this.y}}]`;
}
clone () { clone () {
return new Vector2D(this.x, this.y); return new Vector2D(this.x, this.y);
} }

31
src/es5.js Normal file
View File

@ -0,0 +1,31 @@
"use strict";
import Game from "./classes/game.js";
import Entity from "./classes/entity.js";
import Vector2D from "./classes/vector2d.js";
import Rect from "./classes/rect.js";
import Color from "./classes/color.js";
import {KeyConsts} from "./classes/keyboardinput.js";
const Classes = {
Game: Game,
Entity: Entity,
Rect: Rect,
Vector2D: Vector2D,
Color: Color
};
const Consts = {
Input: {
Keys: KeyConsts
}
};
window.MomentumEngine = {
Classes: Classes,
Consts: Consts
};

31
src/es6.js Normal file
View File

@ -0,0 +1,31 @@
"use strict";
import Game from "./classes/game.js";
import Entity from "./classes/entity.js";
import Vector2D from "./classes/vector2d.js";
import Rect from "./classes/rect.js";
import Color from "./classes/color.js";
import {KeyConsts} from "./classes/keyboardinput.js";
const Classes = {
Game: Game,
Entity: Entity,
Rect: Rect,
Vector2D: Vector2D,
Color: Color
};
const Consts = {
Input: {
Keys: KeyConsts
}
};
export {
Classes,
Consts
};

View File

@ -1,15 +0,0 @@
"use strict";
import Game from "./classes/game.js";
import Entity from "./classes/entity.js";
import Vector2D from "./classes/vector2d.js";
window.MomentumEngine = {
Game: Game,
Entity: Entity,
Vector2D: Vector2D
};
export {Game};
export {Entity};
export {Vector2D};

View File

@ -0,0 +1,24 @@
import Rect from "../classes/rect.js";
import Vector2D from "../classes/vector2d.js";
class CollisionMethods {
static AABB (entity1, entity2) {
if (!entity1 instanceof Rect || !entity2 instanceof Rect) {
throw new Error("AABB collisions can only be checked on these entity types: Rect");
}
return (entity1.pos.x < entity2.pos.x + entity2.size.x &&
entity1.pos.x + entity1.size.x > entity2.pos.x &&
entity1.pos.y < entity2.pos.y + entity2.size.y &&
entity1.size.y + entity1.pos.y > entity2.pos.y);
}
}
export default CollisionMethods;