First pass at particle system

This commit is contained in:
Nathan Kunicki 2016-02-13 16:32:26 +00:00
parent e620ff9c94
commit 9f53e28f35
15 changed files with 4963 additions and 19 deletions

2348
dist/es5.js vendored

File diff suppressed because one or more lines are too long

2
dist/es5.js.map vendored

File diff suppressed because one or more lines are too long

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

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View 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>

View File

@ -0,0 +1,45 @@
"use strict";
import MomentumEngine from "../../src/es6";
let white = new MomentumEngine.Classes.Color(255, 255, 255);
class BlueParticle extends MomentumEngine.Classes.Rect {
constructor (x, y) {
super(x, y, 1, 1, white);
}
}
window.onload = function () {
var width = 640,
height = 360,
baseSize = width / 64;
var particles = new MomentumEngine.Classes.Game({
canvas: document.getElementById("canvas"),
width: width,
height: height,
fixRatio: true,
desiredFps: 60
});
var black = new MomentumEngine.Classes.Color(0, 0, 0),
red = new MomentumEngine.Classes.Color(255, 0, 0);
var mainScene = new MomentumEngine.Classes.Rect(0, 0, width, height, black);
particles.addChildEntity(mainScene);
var rect = new MomentumEngine.Classes.Rect(width / 2 - baseSize, height / 2 - baseSize, baseSize * 2, baseSize * 2, red),
emitter = new MomentumEngine.Classes.Emitter(0, 0, new MomentumEngine.Classes.Vector2D(1, 1), BlueParticle);
mainScene.addChildEntity(rect);
rect.addChildEntity(emitter);
emitter.emitting = true;
particles.start();
};

View File

@ -26,7 +26,8 @@ var build = function (options, callback) {
webpack({ webpack({
entry: { 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, bail: !options.watch,
watch: options.watch, watch: options.watch,
@ -41,7 +42,8 @@ var build = function (options, callback) {
loader: "babel-loader", loader: "babel-loader",
test: /\.js$/, test: /\.js$/,
include: [ include: [
path.join(__dirname, "src") path.join(__dirname, "src"),
path.join(__dirname, "examples")
], ],
query: { query: {
plugins: ["transform-runtime"], 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) => { gulp.task("build-dev", (callback) => {
build({ build({
watch: false, watch: false,

View File

@ -12,15 +12,15 @@
"node": "^4.2.3" "node": "^4.2.3"
}, },
"devDependencies": { "devDependencies": {
"babel-core": "6.3.17", "babel-core": "6.5.2",
"babel-loader": "6.2.0", "babel-loader": "6.2.2",
"babel-plugin-transform-runtime": "6.3.13", "babel-plugin-transform-runtime": "6.5.2",
"babel-preset-es2015": "6.3.13", "babel-preset-es2015": "6.5.0",
"babel-preset-stage-0": "6.3.13", "babel-preset-stage-0": "6.5.0",
"babel-runtime": "6.3.19", "babel-runtime": "6.5.0",
"gulp": "3.9.0", "gulp": "3.9.1",
"gulp-util": "3.0.7", "gulp-util": "3.0.7",
"webpack": "1.12.9" "webpack": "1.12.13"
}, },
"dependencies": {} "dependencies": {}
} }

56
src/classes/emitter.js Normal file
View File

@ -0,0 +1,56 @@
"use strict";
import Entity from "./entity.js";
import Vector2D from "./vector2d.js";
class Emitter extends Entity {
constructor (x, y, velocity, particle) {
super(x, y);
this.particleVelocity = velocity;
this.particleClass = particle;
this.emitting = false;
this.particles = [];
this.spread = function () {
return Math.PI / 32;
}
}
_emit () {
if (this.emitting) {
let ParticleClass = this.particleClass;
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.pos.x, this.pos.y);
particle.velocity = velocity;
this.particles.push(particle);
this._parent.addChildEntity(particle);
}
}
update () {
this._emit();
}
}
export default Emitter;

View File

@ -8,6 +8,8 @@ class Entity {
constructor (x, y) { constructor (x, y) {
this.pos = new Vector2D(x || 0, y || 0); this.pos = new Vector2D(x || 0, y || 0);
this.velocity = new Vector2D(0, 0);
this.acceleration = new Vector2D(0, 0);
this.state = {}; this.state = {};
this.children = []; this.children = [];
@ -20,6 +22,30 @@ class Entity {
} }
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;
}
}
createChildEntity () { createChildEntity () {
let child = new Entity(); let child = new Entity();
@ -46,7 +72,7 @@ class Entity {
detachChildEntity (child) { detachChildEntity (child) {
for (var i = 0; i < this.children.length; i++) { for (let i = 0; i < this.children.length; i++) {
if (this.children[i] == child) { if (this.children[i] == child) {
this.children.splice(i, 1); this.children.splice(i, 1);
@ -104,7 +130,19 @@ class Entity {
_updateEntity (delta) { _updateEntity (delta) {
var updated = this.update && this.update(delta); // 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);
}
// If there's an update method, call it
let updated = this.update && this.update(delta);
if (updated || (typeof updated == "undefined") || (typeof this.update === "undefined")) { if (updated || (typeof updated == "undefined") || (typeof this.update === "undefined")) {
@ -121,7 +159,7 @@ class Entity {
this._preprocess(); this._preprocess();
var rendered = this.render && this.render(); let rendered = this.render && this.render();
if (rendered || (typeof rendered == "undefined") || (typeof this.render === "undefined")) { if (rendered || (typeof rendered == "undefined") || (typeof this.render === "undefined")) {

View File

@ -123,7 +123,7 @@ class Game extends Entity {
self._wantPause = false; self._wantPause = false;
var requestFrame = (() => { let requestFrame = (() => {
return (window.requestAnimationFrame || return (window.requestAnimationFrame ||
window.webkitRequestAnimationFrame || window.webkitRequestAnimationFrame ||

View File

@ -46,9 +46,9 @@ class Sprite extends Entity {
if (this.isReady() && this._game) { if (this.isReady() && this._game) {
var imageObj = this._image.getImageObj(); let imageObj = this._image.getImageObj();
var subWidth = imageObj.width - this._imagePos.x, let subWidth = imageObj.width - this._imagePos.x,
subHeight = imageObj.height - this._imagePos.y; subHeight = imageObj.height - this._imagePos.y;
this._game.context.drawImage( this._game.context.drawImage(

View File

@ -101,6 +101,11 @@ class Vector2D {
} }
angle () {
return Math.atan2(this.x, this.y);
}
toArray () { toArray () {
return [this.x, this.y]; 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));
}
} }

View File

@ -1,6 +1,7 @@
"use strict"; "use strict";
import Game from "./classes/game.js"; import Game from "./classes/game.js";
import Emitter from "./classes/emitter.js";
import Entity from "./classes/entity.js"; import Entity from "./classes/entity.js";
import Vector2D from "./classes/vector2d.js"; import Vector2D from "./classes/vector2d.js";
import Sprite from "./classes/sprite.js"; import Sprite from "./classes/sprite.js";
@ -13,6 +14,7 @@ import {KeyConsts} from "./classes/keyboardinput.js";
const Classes = { const Classes = {
Game: Game, Game: Game,
Emitter: Emitter,
Entity: Entity, Entity: Entity,
Sprite: Sprite, Sprite: Sprite,
Rect: Rect, Rect: Rect,

View File

@ -1,6 +1,7 @@
"use strict"; "use strict";
import Game from "./classes/game.js"; import Game from "./classes/game.js";
import Emitter from "./classes/emitter.js";
import Entity from "./classes/entity.js"; import Entity from "./classes/entity.js";
import Vector2D from "./classes/vector2d.js"; import Vector2D from "./classes/vector2d.js";
import Sprite from "./classes/sprite.js"; import Sprite from "./classes/sprite.js";
@ -13,6 +14,7 @@ import {KeyConsts} from "./classes/keyboardinput.js";
const Classes = { const Classes = {
Game: Game, Game: Game,
Emitter: Emitter,
Entity: Entity, Entity: Entity,
Sprite: Sprite, Sprite: Sprite,
Rect: Rect, Rect: Rect,
@ -29,7 +31,7 @@ const Consts = {
}; };
export { export default {
Classes, Classes,
Consts Consts
}; };