Compare commits
13 Commits
master
...
feature/pa
Author | SHA1 | Date | |
---|---|---|---|
|
18acbd96b2 | ||
|
14ad28dd29 | ||
|
4d6a9561ae | ||
|
1316c814ec | ||
|
2d701de8d1 | ||
|
9f53e28f35 | ||
|
e620ff9c94 | ||
|
5446079fe6 | ||
|
de6b327837 | ||
|
18df8c17ec | ||
|
2c88c9ce20 | ||
|
2eade7a21b | ||
|
ae48ce9de2 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
.idea/
|
||||
.DS_Store
|
||||
dist/
|
||||
node_modules/
|
2
dist/es5.js
vendored
Normal file
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
1
dist/es5.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
examples/particles/dist/particles.js
vendored
Normal file
2
examples/particles/dist/particles.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
examples/particles/dist/particles.js.map
vendored
Normal file
1
examples/particles/dist/particles.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
10
examples/particles/index.html
Normal file
10
examples/particles/index.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Particles - MomentumEngine</title>
|
||||
<script type="application/javascript" src="./dist/particles.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas"></canvas>
|
||||
</body>
|
||||
</html>
|
76
examples/particles/particles.js
Normal file
76
examples/particles/particles.js
Normal file
@ -0,0 +1,76 @@
|
||||
"use strict";
|
||||
|
||||
import MomentumEngine from "../../src/es6";
|
||||
|
||||
let KeyConsts = MomentumEngine.Consts.Input.Keys;
|
||||
|
||||
|
||||
class BlueParticle extends MomentumEngine.Classes.Rect {
|
||||
|
||||
constructor (x, y) {
|
||||
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.00025);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
window.onload = function () {
|
||||
|
||||
let width = 640,
|
||||
height = 360,
|
||||
baseSize = width / 64;
|
||||
|
||||
let particles = new MomentumEngine.Classes.Game({
|
||||
canvas: document.getElementById("canvas"),
|
||||
width: width,
|
||||
height: height,
|
||||
fixRatio: true,
|
||||
desiredFps: 60,
|
||||
inputs: {
|
||||
keyboard: true
|
||||
}
|
||||
});
|
||||
|
||||
let black = new MomentumEngine.Classes.Color(0, 0, 0),
|
||||
red = new MomentumEngine.Classes.Color(255, 0, 0);
|
||||
|
||||
let mainScene = new MomentumEngine.Classes.Rect(0, 0, width, height, black);
|
||||
particles.addChildEntity(mainScene);
|
||||
|
||||
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);
|
||||
|
||||
mainScene.addChildEntity(rect);
|
||||
rect.addChildEntity(emitter);
|
||||
|
||||
rect.update = function (delta) {
|
||||
|
||||
if (particles.inputs.keyboard.isPressed(KeyConsts.UP)) {
|
||||
rect.pos.y -= (0.2 * delta);
|
||||
}
|
||||
|
||||
if (particles.inputs.keyboard.isPressed(KeyConsts.DOWN)) {
|
||||
rect.pos.y += (0.2 * delta);
|
||||
}
|
||||
|
||||
if (particles.inputs.keyboard.isPressed(KeyConsts.LEFT)) {
|
||||
rect.pos.x -= (0.2 * delta);
|
||||
}
|
||||
|
||||
if (particles.inputs.keyboard.isPressed(KeyConsts.RIGHT)) {
|
||||
rect.pos.x += (0.2 * delta);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
emitter.setParticleParent(mainScene);
|
||||
emitter.emitting = true;
|
||||
|
||||
particles.start();
|
||||
|
||||
};
|
@ -6,6 +6,6 @@
|
||||
<script type="application/javascript" src="./pong.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="game"></canvas>
|
||||
<canvas id="canvas"></canvas>
|
||||
</body>
|
||||
</html>
|
@ -12,7 +12,7 @@ window.onload = function () {
|
||||
|
||||
|
||||
var pong = new MomentumEngine.Classes.Game({
|
||||
canvas: document.getElementById("game"),
|
||||
canvas: document.getElementById("canvas"),
|
||||
width: width,
|
||||
height: height,
|
||||
fixRatio: true,
|
||||
@ -28,7 +28,7 @@ window.onload = function () {
|
||||
black = new MomentumEngine.Classes.Color(0, 0, 0);
|
||||
|
||||
|
||||
// All of these are instances of MomentumEngine.Entity;
|
||||
// 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),
|
||||
@ -42,33 +42,33 @@ window.onload = function () {
|
||||
mainScene.addChildEntity(rightPaddle);
|
||||
|
||||
|
||||
// Update and render the ball
|
||||
// Update the ball position
|
||||
ball.state.speed = new MomentumEngine.Classes.Vector2D(0.1, 0.05); // Current ball speed
|
||||
|
||||
ball.update = function () {
|
||||
ball.update = function (delta) {
|
||||
|
||||
this.pos.add(this.state.speed.clone().multiply(pong.lastFrameDelta));
|
||||
this.pos.add(this.state.speed.clone().multiply(delta));
|
||||
|
||||
if ((this.pos.x + baseSize > width) || (this.pos.x < 0)) {
|
||||
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.pos.y < 0)) {
|
||||
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 and render the left paddle
|
||||
leftPaddle.update = function () {
|
||||
// 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 * pong.lastFrameDelta);
|
||||
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 * pong.lastFrameDelta);
|
||||
leftPaddle.pos.y += (0.5 * delta);
|
||||
}
|
||||
|
||||
if (leftPaddle.pos.y > height - (baseSize * 8)) {
|
||||
@ -79,23 +79,22 @@ window.onload = function () {
|
||||
leftPaddle.pos.y = baseSize;
|
||||
}
|
||||
|
||||
if (leftPaddle.isColliding(ball) && ball.state.speed.x < 0) {
|
||||
if (leftPaddle.isCollidingWith(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 () {
|
||||
// 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 * pong.lastFrameDelta);
|
||||
rightPaddle.pos.y -= (0.5 * delta);
|
||||
}
|
||||
|
||||
if (pong.inputs.keyboard.isPressed(KeyConsts.CHAR_L)) {
|
||||
rightPaddle.pos.y += (0.5 * pong.lastFrameDelta);
|
||||
rightPaddle.pos.y += (0.5 * delta);
|
||||
}
|
||||
|
||||
if (rightPaddle.pos.y > height - (baseSize * 8)) {
|
||||
@ -106,7 +105,7 @@ window.onload = function () {
|
||||
rightPaddle.pos.y = baseSize;
|
||||
}
|
||||
|
||||
if (rightPaddle.isColliding(ball) && ball.state.speed.x > 0) {
|
||||
if (rightPaddle.isCollidingWith(ball) && ball.state.speed.x > 0) {
|
||||
ball.state.speed.x = -ball.state.speed.x;
|
||||
}
|
||||
|
||||
|
11
examples/snowflakes/index.html
Normal file
11
examples/snowflakes/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Snowflakes - MomentumEngine</title>
|
||||
<script type="application/javascript" src="../../dist/es5.js"></script>
|
||||
<script type="application/javascript" src="./snowflakes.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas"></canvas>
|
||||
</body>
|
||||
</html>
|
BIN
examples/snowflakes/snowflake.png
Normal file
BIN
examples/snowflakes/snowflake.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 194 KiB |
68
examples/snowflakes/snowflakes.js
Normal file
68
examples/snowflakes/snowflakes.js
Normal file
@ -0,0 +1,68 @@
|
||||
"use strict";
|
||||
|
||||
window.onload = function () {
|
||||
|
||||
|
||||
var KeyConsts = MomentumEngine.Consts.Input.Keys;
|
||||
|
||||
|
||||
var width = 640,
|
||||
height = 360;
|
||||
|
||||
|
||||
var snowflakes = new MomentumEngine.Classes.Game({
|
||||
canvas: document.getElementById("canvas"),
|
||||
width: width,
|
||||
height: height,
|
||||
fixRatio: true,
|
||||
desiredFps: 60
|
||||
});
|
||||
|
||||
|
||||
// Colors
|
||||
var blue = new MomentumEngine.Classes.Color(204, 255, 255);
|
||||
|
||||
|
||||
// All of these are instances of MomentumEngine.Classes.Entity
|
||||
var mainScene = new MomentumEngine.Classes.Rect(0, 0, width, height, blue);
|
||||
|
||||
|
||||
// Load images
|
||||
var snowflakeImg = new MomentumEngine.Classes.ImageLoader("./snowflake.png");
|
||||
|
||||
|
||||
// Create scene graph
|
||||
snowflakes.addChildEntity(mainScene);
|
||||
|
||||
mainScene.update = function (delta) {
|
||||
|
||||
if ((snowflakes.frameCounter % 120) == 0) { // Every two seconds or so, add a new snowflake
|
||||
|
||||
var startPos = (Math.random() * width) - 50;
|
||||
|
||||
var newSnowflake = new MomentumEngine.Classes.Sprite(startPos, -100, 100, 100, snowflakeImg);
|
||||
|
||||
newSnowflake.update = function () {
|
||||
this.pos.y = this.pos.y + (delta * 0.06);
|
||||
};
|
||||
|
||||
mainScene.addChildEntity(newSnowflake);
|
||||
|
||||
mainScene.children.forEach(function (oldSnowflake) {
|
||||
|
||||
if (oldSnowflake.pos.y > height) {
|
||||
// Clean up snowflakes that are no longer visible
|
||||
mainScene.detachChildEntity(oldSnowflake);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
snowflakes.start();
|
||||
|
||||
|
||||
};
|
15
gulpfile.js
15
gulpfile.js
@ -26,7 +26,8 @@ var build = function (options, callback) {
|
||||
|
||||
webpack({
|
||||
entry: {
|
||||
"es5": path.join(__dirname, "src", "es5.js")
|
||||
"es5": path.join(__dirname, "src", "es5.js"),
|
||||
"particles": path.join(__dirname, "examples/particles", "particles.js")
|
||||
},
|
||||
bail: !options.watch,
|
||||
watch: options.watch,
|
||||
@ -41,7 +42,8 @@ var build = function (options, callback) {
|
||||
loader: "babel-loader",
|
||||
test: /\.js$/,
|
||||
include: [
|
||||
path.join(__dirname, "src")
|
||||
path.join(__dirname, "src"),
|
||||
path.join(__dirname, "examples")
|
||||
],
|
||||
query: {
|
||||
plugins: ["transform-runtime"],
|
||||
@ -76,6 +78,15 @@ var build = function (options, callback) {
|
||||
};
|
||||
|
||||
|
||||
gulp.task("move", () => {
|
||||
gulp.src([
|
||||
"./dist/particles.*"
|
||||
], {
|
||||
base: "./dist"
|
||||
}).pipe(gulp.dest("examples/particles/dist"));
|
||||
});
|
||||
|
||||
|
||||
gulp.task("build-dev", (callback) => {
|
||||
build({
|
||||
watch: false,
|
||||
|
16
package.json
16
package.json
@ -12,15 +12,15 @@
|
||||
"node": "^4.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "6.3.17",
|
||||
"babel-loader": "6.2.0",
|
||||
"babel-plugin-transform-runtime": "6.3.13",
|
||||
"babel-preset-es2015": "6.3.13",
|
||||
"babel-preset-stage-0": "6.3.13",
|
||||
"babel-runtime": "6.3.19",
|
||||
"gulp": "3.9.0",
|
||||
"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-util": "3.0.7",
|
||||
"webpack": "1.12.9"
|
||||
"webpack": "1.12.13"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
class Color {
|
||||
|
||||
|
||||
|
94
src/classes/emitter.js
Normal file
94
src/classes/emitter.js
Normal file
@ -0,0 +1,94 @@
|
||||
"use strict";
|
||||
|
||||
import Entity from "./entity.js";
|
||||
import Vector2D from "./vector2d.js";
|
||||
|
||||
|
||||
class Emitter extends Entity {
|
||||
|
||||
|
||||
constructor (x, y, rate, velocity, particle) {
|
||||
|
||||
super(x, y);
|
||||
|
||||
this.particleVelocity = velocity;
|
||||
this.particleClass = particle;
|
||||
|
||||
this.rate = rate;
|
||||
this.emitting = false;
|
||||
this.spread = Math.PI;
|
||||
this._lastEmitTime = this._creationTime;
|
||||
this._wasEmitting = false;
|
||||
|
||||
this._particles = [];
|
||||
|
||||
}
|
||||
|
||||
|
||||
setParticleParent (entity) {
|
||||
this._particleParent = entity;
|
||||
}
|
||||
|
||||
|
||||
_emit () {
|
||||
|
||||
let ParticleClass = this.particleClass,
|
||||
parent = this._particleParent || this._parent;
|
||||
|
||||
let angle = this.particleVelocity.angle() + this.spread - (Math.random() * this.spread * 2),
|
||||
magnitude = this.particleVelocity.length(),
|
||||
velocity = Vector2D.fromAngle(angle, magnitude);
|
||||
|
||||
let particle = new ParticleClass(this._calculatedPos.x, this._calculatedPos.y);
|
||||
particle.velocity = velocity;
|
||||
|
||||
//this._particles.push(particle);
|
||||
parent.addChildEntity(particle);
|
||||
|
||||
}
|
||||
|
||||
|
||||
_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 = +(new Date());
|
||||
|
||||
if (!this._wasEmitting) {
|
||||
this._wasEmitting = true;
|
||||
this._lastEmitTime = currentTime;
|
||||
}
|
||||
|
||||
let emitDelta = currentTime - this._lastEmitTime;
|
||||
if (emitDelta > this.rate) {
|
||||
|
||||
let emissions = ~~(emitDelta / this.rate);
|
||||
|
||||
this._lastEmitTime = currentTime + (emitDelta - (this.rate * emissions));
|
||||
|
||||
for (let i = 0; i < emissions; i++) {
|
||||
this._emit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
this._wasEmitting = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
update () {
|
||||
this._triggerEmissions();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default Emitter;
|
@ -8,6 +8,8 @@ class Entity {
|
||||
constructor (x, y) {
|
||||
|
||||
this.pos = new Vector2D(x || 0, y || 0);
|
||||
this.velocity = new Vector2D(0, 0);
|
||||
this.acceleration = new Vector2D(0, 0);
|
||||
|
||||
this.state = {};
|
||||
this.children = [];
|
||||
@ -17,6 +19,32 @@ class Entity {
|
||||
this._game = null;
|
||||
this._parent = null;
|
||||
|
||||
this._creationTime = +(new Date());
|
||||
|
||||
}
|
||||
|
||||
|
||||
setVelocity (x, y) {
|
||||
|
||||
if (x instanceof Vector2D) {
|
||||
this.velocity = x;
|
||||
} else {
|
||||
this.velocity.x = x;
|
||||
this.velocity.y = y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
setAcceleration (x, y) {
|
||||
|
||||
if (x instanceof Vector2D) {
|
||||
this.acceleration = x;
|
||||
} else {
|
||||
this.acceleration.x = x;
|
||||
this.acceleration.y = y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -44,25 +72,39 @@ class Entity {
|
||||
}
|
||||
|
||||
|
||||
detachChildEntity (entity) {
|
||||
// Not implemented
|
||||
detachChildEntity (child) {
|
||||
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
if (this.children[i] == child) {
|
||||
|
||||
this.children.splice(i, 1);
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
_recalculatePos () {
|
||||
_preprocess () {
|
||||
|
||||
// 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.
|
||||
// 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._calculatedPos rather than this.pos in order for the position to be correct.
|
||||
|
||||
if (this._game && this._lastCalculated < this._game.frameCounter) {
|
||||
|
||||
if (this._parent) {
|
||||
|
||||
let parentPos = this._parent._recalculatePos();
|
||||
let parentPos = this._parent._preprocess();
|
||||
|
||||
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;
|
||||
@ -88,12 +130,32 @@ class Entity {
|
||||
}
|
||||
|
||||
|
||||
_updateEntity () {
|
||||
_updateEntity (delta) {
|
||||
|
||||
if ((this.update && this.update()) || (typeof this.update === "undefined")) {
|
||||
if (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) {
|
||||
|
||||
if (this.acceleration) {
|
||||
this.velocity.add(this.acceleration);
|
||||
}
|
||||
|
||||
this.pos.add(this.velocity.clone().multiply(delta));
|
||||
|
||||
}
|
||||
|
||||
// If there's an update method, call it
|
||||
let updated = this.update && this.update(delta);
|
||||
|
||||
if (updated || (typeof updated == "undefined") || (typeof this.update === "undefined")) {
|
||||
|
||||
this.children.forEach((child) => {
|
||||
child._updateEntity();
|
||||
child._updateEntity(delta);
|
||||
});
|
||||
|
||||
}
|
||||
@ -103,7 +165,11 @@ class Entity {
|
||||
|
||||
_renderEntity () {
|
||||
|
||||
if ((this.render && this.render()) || (typeof this.render === "undefined")) {
|
||||
this._preprocess();
|
||||
|
||||
let rendered = this.render && this.render();
|
||||
|
||||
if (rendered || (typeof rendered == "undefined") || (typeof this.render === "undefined")) {
|
||||
|
||||
this.children.forEach((child) => {
|
||||
child._renderEntity();
|
||||
|
@ -17,19 +17,19 @@ class Game extends Entity {
|
||||
if (config.canvas) {
|
||||
this.canvas = config.canvas;
|
||||
} else {
|
||||
throw new Error("MomentumEngine.Game must be constructed with a canvas");
|
||||
throw new Error("MomentumEngine.Classes.Game must be constructed with a canvas");
|
||||
}
|
||||
|
||||
if (config.width) {
|
||||
this.width = config.width;
|
||||
} else {
|
||||
throw new Error("MomentumEngine.Game must be constructed with canvas width");
|
||||
throw new Error("MomentumEngine.Classes.Game must be constructed with canvas width");
|
||||
}
|
||||
|
||||
if (config.height) {
|
||||
this.height = config.height;
|
||||
} else {
|
||||
throw new Error("MomentumEngine.Game must be constructed with canvas height");
|
||||
throw new Error("MomentumEngine.Classes.Game must be constructed with canvas height");
|
||||
}
|
||||
|
||||
|
||||
@ -86,7 +86,6 @@ class Game extends Entity {
|
||||
|
||||
|
||||
// Initialize defaults
|
||||
this.lastFrameDelta = 0;
|
||||
this.frameCounter = 0;
|
||||
|
||||
this.inputs = {};
|
||||
@ -101,6 +100,16 @@ class Game extends Entity {
|
||||
}
|
||||
|
||||
|
||||
step (delta) {
|
||||
|
||||
this.frameCounter++;
|
||||
|
||||
this._updateEntity(delta);
|
||||
this._renderEntity();
|
||||
|
||||
}
|
||||
|
||||
|
||||
start () {
|
||||
|
||||
var self = this; // NK: Hate doing this...better way plz?
|
||||
@ -108,13 +117,13 @@ class Game extends Entity {
|
||||
if (self._wantPause) {
|
||||
self._wantPause = false;
|
||||
} else {
|
||||
console.log("MomentumEngine.Game.start called, game instance is already started");
|
||||
console.log("MomentumEngine.Classes.Game.start called, game instance is already started");
|
||||
return false; // Game is already running
|
||||
}
|
||||
|
||||
self._wantPause = false;
|
||||
|
||||
var requestFrame = (() => {
|
||||
let requestFrame = (() => {
|
||||
|
||||
return (window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
@ -126,27 +135,21 @@ class Game extends Entity {
|
||||
})();
|
||||
|
||||
self._lastFrameTimestamp = +(new Date());
|
||||
self.startTime = self._lastFrameTimestamp;
|
||||
|
||||
var loop = function () {
|
||||
|
||||
self.frameCounter++;
|
||||
|
||||
let currentTimestamp = +(new Date());
|
||||
|
||||
self.lastFrameDelta = currentTimestamp - self._lastFrameTimestamp;
|
||||
self._lastFrameTimestamp = currentTimestamp;
|
||||
|
||||
self.lastFrameDelta = Math.min(self.lastFrameDelta, 1000 / self.desiredFps);
|
||||
|
||||
if (self._wantPause) {
|
||||
return;
|
||||
}
|
||||
|
||||
self._updateEntity.bind(self);
|
||||
self._updateEntity();
|
||||
let currentTimestamp = +(new Date()),
|
||||
delta = currentTimestamp - self._lastFrameTimestamp;
|
||||
|
||||
self._renderEntity.bind(self);
|
||||
self._renderEntity();
|
||||
delta = Math.min(delta, 1000 / self.desiredFps);
|
||||
self._lastFrameTimestamp = currentTimestamp;
|
||||
|
||||
self.step(delta);
|
||||
|
||||
requestFrame(loop);
|
||||
|
||||
@ -164,7 +167,7 @@ class Game extends Entity {
|
||||
this._wantPause = true;
|
||||
return true;
|
||||
} else {
|
||||
console.log("MomentumEngine.Game.pause called, game instance is already paused");
|
||||
console.log("MomentumEngine.Classes.Game.pause called, game instance is already paused");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
52
src/classes/imageloader.js
Normal file
52
src/classes/imageloader.js
Normal file
@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
|
||||
class ImageLoader {
|
||||
|
||||
|
||||
constructor (src) {
|
||||
|
||||
this._loaded = false; // Default is true, set it to false until the image has loaded
|
||||
this._error = false; // If the image fails to load, this will contain the reason
|
||||
|
||||
this._imageObj = new Image();
|
||||
|
||||
this._imageObj.addEventListener("load", () => {
|
||||
this._loaded = true;
|
||||
this._error = false;
|
||||
});
|
||||
|
||||
this._imageObj.addEventListener("_error", (err) => {
|
||||
this._loaded = false;
|
||||
this._error = err;
|
||||
});
|
||||
|
||||
this._imageObj.src = src;
|
||||
|
||||
}
|
||||
|
||||
|
||||
getImageObj () {
|
||||
|
||||
if (this._loaded) {
|
||||
return this._imageObj;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
isLoaded () {
|
||||
return this._loaded;
|
||||
}
|
||||
|
||||
|
||||
isError () {
|
||||
return this._error;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default ImageLoader;
|
@ -119,7 +119,7 @@ class KeyboardInput {
|
||||
|
||||
|
||||
isPressed (keyCode) {
|
||||
return !!this._keyState[keyCode];
|
||||
return !!this._keyState[keyCode];
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@ class Rect extends Entity {
|
||||
}
|
||||
|
||||
|
||||
isColliding (entity) {
|
||||
isCollidingWith (entity) {
|
||||
|
||||
if (entity instanceof Rect) {
|
||||
return CollisionMethods.AABB(this, entity);
|
||||
@ -30,11 +30,9 @@ class Rect extends Entity {
|
||||
|
||||
render () {
|
||||
|
||||
this._recalculatePos();
|
||||
|
||||
if (this._game) {
|
||||
|
||||
this._game.context.fillStyle = this.color;
|
||||
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;
|
||||
|
78
src/classes/sprite.js
Normal file
78
src/classes/sprite.js
Normal file
@ -0,0 +1,78 @@
|
||||
"use strict";
|
||||
|
||||
import Entity from "./entity.js";
|
||||
import Vector2D from "./vector2d.js";
|
||||
import ImageLoader from "./imageloader.js";
|
||||
|
||||
import CollisionMethods from "../libs/collisionmethods.js";
|
||||
|
||||
|
||||
class Sprite extends Entity {
|
||||
|
||||
|
||||
constructor (x, y, width, height, image) {
|
||||
|
||||
if (!image instanceof ImageLoader) {
|
||||
throw new Error("MomentumEngine.Classes.Sprite must be instantiated with an ImageLoader instance");
|
||||
}
|
||||
|
||||
super(x, y);
|
||||
|
||||
this.size = new Vector2D(width || 0, height || 0);
|
||||
|
||||
this._image = image;
|
||||
this._imagePos = new Vector2D(0, 0);
|
||||
this._imageSize = new Vector2D(0, 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
setImageCoords (x, y, width, height) {
|
||||
|
||||
this._imagePos.x = x;
|
||||
this._imagePos.y = y;
|
||||
this._imageSize.x = width || 0;
|
||||
this._imageSize.y = height || 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
isReady () {
|
||||
return (this._image.isLoaded() && !this._image.isError());
|
||||
}
|
||||
|
||||
|
||||
render () {
|
||||
|
||||
if (this.isReady() && this._game) {
|
||||
|
||||
let imageObj = this._image.getImageObj();
|
||||
|
||||
let subWidth = imageObj.width - this._imagePos.x,
|
||||
subHeight = imageObj.height - this._imagePos.y;
|
||||
|
||||
this._game.context.drawImage(
|
||||
imageObj,
|
||||
this._imagePos.x,
|
||||
this._imagePos.y,
|
||||
this._imageSize.x || subWidth,
|
||||
this._imageSize.y || subHeight,
|
||||
this._calculatedPos.x,
|
||||
this._calculatedPos.y,
|
||||
this.size.x || subWidth,
|
||||
this.size.y || subHeight
|
||||
);
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default Sprite;
|
@ -101,6 +101,11 @@ class Vector2D {
|
||||
}
|
||||
|
||||
|
||||
angle () {
|
||||
return Math.atan2(this.x, this.y);
|
||||
}
|
||||
|
||||
|
||||
toArray () {
|
||||
return [this.x, this.y];
|
||||
}
|
||||
@ -116,6 +121,11 @@ class Vector2D {
|
||||
}
|
||||
|
||||
|
||||
static fromAngle (angle, length) {
|
||||
return new Vector2D(length * Math.cos(angle), length * Math.sin(angle));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,20 +1,26 @@
|
||||
"use strict";
|
||||
|
||||
import Game from "./classes/game.js";
|
||||
import Emitter from "./classes/emitter.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 Color from "./classes/color.js";
|
||||
import ImageLoader from "./classes/imageloader.js";
|
||||
|
||||
import {KeyConsts} from "./classes/keyboardinput.js";
|
||||
|
||||
|
||||
const Classes = {
|
||||
Game: Game,
|
||||
Emitter: Emitter,
|
||||
Entity: Entity,
|
||||
Sprite: Sprite,
|
||||
Rect: Rect,
|
||||
Vector2D: Vector2D,
|
||||
Color: Color
|
||||
Color: Color,
|
||||
ImageLoader: ImageLoader
|
||||
};
|
||||
|
||||
|
||||
|
10
src/es6.js
10
src/es6.js
@ -1,20 +1,26 @@
|
||||
"use strict";
|
||||
|
||||
import Game from "./classes/game.js";
|
||||
import Emitter from "./classes/emitter.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 Color from "./classes/color.js";
|
||||
import ImageLoader from "./classes/imageloader.js";
|
||||
|
||||
import {KeyConsts} from "./classes/keyboardinput.js";
|
||||
|
||||
|
||||
const Classes = {
|
||||
Game: Game,
|
||||
Emitter: Emitter,
|
||||
Entity: Entity,
|
||||
Sprite: Sprite,
|
||||
Rect: Rect,
|
||||
Vector2D: Vector2D,
|
||||
Color: Color
|
||||
Color: Color,
|
||||
ImageLoader: ImageLoader
|
||||
};
|
||||
|
||||
|
||||
@ -25,7 +31,7 @@ const Consts = {
|
||||
};
|
||||
|
||||
|
||||
export {
|
||||
export default {
|
||||
Classes,
|
||||
Consts
|
||||
};
|
@ -1,5 +1,4 @@
|
||||
import Rect from "../classes/rect.js";
|
||||
import Vector2D from "../classes/vector2d.js";
|
||||
|
||||
class CollisionMethods {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user