Compare commits

..

13 Commits

Author SHA1 Message Date
Nathan Kunicki
18acbd96b2 Fixed addition of velocity to take into account delta 2016-02-14 01:56:23 +00:00
Nathan Kunicki
14ad28dd29 Particle system appears to be working 2016-02-14 01:40:00 +00:00
Nathan Kunicki
4d6a9561ae Particle system appears to be working 2016-02-14 01:19:07 +00:00
Nathan Kunicki
1316c814ec Particle system appears to be working 2016-02-14 01:16:11 +00:00
Nathan Kunicki
2d701de8d1 Particles now emit at a specified rate and correctly obey parent positions 2016-02-13 23:22:21 +00:00
Nathan Kunicki
9f53e28f35 First pass at particle system 2016-02-13 16:32:26 +00:00
Nathan Kunicki
e620ff9c94 Delta is now passed as param to update methods rather than game property, tidied up sprite and entity 2015-12-24 18:29:00 +00:00
Nathan Kunicki
5446079fe6 Seperated out stepper from start function, allows manual stepping of world 2015-12-23 17:32:44 +00:00
Nathan Kunicki
de6b327837 Fixed Safari Rect rendering issue 2015-12-23 16:41:46 +00:00
Nathan Kunicki
18df8c17ec Added image classes, new example (snowflakes) 2015-12-22 18:08:33 +00:00
Nathan Kunicki
2c88c9ce20 Tidied up method names 2015-12-21 16:56:24 +00:00
Nathan Kunicki
2eade7a21b Fixed bug in pong bounds handling 2015-12-21 16:48:55 +00:00
Nathan Kunicki
ae48ce9de2 Committed dists 2015-12-21 16:40:40 +00:00
33 changed files with 248 additions and 1657 deletions

6
.gitignore vendored
View File

@ -1,7 +1,3 @@
.idea/
.DS_Store
node_modules/
dist/
docs/
examples/*/dist/
browse.VC.db
node_modules/

2
dist/es5.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/es5.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,103 +0,0 @@
"use strict";
import MomentumEngine from "../../src/es6";
let KeyConsts = MomentumEngine.Consts.Input.Keys;
let black = new MomentumEngine.Classes.Color(0, 0, 0),
fireParticleWidth = 150,
fireParticleHeight = 150;
let startColour = new MomentumEngine.Classes.Color(250, 218, 68, 1),
startColourRandom = new MomentumEngine.Classes.Color(62, 60, 60, 0),
finishColour = new MomentumEngine.Classes.Color(245, 35, 0, 0),
finishColourRandom = new MomentumEngine.Classes.Color(60, 60, 60, 0);
class RandomColor extends MomentumEngine.Classes.Color {
constructor (initialColor, deltaColor) {
let r = initialColor.r + (deltaColor.r * RandomColor._rand()),
g = initialColor.g + (deltaColor.g * RandomColor._rand()),
b = initialColor.b + (deltaColor.b * RandomColor._rand()),
a = initialColor.a + (deltaColor.a * RandomColor._rand());
super(~~r, ~~g, ~~b, ~~a);
}
static _rand () {
return (Math.random() * 2 - 1);
}
}
class FireParticle extends MomentumEngine.Classes.Entity {
constructor (x, y) {
super(x, y);
this.timeToLive = 10000;
this.startColor = new RandomColor(startColour, startColourRandom);
this.finishColor = new RandomColor(finishColour, startColour);
this.deltaColor = startColour.clone().subtract(finishColour);
}
update (delta) {
this.startColor.a = this.startColor.a - (delta * 0.0001);
}
render () {
var gradient = this._game.context.createRadialGradient(
this.relativeLeft + fireParticleWidth / 2,
this.relativeTop + fireParticleHeight / 2,
fireParticleWidth / 10,
this.relativeLeft + fireParticleWidth / 2,
this.relativeTop + fireParticleHeight / 2,
fireParticleWidth / 2
);
gradient.addColorStop(0, this.startColor.toString());
gradient.addColorStop(1, "rgba(0, 0, 0, 0)");
this._game.context.fillStyle = gradient;
this._game.context.fillRect(this.relativeLeft, this.relativeTop, fireParticleWidth, fireParticleHeight);
return true;
}
}
window.onload = function () {
let width = 640,
height = 360,
baseSize = width / 64;
let fireDemo = new MomentumEngine.Classes.Game({
canvas: document.getElementById("canvas"),
width: width,
height: height,
fixRatio: true,
desiredFps: 60,
inputs: {
keyboard: true
}
});
let mainScene = new MomentumEngine.Classes.Rect(0, 0, width, height, black);
fireDemo.addChildEntity(mainScene);
let fireEmitter = new MomentumEngine.Classes.Emitter(width / 2 - (fireParticleWidth / 2), height / 2 - (fireParticleHeight / 2), 250, new MomentumEngine.Classes.Vector2D(0.02, 0.02), FireParticle);
mainScene.addChildEntity(fireEmitter);
fireEmitter.setParticleParent(mainScene);
fireEmitter.emitting = true;
fireDemo.start();
};

View File

@ -1,10 +0,0 @@
<!doctype html>
<html>
<head>
<title>Fire - MomentumEngine</title>
<script type="application/javascript" src="./dist/fire.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>

2
examples/particles/dist/particles.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -8,12 +8,12 @@ let KeyConsts = MomentumEngine.Consts.Input.Keys;
class BlueParticle extends MomentumEngine.Classes.Rect {
constructor (x, y) {
super(x, y, 1, 1, new MomentumEngine.Classes.Color(0, 255, 0));
this.timeToLive = 25500;
super(x, y, 1, 1, new MomentumEngine.Classes.Color(255, 255, 255, 0));
this.timeToLive = 5000;
}
update (delta) {
this.color.a = this.color.a - (delta * 0.00004);
this.color.a = this.color.a - (delta * 0.00025);
}
}
@ -25,7 +25,7 @@ window.onload = function () {
height = 360,
baseSize = width / 64;
let particleDemo = new MomentumEngine.Classes.Game({
let particles = new MomentumEngine.Classes.Game({
canvas: document.getElementById("canvas"),
width: width,
height: height,
@ -37,54 +37,40 @@ window.onload = function () {
});
let black = new MomentumEngine.Classes.Color(0, 0, 0),
red = new MomentumEngine.Classes.Color(255, 0, 0),
blue = new MomentumEngine.Classes.Color(0, 0, 255);
red = new MomentumEngine.Classes.Color(255, 0, 0);
let mainScene = new MomentumEngine.Classes.Rect(0, 0, width, height, black);
particleDemo.addChildEntity(mainScene);
particles.addChildEntity(mainScene);
let emitterRect = new MomentumEngine.Classes.Rect(width / 8 - baseSize, height / 2 - baseSize, baseSize * 2, baseSize * 2, red),
let rect = new MomentumEngine.Classes.Rect(width / 2 - baseSize, height / 2 - baseSize, baseSize * 2, baseSize * 2, red),
emitter = new MomentumEngine.Classes.Emitter(baseSize, baseSize, 4, new MomentumEngine.Classes.Vector2D(0, 0.05), BlueParticle);
let bottomFieldRect = new MomentumEngine.Classes.Rect(width - (baseSize * 33), height - (baseSize * 11), baseSize * 2, baseSize * 2, blue),
bottomField = new MomentumEngine.Classes.Field(baseSize, baseSize, 0.1);
mainScene.addChildEntity(rect);
rect.addChildEntity(emitter);
let topFieldRect = new MomentumEngine.Classes.Rect(width - (baseSize * 33), baseSize * 9, baseSize * 2, baseSize * 2, blue),
topField = new MomentumEngine.Classes.Field(baseSize, baseSize, 0.1);
rect.update = function (delta) {
mainScene.addChildEntity(emitterRect);
emitterRect.addChildEntity(emitter);
mainScene.addChildEntity(bottomFieldRect);
bottomFieldRect.addChildEntity(bottomField);
mainScene.addChildEntity(topFieldRect);
topFieldRect.addChildEntity(topField);
emitterRect.update = function (delta) {
if (particleDemo.inputs.keyboard.isPressed(KeyConsts.UP)) {
emitterRect.pos.y -= (0.2 * delta);
if (particles.inputs.keyboard.isPressed(KeyConsts.UP)) {
rect.pos.y -= (0.2 * delta);
}
if (particleDemo.inputs.keyboard.isPressed(KeyConsts.DOWN)) {
emitterRect.pos.y += (0.2 * delta);
if (particles.inputs.keyboard.isPressed(KeyConsts.DOWN)) {
rect.pos.y += (0.2 * delta);
}
if (particleDemo.inputs.keyboard.isPressed(KeyConsts.LEFT)) {
emitterRect.pos.x -= (0.2 * delta);
if (particles.inputs.keyboard.isPressed(KeyConsts.LEFT)) {
rect.pos.x -= (0.2 * delta);
}
if (particleDemo.inputs.keyboard.isPressed(KeyConsts.RIGHT)) {
emitterRect.pos.x += (0.2 * delta);
if (particles.inputs.keyboard.isPressed(KeyConsts.RIGHT)) {
rect.pos.x += (0.2 * delta);
}
};
emitter.setParticleParent(mainScene);
emitter.particleFields.push(bottomField, topField);
emitter.spread = Math.PI / 8;
emitter.emitting = true;
particleDemo.start();
particles.start();
};

View File

@ -2,7 +2,8 @@
<html>
<head>
<title>Pong - MomentumEngine</title>
<script type="application/javascript" src="./dist/pong.js"></script>
<script type="application/javascript" src="../../dist/es5.js"></script>
<script type="application/javascript" src="./pong.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>

View File

@ -1,332 +1,118 @@
"use strict";
import MomentumEngine from "../../src/es6";
let KeyConsts = MomentumEngine.Consts.Input.Keys;
let width = 640,
height = 360,
baseSize = width / 64;
let white = new MomentumEngine.Classes.Color(255, 255, 255),
black = new MomentumEngine.Classes.Color(0, 0, 0),
red = new MomentumEngine.Classes.Color(255, 0, 0);
let font = new MomentumEngine.Classes.Font("Arial", 32, white, red);
class Ball extends MomentumEngine.Classes.Rect {
constructor (startingLeft, startingTop) {
super(startingLeft, startingTop, baseSize, baseSize, white);
this.startingLeft = startingLeft;
this.startingTop = startingTop;
this.speed = new MomentumEngine.Classes.Vector2D(0.1, 0.05); // Starting ball speed
}
update (delta) {
this.pos.add(this.speed.clone().multiply(delta));
if (this.left + baseSize > width && this.speed.x > 0) {
this.left = this.startingLeft;
this.top = this.startingTop;
this.game.leftScoreboard.increment();
} else if (this.left < 0 && this.speed.x < 0) {
this.left = this.startingLeft;
this.top = this.startingTop;
this.game.rightScoreboard.increment();
}
if ((this.top + baseSize > height && this.speed.y > 0) || (this.top < 0 && this.speed.y < 0)) {
this.speed.y = -this.speed.y;
}
}
}
class Paddle extends MomentumEngine.Classes.Rect {
constructor (posLeft, keys) {
super(posLeft, baseSize, baseSize, baseSize * 7, white);
this.keyUp = keys.up;
this.keyDown = keys.down;
this.scoreboard = null;
}
update (delta) {
if (this.keyUp(this, delta)) {
this.top -= (0.5 * delta);
} else if (this.keyDown(this, delta)) {
this.top += (0.5 * delta);
}
if (this.top > height - (baseSize * 8)) {
this.top = height - (baseSize * 8);
} else if (this.top < baseSize) {
this.top = baseSize;
}
this.balls.forEach((ball) => {
if (this.isCollidingWith(ball)) {
ball.speed.x = -ball.speed.x;
}
});
}
}
class Scoreboard extends MomentumEngine.Classes.Text {
constructor (posLeft) {
super(posLeft, 35, font);
this.score = 0;
this.text = "Score: 0";
}
increment () {
this.score++;
this.text = `Score: ${this.score}`;
}
}
class Pong extends MomentumEngine.Classes.Game {
constructor (canvas, width, height) {
super({
canvas: canvas,
width: width,
height: height,
fixRatio: true,
desiredFps: 60,
//fixFrameRate: true,
fullscreen: {
nativeResolution: true,
maintainAspectRatio: true
},
inputs: {
keyboard: true,
gamepad: true
}
});
let background = new MomentumEngine.Classes.Rect(0, 0, width, height, black);
this.addChildEntity(background);
this.balls = [];
this.paddles = [];
}
setLeftScoreboard (scoreboard) {
this.leftScoreboard = scoreboard;
this.addChildEntity(scoreboard);
}
setRightScoreboard (scoreboard) {
this.rightScoreboard = scoreboard;
this.addChildEntity(scoreboard);
}
addBall (ball) {
ball.game = this;
this.balls.push(ball);
this.addChildEntity(ball);
}
addPaddle (paddle) {
this.paddles.push(paddle);
this.addChildEntity(paddle);
paddle.balls = this.balls;
}
}
var leftPaddleUpCondition = function (paddle, delta) {
let gamepadInput = paddle._game.inputs.gamepad;
let gamepadConnected = (gamepadInput.numGamepads >= 1),
axisMoved = false;
if (gamepadConnected) {
let upDownAxes = gamepadInput.getGamepadById(0).getAxis(1);
if (upDownAxes < -0.1) {
this.top += (0.5 * delta) * upDownAxes;
axisMoved = true;
}
}
if (!axisMoved) {
if (paddle._game.inputs.keyboard.isPressed(KeyConsts.CHAR_Q)) {
this.top -= 0.5 * delta;
}
}
};
var leftPaddleDownCondition = function (paddle, delta) {
let gamepadInput = paddle._game.inputs.gamepad;
let gamepadConnected = (gamepadInput.numGamepads >= 1),
axisMoved = false;
if (gamepadConnected) {
let upDownAxes = gamepadInput.getGamepadById(0).getAxis(1);
if (upDownAxes > 0.1) {
this.top += (0.5 * delta) * upDownAxes;
axisMoved = true;
}
}
if (!axisMoved) {
if (paddle._game.inputs.keyboard.isPressed(KeyConsts.CHAR_A)) {
this.top += 0.5 * delta;
}
}
};
var rightPaddleUpCondition = function (paddle, delta) {
let gamepadInput = paddle._game.inputs.gamepad;
let gamepadConnected = (gamepadInput.numGamepads >= 1 && gamepadInput.getGamepadById(0).numAxis >= 6),
axisMoved = false;
if (gamepadConnected) {
let upDownAxes = gamepadInput.getGamepadById(0).getAxis(4);
if (upDownAxes < -0.1) {
this.top += (0.5 * delta) * upDownAxes;
axisMoved = true;
}
}
if (!axisMoved) {
if (paddle._game.inputs.keyboard.isPressed(KeyConsts.CHAR_O)) {
this.top -= 0.5 * delta;
}
}
};
var rightPaddleDownCondition = function (paddle, delta) {
let gamepadInput = paddle._game.inputs.gamepad;
let gamepadConnected = (gamepadInput.numGamepads >= 1),
axisMoved = false;
if (gamepadConnected) {
let upDownAxes = gamepadInput.getGamepadById(0).getAxis(4);
if (upDownAxes > 0.1) {
this.top += (0.5 * delta) * upDownAxes;
axisMoved = true;
}
}
if (!axisMoved) {
if (paddle._game.inputs.keyboard.isPressed(KeyConsts.CHAR_L)) {
this.top += 0.5 * delta;
}
}
};
window.onload = function () {
var pong = new Pong(document.getElementById("canvas"), width, height);
var ball = new Ball((width / 2) - (baseSize / 2), (height / 2) - (baseSize / 2));
var KeyConsts = MomentumEngine.Consts.Input.Keys;
var leftPaddle = new Paddle(baseSize, {
up: leftPaddleUpCondition,
down: leftPaddleDownCondition
var width = 640,
height = 360,
baseSize = width / 64;
var pong = new MomentumEngine.Classes.Game({
canvas: document.getElementById("canvas"),
width: width,
height: height,
fixRatio: true,
desiredFps: 60,
inputs: {
keyboard: true
}
});
var rightPaddle = new Paddle(width - (baseSize * 2), {
up: rightPaddleUpCondition,
down: rightPaddleDownCondition
});
var leftScoreboard = new Scoreboard(baseSize),
rightScoreboard = new Scoreboard(width - baseSize);
// 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.Classes.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);
rightScoreboard.textAlign = "right"; // Right align the text of the right scoreboard
// Create scene graph
pong.addBall(ball);
pong.addPaddle(leftPaddle);
pong.addPaddle(rightPaddle);
pong.addChildEntity(mainScene);
mainScene.addChildEntity(ball);
mainScene.addChildEntity(leftPaddle);
mainScene.addChildEntity(rightPaddle);
// Update the ball position
ball.state.speed = new MomentumEngine.Classes.Vector2D(0.1, 0.05); // Current ball speed
ball.update = function (delta) {
this.pos.add(this.state.speed.clone().multiply(delta));
if ((this.pos.x + baseSize > width && this.state.speed.x > 0) || (this.pos.x < 0 && this.state.speed.x < 0)) {
this.state.speed.x = -this.state.speed.x;
}
if ((this.pos.y + baseSize > height && this.state.speed.y > 0) || (this.pos.y < 0 && this.state.speed.y < 0)) {
this.state.speed.y = -this.state.speed.y;
}
};
// Update the left paddle according to keyboard input
leftPaddle.update = function (delta) {
if (pong.inputs.keyboard.isPressed(KeyConsts.CHAR_Q) || pong.inputs.keyboard.isPressed(KeyConsts.UP)) {
leftPaddle.pos.y -= (0.5 * delta);
}
if (pong.inputs.keyboard.isPressed(KeyConsts.CHAR_A) || pong.inputs.keyboard.isPressed(KeyConsts.DOWN)) {
leftPaddle.pos.y += (0.5 * delta);
}
if (leftPaddle.pos.y > height - (baseSize * 8)) {
leftPaddle.pos.y = height - (baseSize * 8);
}
if (leftPaddle.pos.y < baseSize) {
leftPaddle.pos.y = baseSize;
}
if (leftPaddle.isCollidingWith(ball) && ball.state.speed.x < 0) {
ball.state.speed.x = -ball.state.speed.x;
}
};
// Update the right paddle according to keyboard input
rightPaddle.update = function (delta) {
if (pong.inputs.keyboard.isPressed(KeyConsts.CHAR_O)) {
rightPaddle.pos.y -= (0.5 * delta);
}
if (pong.inputs.keyboard.isPressed(KeyConsts.CHAR_L)) {
rightPaddle.pos.y += (0.5 * delta);
}
if (rightPaddle.pos.y > height - (baseSize * 8)) {
rightPaddle.pos.y = height - (baseSize * 8);
}
if (rightPaddle.pos.y < baseSize) {
rightPaddle.pos.y = baseSize;
}
if (rightPaddle.isCollidingWith(ball) && ball.state.speed.x > 0) {
ball.state.speed.x = -ball.state.speed.x;
}
};
pong.setLeftScoreboard(leftScoreboard);
pong.setRightScoreboard(rightScoreboard);
pong.start();
document.addEventListener("keydown", function(e) {
if (e.keyCode == 13) {
pong.toggleFullScreen();
}
}, false);
};

View File

@ -2,7 +2,8 @@
<html>
<head>
<title>Snowflakes - MomentumEngine</title>
<script type="application/javascript" src="./dist/snowflakes.js"></script>
<script type="application/javascript" src="../../dist/es5.js"></script>
<script type="application/javascript" src="./snowflakes.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>

View File

@ -1,13 +1,11 @@
"use strict";
import MomentumEngine from "../../src/es6";
let KeyConsts = MomentumEngine.Consts.Input.Keys;
window.onload = function () {
var KeyConsts = MomentumEngine.Consts.Input.Keys;
var width = 640,
height = 360;
@ -45,14 +43,14 @@ window.onload = function () {
var newSnowflake = new MomentumEngine.Classes.Sprite(startPos, -100, 100, 100, snowflakeImg);
newSnowflake.update = function () {
this.top = this.top + (delta * 0.06);
this.pos.y = this.pos.y + (delta * 0.06);
};
mainScene.addChildEntity(newSnowflake);
mainScene.children.forEach(function (oldSnowflake) {
if (oldSnowflake.top > height) {
if (oldSnowflake.pos.y > height) {
// Clean up snowflakes that are no longer visible
mainScene.detachChildEntity(oldSnowflake);
}

View File

@ -3,33 +3,7 @@
var gulp = require("gulp"),
path = require("path"),
gutil = require("gulp-util"),
webpack = require("webpack"),
jsdoc = require("gulp-jsdoc3");
let minify = true,
watch = false,
examples = [
"fire",
"particles",
"pong",
"snowflakes"
];
process.argv.forEach((arg) => {
if (arg == "--dev" || arg == "-d") {
minify = false;
gutil.log("[Momentum Engine] dev flag passed, enabled");
}
if (arg == "--watch" || arg == "-w") {
watch = true;
gutil.log("[Momentum Engine] watch flag passed, enabled");
}
});
webpack = require("webpack");
var build = function (options, callback) {
@ -51,13 +25,16 @@ var build = function (options, callback) {
}
webpack({
entry: options.entry,
entry: {
"es5": path.join(__dirname, "src", "es5.js"),
"particles": path.join(__dirname, "examples/particles", "particles.js")
},
bail: !options.watch,
watch: options.watch,
devtool: "source-map",
plugins: plugins,
output: {
path: options.path,
path: path.join(__dirname, "dist"),
filename: "[name].js"
},
module: {
@ -101,51 +78,34 @@ var build = function (options, callback) {
};
examples.forEach((example) => {
let entry = {};
entry[example] = path.join(__dirname, "examples", example, `${example}.js`);
gulp.task(`${example}-example`, (callback) => {
build({
entry: entry,
path: path.join(__dirname, "examples", example, "dist"),
watch: watch,
minify: minify
}, callback);
});
gulp.task("move", () => {
gulp.src([
"./dist/particles.*"
], {
base: "./dist"
}).pipe(gulp.dest("examples/particles/dist"));
});
gulp.task("examples", examples.map((example) => { return `${example}-example`; }));
gulp.task("engine", (callback) => {
gulp.task("build-dev", (callback) => {
build({
entry: {
"es5": path.join(__dirname, "src", "es5.js")
},
path: path.join(__dirname, "dist"),
watch: watch,
minify: minify
watch: false,
minify: false
}, callback);
});
gulp.task("docs", (callback) => {
gulp.src([
"src/classes/*.js"
], {
read: false
}).pipe(jsdoc({
opts: {
destination: "docs"
}
}, callback));
})
gulp.task("build", (callback) => {
build({
watch: false,
minify: true
}, callback);
});
gulp.task("build", ["engine", "docs", "examples"]);
gulp.task("default", ["build"]);
gulp.task("watch", () => {
build({
watch: true,
minify: false
});
});

View File

@ -1,31 +1,26 @@
{
"name": "momentumengine",
"version": "0.10.0",
"version": "0.0.1",
"description": "An ES6 game and animation engine.",
"main": "src/es6.js",
"repository": {
"type": "git",
"url": "https://github.com/nathankunicki/momentumengine.git"
},
"scripts": {
"postinstall": "gulp --silent",
"build": "gulp",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Nathan Kunicki <me@nathankunicki.com>",
"license": "MIT",
"license": "ISC",
"engines": {
"node": "^7.6.0"
"node": "^4.2.3"
},
"dependencies": {
"babel-core": "6.23.1",
"babel-loader": "6.3.2",
"babel-plugin-transform-runtime": "6.23.0",
"babel-preset-es2015": "6.22.0",
"babel-preset-stage-0": "6.22.0",
"devDependencies": {
"babel-core": "6.5.2",
"babel-loader": "6.2.2",
"babel-plugin-transform-runtime": "6.5.2",
"babel-preset-es2015": "6.5.0",
"babel-preset-stage-0": "6.5.0",
"babel-runtime": "6.5.0",
"gulp": "3.9.1",
"gulp-jsdoc3": "1.0.1",
"gulp-util": "3.0.8",
"webpack": "2.2.1"
}
"gulp-util": "3.0.7",
"webpack": "1.12.13"
},
"dependencies": {}
}

View File

@ -1,87 +0,0 @@
"use strict";
class AudioTrack {
constructor (src) {
this._loaded = false; // Default is true, set it to false until the audio has loaded
this._error = false; // If the audio fails to load, this will contain the reason
this._loop = false;
this._audioObj = new Audio();
this._audioObj.addEventListener("loadeddata", () => {
this._loaded = true;
this._error = false;
this._audioObj.addEventListener("ended", () => {
if (this._loop) {
this._audioObj.currentTime = 0;
this._audioObj.play();
}
});
});
this._audioObj.addEventListener("error", (err) => {
this._loaded = false;
this._error = err;
});
this._audioObj.src = src;
}
get loop () {
return this._loop;
}
set loop (shouldLoop) {
return this._loop = shouldLoop;
}
play () {
if (this._loaded) {
return this._audioObj.play();
} else {
return false;
}
}
pause () {
if (this._loaded) {
return this._audioObj.pause();
} else {
return false;
}
}
seek (seconds) {
if (this._loaded) {
return this._audioObj.currentTime = seconds;
} else {
return false;
}
}
isLoaded () {
return this._loaded;
}
isError () {
return this._error;
}
}
export default AudioTrack;

View File

@ -1,128 +1,28 @@
"use strict";
/**
* Class representing a color
*/
class Color {
/**
* Create a color
* @param {number} red - Red value (0-255)
* @param {number} green - Green value (0-255)
* @param {number} blue - Blue value (0-255)
* @param {number} alpha - Alpha value (0-1)
*/
constructor (red = 0, green = 0, blue = 0, alpha = 1) {
constructor (r, g, b, a) {
this.red = red;
this.green = green;
this.blue = blue;
this.alpha = alpha;
this.r = r || 0;
this.g = g || 0;
this.b = b || 0;
this.a = a || 1;
}
/**
* Returns the rgba (rgba()) string representation of the color
* @returns {string}
*/
toString () {
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${this.alpha})`;
return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a})`;
}
/**
* Returns the hex (#) representation of the color
* @returns {string}
*/
toHex () {
return `#${((r << 16) | (g << 8) | b).toString(16)}`;
}
/**
* Clones the color and returns a new color
* @returns {Color}
*/
clone () {
return new Color(this.red, this.green, this.blue, this.alpha);
}
/**
* Add a color to this color
* @param {Color} color - Color to add
* @returns {Color}
*/
add (color) {
if (color instanceof Color) {
this.red += color.r; this.green += color.g; this.blue += color.b; this.alpha += color.a;
} else {
this.red += color; this.green += color; this.blue += color; this.alpha += color;
}
return this;
}
/**
* Subtract a color from this color
* @param {Color} color - Color to subtract
* @returns {Color}
*/
subtract (color) {
if (color instanceof Color) {
this.red -= color.r; this.green -= color.g; this.blue -= color.b; this.alpha -= color.a;
} else {
this.red -= color; this.green -= color; this.blue -= color; this.alpha -= color;
}
return this;
}
/**
* Multiply this color with another color
* @param {Color} color - Color to multiply with
* @returns {Color}
*/
multiply (color) {
if (color instanceof Color) {
this.red *= color.r; this.green *= color.g; this.blue *= color.b; this.alpha *= color.a;
} else {
this.red *= color; this.green *= color; this.blue *= color; this.alpha *= color;
}
return this;
}
/**
* Divide this color with another color
* @param {Color} color - Color to divide by
* @returns {Color}
*/
divide (color) {
if (color instanceof Color) {
this.red /= color.r; this.green /= color.g; this.blue /= color.b; this.alpha /= color.a;
} else {
this.red /= color; this.green /= color; this.blue /= color; this.alpha /= color;
}
return this;
}
}

View File

@ -3,8 +3,6 @@
import Entity from "./entity.js";
import Vector2D from "./vector2d.js";
import Utils from "../libs/utils";
class Emitter extends Entity {
@ -15,7 +13,6 @@ class Emitter extends Entity {
this.particleVelocity = velocity;
this.particleClass = particle;
this.particleFields = [];
this.rate = rate;
this.emitting = false;
@ -42,10 +39,8 @@ class Emitter extends Entity {
magnitude = this.particleVelocity.length(),
velocity = Vector2D.fromAngle(angle, magnitude);
// NK: This might cause a bug where child renders have an incorrect position because preprocess should normally be called after the update function but before the render, here it is before update. We'll see.
let particle = new ParticleClass(this.relativeLeft, this.relativeTop);
let particle = new ParticleClass(this._calculatedPos.x, this._calculatedPos.y);
particle.velocity = velocity;
Utils.mergeIntoArray(particle.fields, this.particleFields);
//this._particles.push(particle);
parent.addChildEntity(particle);
@ -55,9 +50,13 @@ class Emitter extends Entity {
_triggerEmissions () {
// We prematurely call preprocess so that child particles can spawn from the emitters permission but be children of a different parent
// NK: This might cause a bug where child renders have an incorrect position because preprocess should normally be called after the update function but before the render, here it is before update. We'll see.
this._preprocess();
if (this.emitting) {
let currentTime = Date.now();
let currentTime = +(new Date());
if (!this._wasEmitting) {
this._wasEmitting = true;

View File

@ -2,35 +2,20 @@
import Vector2D from "./vector2d.js";
/**
* Class representing an entity in a scene
*/
class Entity {
/**
* Create an entity
* @param {number} x - x (Left) position of the entity
* @param {number} y - y (Top) position of the entity
*/
constructor (x = 0, y = 0) {
constructor (x, y) {
this.pos = new Vector2D(x, y);
this.pos = new Vector2D(x || 0, y || 0);
this.velocity = new Vector2D(0, 0);
this.acceleration = new Vector2D(0, 0);
this.size = new Vector2D(0, 0);
this.rotation = 0;
this.display = true;
this.fields = [];
this.state = {};
this.children = [];
this._relativePos = this.pos.clone();
this._lastRelativePosCalculated = 0;
this._lastRelativeSizeCalculated = 0;
this._calculatedPos = this.pos.clone();
this._lastCalculated = 0;
this._game = null;
this._parent = null;
@ -39,91 +24,6 @@ class Entity {
}
/**
* x (Left) position of the entity
*/
get left () {
return this.pos.x;
}
set left (val) {
let res = (this.pos.x = val);
if (this._parent) {
this._relativePos.x = this.pos.x + this._parent.relativeLeft;
} else {
this._relativePos.x = this.pos.x;
}
return res;
}
/**
* y (Top) position of the entity
*/
get top () {
return this.pos.y;
}
set top (val) {
let res = (this.pos.y = val);
if (this._parent) {
this._relativePos.y = this.pos.y + this._parent.relativeTop;
} else {
this._relativePos.y = this.pos.y;
}
return res;
}
/**
* Returns the absolute x (Left) position relative to the entities parent tree
* @returns {number} x - x (Left) position relative to the entities parent tree
*/
get relativeLeft () {
return this._calculateRelativePos().x;
}
/**
* Returns the absolute y (Top) position relative to the entities parent tree
* @returns {number} y - y (Top) position relative to the entities parent tree
*/
get relativeTop () {
return this._calculateRelativePos().y;
}
/**
* Width of the entity
*/
get width () {
return this.size.x;
}
set width (width) {
return this.size.x = width;
}
/**
* Height of the entity
*/
get height () {
return this.size.y;
}
set height (height) {
return this.size.y = height;
}
/**
* Set the velocity of the entity
* @param {Number} x - x (Left) velocity
* @param {Number} y - y (Top) velocity
*/
setVelocity (x, y) {
if (x instanceof Vector2D) {
@ -136,11 +36,6 @@ class Entity {
}
/**
* Set the acceleration of the entity
* @param x {Number} x - x (Left) acceleration
* @param y {Number} y - y (Top) acceleration
*/
setAcceleration (x, y) {
if (x instanceof Vector2D) {
@ -153,11 +48,6 @@ class Entity {
}
/**
* Creates a new child entity.
* Note: This creates an instance of Entity, the base class. Under most circumstances you should use addChildEntity with an entity you have created.
* @returns {Entity}
*/
createChildEntity () {
let child = new Entity();
@ -171,11 +61,6 @@ class Entity {
}
/**
* Add an entity as a child
* @param {Entity} child - The child entity
* @returns {Entity}
*/
addChildEntity (child) {
child._updateGame(this._game);
@ -187,11 +72,6 @@ class Entity {
}
/**
* Removes entity from children
* @param {Entity} child - The child entity
* @returns {boolean} Indicates successful removal
*/
detachChildEntity (child) {
for (let i = 0; i < this.children.length; i++) {
@ -208,31 +88,33 @@ class Entity {
}
_calculateRelativePos () {
_preprocess () {
// NK: 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 _calculateRelativePos method all the way back up the tree and continuously adding the results together.
// NK: 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 _preprocess 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.
// When rendering, the draw calls should use this._relativePos rather than this.pos in order for the position to be correct.
// When rendering, the draw calls should use this._calculatedPos rather than this.pos in order for the position to be correct.
if (this._game && this._lastRelativePosCalculated < this._game.frameCounter) {
if (this._game && this._lastCalculated < this._game.frameCounter) {
if (this._parent) {
this._relativePos.x = this.pos.x + this._parent.relativeLeft;
this._relativePos.y = this.pos.y + this._parent.relativeTop;
let parentPos = this._parent._preprocess();
this._calculatedPos.x = this.pos.x + parentPos.x;
this._calculatedPos.y = this.pos.y + parentPos.y;
} else {
this._relativePos.x = this.pos.x;
this._relativePos.y = this.pos.y;
this._calculatedPos.x = this.pos.x;
this._calculatedPos.y = this.pos.y;
}
this._lastRelativePosCalculated = this._game.frameCounter;
this._lastCalculated = this._game.frameCounter;
}
return this._relativePos;
return this._calculatedPos;
}
@ -248,99 +130,22 @@ class Entity {
}
_scaleForLeft (val) {
let game = this._game;
if (!game.isFullScreen) {
return val;
} else {
return (game._fullScreenXPos + (val * game._fullScreenXScaling));
}
}
_scaleForWidth (val) {
let game = this._game;
if (!game.isFullScreen) {
return val;
} else {
return (val * game._fullScreenXScaling);
}
}
_scaleForTop (val) {
let game = this._game;
if (!game.isFullScreen) {
return val;
} else {
return (game._fullScreenYPos + (val * game._fullScreenYScaling));
}
}
_scaleForHeight (val) {
let game = this._game;
if (!game.isFullScreen) {
return val;
} else {
return (val * game._fullScreenYScaling);
}
}
_calculateFields (delta) {
let acceleration = new Vector2D(0, 0);
for (let i = 0; i < this.fields.length; i++) {
let field = this.fields[i];
// NK: These call _relativePos, I don't like using this outside of the render method...
let vector = new Vector2D(
field.relativeLeft - this.relativeLeft,
field.relativeTop - this.relativeTop
);
let force = field.mass / Math.pow(vector.dot(vector), 1.5);
acceleration.add(vector.multiply(force).multiply(delta));
}
return this.acceleration.clone().add(acceleration);
}
_updateEntity (delta) {
if (this.timeToLive) {
if (Date.now() - this._creationTime > this.timeToLive) {
if (+(new Date()) - this._creationTime > this.timeToLive) {
this._parent.detachChildEntity(this);
}
}
// Calculate new position based on velocity and acceleration if there's one set
if (this.velocity && (this.velocity.x !== 0 || this.velocity.y !== 0)) {
if (this.velocity) {
this.velocity.add(this._calculateFields(delta));
this.pos.x += (this.velocity.x * delta);
this.pos.y += (this.velocity.y * delta);
if (this.acceleration) {
this.velocity.add(this.acceleration);
}
this.pos.add(this.velocity.clone().multiply(delta));
}
@ -360,11 +165,9 @@ class Entity {
_renderEntity () {
let rendered = this.display && this.render && this.render();
this._preprocess();
if (rendered) {
this._game._lastFrameTotalRenders++;
}
let rendered = this.render && this.render();
if (rendered || (typeof rendered == "undefined") || (typeof this.render === "undefined")) {

View File

@ -1,21 +0,0 @@
"use strict";
import Entity from "./entity.js";
import Vector2D from "./vector2d.js";
class Field extends Entity {
constructor (x, y, mass) {
super(x, y);
this.mass = mass;
}
}
export default Field;

View File

@ -1,22 +0,0 @@
"use strict";
import Color from "./color.js";
class Font {
constructor(family, size, fill = null, stroke = null) {
this.family = family;
this.size = `${size}px`;
this.fill = fill;
this.stroke = stroke;
}
}
export default Font;

View File

@ -1,10 +1,7 @@
"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 {
@ -13,7 +10,6 @@ class Game extends Entity {
super(); // Call entity constructor
config = config || {};
config.fullscreen = config.fullscreen || {};
config.inputs = config.inputs || {};
@ -36,13 +32,9 @@ class Game extends Entity {
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) {
@ -65,45 +57,19 @@ class Game extends Entity {
}
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;
}
}
this.canvas.style.width = this.width + "px";
this.canvas.style.height = this.height + "px";
// Call getContext last for Ejecta only.
if (typeof ejecta !== "undefined") {
this.context = this.canvas.getContext("2d");
}
this.context.scale(this._deviceRatio, this._deviceRatio);
this.context.scale(deviceRatio, deviceRatio);
} else {
@ -122,43 +88,14 @@ class Game extends Entity {
// 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;
}
}
@ -167,61 +104,8 @@ class Game extends Entity {
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;
}
}
@ -262,13 +146,8 @@ class Game extends Entity {
let currentTimestamp = +(new Date()),
delta = currentTimestamp - self._lastFrameTimestamp;
if (self.fixFrameRate) {
delta = 1000 / self.desiredFps;
}
//delta = Math.min(delta, 1000 / self.desiredFps);
delta = Math.min(delta, 1000 / self.desiredFps);
self._lastFrameTimestamp = currentTimestamp;
self._lastFrameTotalRenders = 0;
self.step(delta);
@ -294,34 +173,6 @@ class Game extends Entity {
}
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;
}
}

View File

@ -1,155 +0,0 @@
"use strict";
class Gamepad {
constructor (gamepadObj) {
this._gamepadObj = gamepadObj;
}
get numButtons () {
return this._gamepadObj.buttons.length;
}
get numAxis () {
return this._gamepadObj.axes.length;
}
isPressed (buttonId) {
if (this._gamepadObj.buttons[buttonId]) {
return !!this._gamepadObj.buttons[buttonId].pressed;
} else {
throw new Error(`Button ${buttonId} not found on gamepad`);
}
}
getAxis (axisId) {
if (typeof this._gamepadObj.axes[axisId] !== "undefined") {
return this._gamepadObj.axes[axisId];
} else {
throw new Error(`Axis ${axisId} not found on gamepad`);
}
}
}
class GamepadInput {
constructor () {
var self = this;
self._gamepadState = {};
self.gamepadIds = [];
if ('ongamepadconnected' in window) {
window.addEventListener("gamepadconnected", (event) => {
self._gamepadState[event.gamepad.index] = new Gamepad(event.gamepad);
self.gamepadIds.push(event.gamepad.index);
console.log(`Gamepad ${event.gamepad.index} connected`);
});
window.addEventListener("gamepaddisconnected", (event) => {
delete self._gamepadState[event.gamepad.index];
self.gamepadIds.splice(self.gamepadIds.indexOf(event.gamepad.index));
console.log(`Gamepad ${event.gamepad.index} disconnected`);
});
}
}
update () {
if (!("ongamepadconnected" in window)) {
let gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads : []);
// If there are more gamepads registered than we know about, make ourselves aware of the new ones
if (gamepads.length != this.gamepadIds.length) {
for (let i = 0; i < gamepads.length; i++) {
let gamepad = gamepads[i];
if (gamepad) {
if (this.gamepadIds.indexOf(gamepad.index) < 0) {
this._gamepadState[gamepad.index] = new Gamepad(gamepad);
this.gamepadIds.push(gamepad.index);
console.log(`Gamepad ${gamepad.index} connected`);
}
}
}
// If there is still a mismatch, then we assume some gamepads have been disconnected, so we need to remove them
if (gamepads.length != this.gamepadIds.length) {
for (let i = 0; i < this.gamepadIds.length; i++) {
let found = false;
for (let j = 0; j < gamepads.length; j++) {
let gamepad = gamepads[i];
if (gamepad && gamepad.index == this.gamepadIds[i]) {
found = true;
}
}
if (!found) {
console.log(`Gamepad ${this.gamepadIds[i]} disconnected`);
delete this._gamepadState[this.gamepadIds[i]];
this.gamepadIds.splice(this.gamepadIds.indexOf(this.gamepadIds[i]));
i--;
}
}
}
}
}
}
get numGamepads () {
return this.gamepadIds.length;
}
getGamepadById (gamepadId) {
if (this._gamepadState[gamepadId]) {
return this._gamepadState[gamepadId];
} else {
throw new Error(`Gamepad ${buttonId} is not connected`);
}
}
}
export default GamepadInput;

View File

@ -15,7 +15,7 @@ class ImageLoader {
this._error = false;
});
this._imageObj.addEventListener("error", (err) => {
this._imageObj.addEventListener("_error", (err) => {
this._loaded = false;
this._error = err;
});

View File

@ -99,10 +99,6 @@ const KeyConsts = {
};
let wasReleased = {},
wasPressed = {};
class KeyboardInput {
@ -123,52 +119,16 @@ class KeyboardInput {
isPressed (keyCode) {
console.log("[MomentumEngine] WARNING: MomentumEngine.Classes.KeyboardInput.isPressed is deprecated. Use isDown instead.")
return !!this._keyState[keyCode];
}
isDown (keyCode) {
return !!this._keyState[keyCode];
}
wasPressed (keyCode) {
let pressed = !!wasPressed[keyCode];
if (pressed) {
wasPressed[keyCode] = false;
}
return pressed;
}
wasReleased (keyCode) {
let pressed = !!wasReleased[keyCode];
if (pressed) {
wasReleased[keyCode] = false;
}
return pressed;
}
_keyDownHandler (event) {
wasReleased[event.keyCode] = false;
wasPressed[event.keyCode] = true;
this._keyState[event.keyCode] = true;
}
_keyUpHandler (event) {
wasReleased[event.keyCode] = true;
wasPressed[event.keyCode] = false;
this._keyState[event.keyCode] = false;
}

View File

@ -1,57 +0,0 @@
"use strict";
import Entity from "./entity.js";
import Vector2D from "./vector2d.js";
import CollisionMethods from "../libs/collisionmethods.js";
class Path extends Entity {
constructor (x, y, width, height, color) {
super(x, y);
if (width instanceof Array) {
color = height;
this.coords = width;
} else {
this.coords = [new Vector2D(width, height)];
}
this.color = color;
}
render () {
if (this._game) {
let ctx = this._game.context;
ctx.strokeStyle = this.color.toString();
ctx.beginPath();
ctx.moveTo(this._scaleForLeft(this.relativeLeft), this._scaleForTop(this.relativeTop));
for (let coord in this.coords) {
ctx.lineTo(this._scaleForWidth(this.relativeLeft + this.coords[coord].x), this._scaleForHeight(this.relativeTop + this.coords[coord].y));
}
//ctx.closePath();
ctx.stroke();
return true;
} else {
return false;
}
}
}
export default Path;

View File

@ -1,41 +1,24 @@
"use strict";
import Entity from "./entity.js";
import Vector2D from "./vector2d.js";
import CollisionMethods from "../libs/collisionmethods.js";
/**
* Class representing a rectangle in a scene
* @extends Entity
*/
class Rect extends Entity {
/**
* Create a rectangle
* @param {number} x - x (Left) position of the rectangle
* @param {number} y - y (Top) position of the rectangle
* @param {number} width - Width of the rectangle
* @param {number} height - Height of the rectangle
* @param {Color} color - Color of the rectangle
*/
constructor (x, y, width, height, color) {
super(x, y);
this.size.x = width || 0;
this.size.y = height || 0;
this.size = new Vector2D(width, height);
this.color = color;
}
/**
* Detects if the rectangle is colliding with another entity
* @param {Entity} entity - Entity to check against
* @returns {boolean} Indicates whether the entities are colliding
*/
isCollidingWith (entity) {
if (entity instanceof Rect) {
@ -49,31 +32,8 @@ class Rect extends Entity {
if (this._game) {
let left = this._scaleForLeft(this.relativeLeft),
top = this._scaleForTop(this.relativeTop),
width = this._scaleForWidth(this.width),
height = this._scaleForHeight(this.height),
ctx = this._game.context;
let xRot = left + (width / 2),
yRot = top + (height / 2);
if (this.rotation > 0) {
// Rotate the canvas based on the central point of this entity
ctx.translate(xRot, yRot);
ctx.rotate(this.rotation * Math.PI / 180);
ctx.translate(-xRot, -yRot);
}
ctx.fillStyle = this.color.toString();
ctx.fillRect(left, top, width, height);
if (this.rotation > 0) {
// Rotate back after drawing
ctx.translate(xRot, yRot);
ctx.rotate(-(this.rotation * Math.PI / 180));
ctx.translate(-xRot, -yRot);
}
this._game.context.fillStyle = this.color.toString();
this._game.context.fillRect(this._calculatedPos.x, this._calculatedPos.y, this.size.x, this.size.y);
return true;

View File

@ -18,8 +18,7 @@ class Sprite extends Entity {
super(x, y);
this.size.x = width || 0;
this.size.y = height || 0;
this.size = new Vector2D(width || 0, height || 0);
this._image = image;
this._imagePos = new Vector2D(0, 0);
@ -58,10 +57,10 @@ class Sprite extends Entity {
this._imagePos.y,
this._imageSize.x || subWidth,
this._imageSize.y || subHeight,
this._scaleForLeft(this.relativeLeft),
this._scaleForTop(this.relativeTop),
this._scaleForWidth(this.width || subWidth),
this._scaleForHeight(this.height || subHeight)
this._calculatedPos.x,
this._calculatedPos.y,
this.size.x || subWidth,
this.size.y || subHeight
);
return true;

View File

@ -1,113 +0,0 @@
"use strict";
import Entity from "./entity.js";
import Vector2D from "./vector2d.js";
class Text extends Entity {
constructor (x, y, font, text) {
super(x, y);
this.font = font;
this.text = text;
this.textAlign = "start";
this.textBaseline = "alphabetic";
this.direction = "inherit";
this.letterSpacing = 0;
}
isCollidingWith (entity) {
if (entity instanceof Rect) {
return CollisionMethods.AABB(this, entity);
}
}
_renderText (text, x, y, letterSpacing, renderFunc) {
// Code modified from original by David Hong (sozonov): https://jsfiddle.net/sozonov/mg1jkz3q/
if (!text || typeof text !== "string" || text.length === 0) {
return false;
}
if (letterSpacing == 0) {
renderFunc(text, x, y);
return;
}
let characters = text.split(""),
index = 0,
current,
currentPosition = x,
align = 1;
if (this.textAlign === "right") {
characters = characters.reverse();
align = -1;
} else if (this.textAlign === "center") {
let totalWidth = 0;
for (let i = 0; i < characters.length; i++) {
// NK: We want to cache the results of measureText instead of recalculating every character every frame
totalWidth += (this._game.context.measureText(characters[i]).width + letterSpacing);
}
currentPosition = x - (totalWidth / 2);
}
while (index < text.length) {
current = characters[index++];
renderFunc(current, currentPosition, y);
// NK: We want to cache the results of measureText instead of recalculating every character every frame
currentPosition += (align * (this._game.context.measureText(current).width + letterSpacing));
}
}
render () {
if (this._game) {
this._game.context.font = `${this.font.size} ${this.font.family}`;
this._game.context.textAlign = this.textAlign;
this._game.context.textBaseline = this.textBaseline;
this._game.context.direction = this.direction;
if (this.font.fill) {
this._game.context.fillStyle = this.font.fill;
this._renderText(this.text, this._scaleForLeft(this.relativeLeft), this._scaleForTop(this.relativeTop), this.letterSpacing, this._game.context.fillText.bind(this._game.context));
}
if (this.font.stroke) {
this._game.context.strokeStyle = this.font.stroke;
this._renderText(this.text, this._scaleForLeft(this.relativeLeft), this._scaleForTop(this.relativeTop), this.letterSpacing, this._game.context.strokeText.bind(this._game.context));
}
return true;
} else {
return false;
}
}
}
export default Text;

View File

@ -112,7 +112,7 @@ class Vector2D {
toString () {
return `[${this.x},${this.y}]`;
return `[${this.x}},${this.y}}]`;
}

View File

@ -2,35 +2,25 @@
import Game from "./classes/game.js";
import Emitter from "./classes/emitter.js";
import Field from "./classes/field.js";
import Entity from "./classes/entity.js";
import Vector2D from "./classes/vector2d.js";
import Sprite from "./classes/sprite.js";
import Rect from "./classes/rect.js";
import Path from "./classes/path.js";
import Color from "./classes/color.js";
import Text from "./classes/text.js";
import Font from "./classes/font.js";
import AudioTrack from "./classes/audio.js";
import ImageLoader from "./classes/imageloader.js";
import {KeyConsts} from "./classes/keyboardinput.js";
const Classes = {
Game,
Emitter,
Field,
Entity,
Sprite,
Rect,
Path,
Vector2D,
Color,
Text,
Font,
AudioTrack,
ImageLoader
Game: Game,
Emitter: Emitter,
Entity: Entity,
Sprite: Sprite,
Rect: Rect,
Vector2D: Vector2D,
Color: Color,
ImageLoader: ImageLoader
};

View File

@ -2,35 +2,25 @@
import Game from "./classes/game.js";
import Emitter from "./classes/emitter.js";
import Field from "./classes/field.js";
import Entity from "./classes/entity.js";
import Vector2D from "./classes/vector2d.js";
import Sprite from "./classes/sprite.js";
import Rect from "./classes/rect.js";
import Path from "./classes/path.js";
import Color from "./classes/color.js";
import Text from "./classes/text.js";
import Font from "./classes/font.js";
import AudioTrack from "./classes/audio.js";
import ImageLoader from "./classes/imageloader.js";
import {KeyConsts} from "./classes/keyboardinput.js";
const Classes = {
Game,
Emitter,
Field,
Entity,
Sprite,
Rect,
Path,
Vector2D,
Color,
Text,
Font,
AudioTrack,
ImageLoader
Game: Game,
Emitter: Emitter,
Entity: Entity,
Sprite: Sprite,
Rect: Rect,
Vector2D: Vector2D,
Color: Color,
ImageLoader: ImageLoader
};

View File

@ -9,12 +9,10 @@ class CollisionMethods {
throw new Error("AABB collisions can only be checked on these entity types: Rect");
}
let colliding = (entity1.left < entity2.left + entity2.width &&
entity1.left + entity1.width > entity2.left &&
entity1.top < entity2.top + entity2.height &&
entity1.height + entity1.top > entity2.top);
return colliding;
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);
}

View File

@ -1,20 +0,0 @@
class Utils {
static mergeIntoArray (dest, source) {
source.forEach((item) => {
if (dest.indexOf(item) < 0) {
dest.push(item);
}
});
return dest;
}
}
export default Utils;