Added image classes, new example (snowflakes)

This commit is contained in:
Nathan Kunicki 2015-12-22 18:08:33 +00:00
parent 2c88c9ce20
commit 18df8c17ec
15 changed files with 376 additions and 21 deletions

2
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

View File

@ -6,6 +6,6 @@
<script type="application/javascript" src="./pong.js"></script> <script type="application/javascript" src="./pong.js"></script>
</head> </head>
<body> <body>
<canvas id="game"></canvas> <canvas id="canvas"></canvas>
</body> </body>
</html> </html>

View File

@ -12,7 +12,7 @@ window.onload = function () {
var pong = new MomentumEngine.Classes.Game({ var pong = new MomentumEngine.Classes.Game({
canvas: document.getElementById("game"), canvas: document.getElementById("canvas"),
width: width, width: width,
height: height, height: height,
fixRatio: true, fixRatio: true,
@ -28,7 +28,7 @@ window.onload = function () {
black = new MomentumEngine.Classes.Color(0, 0, 0); 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), 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), 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), leftPaddle = new MomentumEngine.Classes.Rect(baseSize, baseSize, baseSize, baseSize * 7, white),
@ -81,7 +81,6 @@ window.onload = function () {
if (leftPaddle.isCollidingWith(ball) && ball.state.speed.x < 0) { if (leftPaddle.isCollidingWith(ball) && ball.state.speed.x < 0) {
ball.state.speed.x = -ball.state.speed.x; ball.state.speed.x = -ball.state.speed.x;
console.log(ball.state.speed.length());
} }
}; };
@ -111,8 +110,6 @@ window.onload = function () {
} }
}; };
pong.start(); pong.start();

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

116
examples/snowflakes/pong.js Normal file
View File

@ -0,0 +1,116 @@
"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("canvas"),
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 the ball position
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.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 () {
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.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 () {
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.isCollidingWith(ball) && ball.state.speed.x > 0) {
ball.state.speed.x = -ball.state.speed.x;
}
};
pong.start();
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

View File

@ -0,0 +1,67 @@
"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 () {
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 + (snowflakes.lastFrameDelta * 0.06);
};
mainScene.addChildEntity(newSnowflake);
mainScene.children.forEach((oldSnowflake) => {
if (oldSnowflake.pos.y > height) {
mainScene.detachChildEntity(oldSnowflake);
}
});
}
};
snowflakes.start();
};

View File

@ -1,3 +1,5 @@
"use strict";
class Color { class Color {

View File

@ -9,6 +9,7 @@ class Entity {
this.pos = new Vector2D(x || 0, y || 0); this.pos = new Vector2D(x || 0, y || 0);
this._ready = true;
this.state = {}; this.state = {};
this.children = []; this.children = [];
@ -44,22 +45,40 @@ class Entity {
} }
detachChildEntity (entity) { detachChildEntity (child) {
// Not implemented
for (var i = 0; i < this.children.length; i++) {
if (this.children[i] == child) {
this.children.splice(i, 1);
return true;
}
}
return false;
} }
_recalculatePos () { isReady () {
return this._ready;
}
// 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.
_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 _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. // 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._game && this._lastCalculated < this._game.frameCounter) {
if (this._parent) { if (this._parent) {
let parentPos = this._parent._recalculatePos(); let parentPos = this._parent._preprocess();
this._calculatedPos.x = this.pos.x + parentPos.x; this._calculatedPos.x = this.pos.x + parentPos.x;
this._calculatedPos.y = this.pos.y + parentPos.y; this._calculatedPos.y = this.pos.y + parentPos.y;
@ -91,9 +110,9 @@ class Entity {
_updateEntity () { _updateEntity () {
this._recalculatePos(); var updated = this.update && this.update();
if ((this.update && this.update()) || (typeof this.update === "undefined")) { if (this.isReady() && (updated || (typeof updated == "undefined") || (typeof this.update === "undefined"))) {
this.children.forEach((child) => { this.children.forEach((child) => {
child._updateEntity(); child._updateEntity();
@ -106,7 +125,11 @@ class Entity {
_renderEntity () { _renderEntity () {
if ((this.render && this.render()) || (typeof this.render === "undefined")) { this._preprocess();
var rendered = this.render && this.render();
if (this.isReady() && (rendered || (typeof rendered == "undefined") || (typeof this.render === "undefined"))) {
this.children.forEach((child) => { this.children.forEach((child) => {
child._renderEntity(); child._renderEntity();

View File

@ -17,19 +17,19 @@ class Game extends Entity {
if (config.canvas) { if (config.canvas) {
this.canvas = config.canvas; this.canvas = config.canvas;
} else { } 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) { if (config.width) {
this.width = config.width; this.width = config.width;
} else { } 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) { if (config.height) {
this.height = config.height; this.height = config.height;
} else { } else {
throw new Error("MomentumEngine.Game must be constructed with canvas height"); throw new Error("MomentumEngine.Classes.Game must be constructed with canvas height");
} }
@ -126,6 +126,7 @@ class Game extends Entity {
})(); })();
self._lastFrameTimestamp = +(new Date()); self._lastFrameTimestamp = +(new Date());
self.startTime = self._lastFrameTimestamp;
var loop = function () { var loop = function () {

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

78
src/classes/sprite.js Normal file
View 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 () { // Overrides super isReady
return (this._image.isLoaded() && !this._image.isError());
}
render () {
if (this.isReady()) {
var imageObj = this._image.getImageObj();
var 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;

View File

@ -3,8 +3,10 @@
import Game from "./classes/game.js"; import Game from "./classes/game.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 Rect from "./classes/rect.js"; import Rect from "./classes/rect.js";
import Color from "./classes/color.js"; import Color from "./classes/color.js";
import ImageLoader from "./classes/imageloader.js";
import {KeyConsts} from "./classes/keyboardinput.js"; import {KeyConsts} from "./classes/keyboardinput.js";
@ -12,9 +14,11 @@ import {KeyConsts} from "./classes/keyboardinput.js";
const Classes = { const Classes = {
Game: Game, Game: Game,
Entity: Entity, Entity: Entity,
Sprite: Sprite,
Rect: Rect, Rect: Rect,
Vector2D: Vector2D, Vector2D: Vector2D,
Color: Color Color: Color,
ImageLoader: ImageLoader
}; };

View File

@ -3,8 +3,10 @@
import Game from "./classes/game.js"; import Game from "./classes/game.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 Rect from "./classes/rect.js"; import Rect from "./classes/rect.js";
import Color from "./classes/color.js"; import Color from "./classes/color.js";
import ImageLoader from "./classes/imageloader.js";
import {KeyConsts} from "./classes/keyboardinput.js"; import {KeyConsts} from "./classes/keyboardinput.js";
@ -12,9 +14,11 @@ import {KeyConsts} from "./classes/keyboardinput.js";
const Classes = { const Classes = {
Game: Game, Game: Game,
Entity: Entity, Entity: Entity,
Sprite: Sprite,
Rect: Rect, Rect: Rect,
Vector2D: Vector2D, Vector2D: Vector2D,
Color: Color Color: Color,
ImageLoader: ImageLoader
}; };