diff --git a/.gitignore b/.gitignore
index ccedfda..c4e7d9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
node_modules
-projects
\ No newline at end of file
+projects
+*.tgz
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..5fd0e36
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,4 @@
+node_modules
+projects
+*.tgz
+examples
\ No newline at end of file
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..0a39086
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,15 @@
+The ISC License
+
+Copyright (c) 2020 Arne van Iterson
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
index 4c38088..eb024ef 100644
--- a/README.md
+++ b/README.md
@@ -6,13 +6,7 @@ Me making games using HTML5 Games: Novice to Ninja by Sitepoint.
The projects here are very similar to those featured in the book, and it will take some time before I get to make my own game.
To try out asdf library and the projects for yourself, you need to:
-* Download node.js
-* Clone this repository
-* Go the the folder where you cloned this repository
-* Run `npm start` or run
-```bash
-node list.js --dir ./
-```
+* TODO
Releases will be featured on
[ARNweb Games](https://arnweb.nl/games/)
\ No newline at end of file
diff --git a/asdf/index.html b/asdf/index.html
deleted file mode 100644
index ade551b..0000000
--- a/asdf/index.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
- ASDF Framework
-
-
-
- ASDF JS Framework
- Nothing to browse here, just some shared files to make these games work.
-
-
-
\ No newline at end of file
diff --git a/asdf/index.js b/asdf/index.js
deleted file mode 100644
index c589f3d..0000000
--- a/asdf/index.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import Container from "./Container.js";
-import CanvasRenderer from "./renderer/CanvasRenderer.js";
-import Game from "./Game.js";
-
-import math from "./utilities/math.js";
-
-import KeyControls from "./controls/KeyControls.js";
-import MouseControls from "./controls/MouseControls.js";
-
-import Sprite from "./Sprite.js";
-import TileMap from "./TileMap.js";
-import TileMapXML from "./TileMapXML.js";
-import TileSprite from "./TileSprite.js";
-import TileSpriteXML from "./TileSpriteXML.js";
-import Text from "./Text.js";
-import Texture from "./Texture.js";
-
-import SpriteSheetXML from "./SpriteSheetXML.js";
-
-export default {
- CanvasRenderer,
- Container,
- Game,
- math,
- KeyControls,
- MouseControls,
- Sprite,
- TileMap,
- TileMapXML,
- TileSprite,
- SpriteSheetXML,
- TileSpriteXML,
- Text,
- Texture
-};
diff --git a/examples/lib-test/bundle.js b/examples/lib-test/bundle.js
new file mode 100644
index 0000000..241771f
--- /dev/null
+++ b/examples/lib-test/bundle.js
@@ -0,0 +1,545 @@
+(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i c !== child);
+ return child;
+ }
+
+ map(f) {
+ return this.children.map(f);
+ }
+
+ update(dt, t) {
+ this.children = this.children.filter(child => {
+ if (child.update) {
+ child.update(dt, t, this);
+ }
+ return child.dead ? false : true;
+ });
+ }
+}
+module.exports = Container;
+
+},{}],2:[function(require,module,exports){
+var Container = require("./Container"),
+ CanvasRenderer = require('./renderer/CanvasRenderer')
+;
+
+const STEP = 1 / 60;
+const FRAME_MAX = 5 * STEP;
+
+class Game {
+ constructor(w, h, pixelated, parent = "#board") {
+ this.w = w;
+ this.h = h;
+ this.renderer = new CanvasRenderer(w, h);
+ document.querySelector(parent).appendChild(this.renderer.view);
+
+ if (pixelated) {
+ this.renderer.setPixelated();
+ }
+
+ this.scene = new Container();
+ }
+
+ run(gameUpdate = () => { }) {
+ let dt = 0;
+ let last = 0;
+ const loop = ms => {
+ requestAnimationFrame(loop);
+
+ const t = ms / 1000;
+ dt = Math.min(t - last, FRAME_MAX);
+ last = t;
+
+ this.scene.update(dt, t);
+ gameUpdate(dt, t);
+ this.renderer.render(this.scene);
+ };
+ requestAnimationFrame(loop);
+ }
+}
+
+module.exports = Game;
+},{"./Container":1,"./renderer/CanvasRenderer":14}],3:[function(require,module,exports){
+class Sprite {
+ constructor(texture) {
+ this.texture = texture;
+ this.pos = { x: 0, y: 0 };
+ this.anchor = { x: 0, y: 0 };
+ this.scale = { x: 1, y: 1 };
+ this.rotation = 0;
+ }
+}
+module.exports = Sprite;
+
+},{}],4:[function(require,module,exports){
+class SpriteSheetXML {
+ constructor(url) {
+ this.array = [];
+ this.fetchXMLtoArray(url);
+ }
+
+ fetchXMLtoArray(url) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false);
+ xhr.send(null);
+
+ if (xhr.status === 200) {
+ var children = xhr.responseXML.children[0].children;
+ for (let index = 0; index < children.length; index++) {
+ const element = children[index];
+ this.array.push({
+ name: element.attributes.name.nodeValue,
+ x: element.attributes.x.nodeValue,
+ y: element.attributes.y.nodeValue,
+ width: element.attributes.width.nodeValue,
+ height: element.attributes.height.nodeValue
+ });
+ }
+ } else {
+ console.error('XML file cannot be loaded!')
+ }
+ }
+
+ findIndex(attribute, value) {
+ for (let index = 0; index < this.array.length; index++) {
+ const element = this.array[index];
+ if (element[attribute] == value) {
+ return index;
+ }
+ }
+ }
+}
+
+module.exports = SpriteSheetXML;
+},{}],5:[function(require,module,exports){
+class Text {
+ constructor(text = "", style = {}) {
+ this.pos = { x: 0, y: 0 };
+ this.text = text;
+ this.style = style;
+ }
+}
+module.exports = Text;
+
+},{}],6:[function(require,module,exports){
+class Texture {
+ constructor(url) {
+ this.img = new Image();
+ this.img.src = url;
+ }
+}
+module.exports = Texture;
+
+},{}],7:[function(require,module,exports){
+var Container = require("./Container"),
+ TileSprite = require("./TileSprite")
+;
+
+class TileMap extends Container {
+ constructor(tiles, mapW, mapH, tileW, tileH, texture) {
+ super();
+ this.mapW = mapW;
+ this.mapH = mapH;
+ this.tileW = tileW;
+ this.tileH = tileH;
+ this.w = mapW * tileW;
+ this.h = mapH * tileH;
+
+ this.children = tiles.map((frame, i) => {
+ const s = new TileSprite(texture, tileW, tileH);
+ s.frame = frame;
+ s.pos.x = i % mapW * tileW;
+ s.pos.y = Math.floor(i / mapW) * tileH;
+ return s;
+ });
+ }
+}
+
+module.exports = TileMap;
+},{"./Container":1,"./TileSprite":9}],8:[function(require,module,exports){
+var Container = require("./Container"),
+ TileSpriteXML = require("./TileSpriteXML")
+;
+
+class TileMapXML extends Container {
+ constructor(tiles, mapW, mapH, texture, xml) {
+ super(texture);
+ this.mapW = mapW;
+ this.mapH = mapH;
+ this.tileW = xml.array[tiles[0]].width;
+ this.tileH = xml.array[tiles[0]].height;
+ this.w = mapW * this.tileW;
+ this.h = mapH * this.tileH;
+
+ this.children = tiles.map((frame, i) => {
+ const s = new TileSpriteXML(texture, xml, frame);
+ s.frame = frame;
+ s.pos.x = i % mapW * this.tileW;
+ s.pos.y = Math.floor(i / mapW) * this.tileH;
+ return s;
+ });
+ }
+}
+
+module.exports = TileMapXML;
+},{"./Container":1,"./TileSpriteXML":10}],9:[function(require,module,exports){
+var Sprite = require("./Sprite");
+
+class TileSprite extends Sprite {
+ constructor(texture, w, h) {
+ super(texture);
+ this.tileW = w;
+ this.tileH = h;
+ this.frame = { x: 0, y: 0 };
+ }
+}
+
+module.exports = TileSprite;
+},{"./Sprite":3}],10:[function(require,module,exports){
+var Sprite = require("./Sprite");
+
+class TileSpriteXML extends Sprite {
+ constructor(texture, xml, index) {
+ super(texture);
+ var src = xml.array[index];
+ this.imgPos = { x: src['x'], y: src['y'] };
+ this.width = src['width'];
+ this.height = src['height'];
+ }
+}
+
+module.exports = TileSpriteXML;
+},{"./Sprite":3}],11:[function(require,module,exports){
+class KeyControls {
+
+ constructor() {
+ this.keys = {};
+ // Bind event handlers
+ document.addEventListener("keydown", e => {
+ if ([37, 38, 39, 40].indexOf(e.which) >= 0) {
+ e.preventDefault();
+ }
+ this.keys[e.which] = true;
+ }, false);
+ document.addEventListener('keyup', e => {
+ this.keys[e.which] = false;
+ }, false);
+ }
+
+ get action() {
+ // Spacebar
+ return this.keys[32];
+ }
+
+ get x() {
+ // Arrow Left or A (WASD)
+ if (this.keys[37] || this.keys[65]) {
+ return -1;
+ }
+ // Arrow Right or D (WASD)
+ if (this.keys[39] || this.keys[68]) {
+ return 1;
+ }
+ return 0;
+ }
+
+ get y() {
+ // Arrow Up or W (WASD)
+ if (this.keys[38] || this.keys[87]) {
+ return -1;
+ }
+ // Arrow Down or S (WASD)
+ if (this.keys[40] || this.keys[83]) {
+ return 1;
+ }
+ return 0;
+ }
+
+
+ key(key, value) {
+ if (value !== undefined) {
+ this.keys[key] = value;
+ }
+ return this.keys[key];
+ }
+
+ reset() {
+ for (let key in this.keys) {
+ this.keys[key] = false;
+ }
+ }
+
+}
+
+module.exports = KeyControls;
+
+},{}],12:[function(require,module,exports){
+class MouseControls {
+ constructor(container) {
+ this.el = container || document.body;
+ // State
+ this.pos = { x: 0, y: 0 };
+ this.isDown = false;
+ this.pressed = false;
+ this.released = false;
+ // Handlers
+ document.addEventListener('mousemove', this.move.bind(this), false);
+ document.addEventListener('mousedown', this.down.bind(this), false);
+ document.addEventListener('mouseup', this.up.bind(this), false);
+ }
+
+ mousePosFromEvent({ clientX, clientY }) {
+ const { el, pos } = this;
+ const rect = el.getBoundingClientRect();
+ const xr = el.width / el.clientWidth;
+ const yr = el.height / el.clientHeight;
+ pos.x = (clientX - rect.left) * xr;
+ pos.y = (clientY - rect.top) * yr;
+ }
+
+ move(e) {
+ this.mousePosFromEvent(e);
+ }
+
+ down(e) {
+ this.isDown = true;
+ this.pressed = true;
+ this.mousePosFromEvent(e);
+ }
+
+ up() {
+ this.isDown = false;
+ this.released = true;
+ }
+
+ update() {
+ this.released = false;
+ this.pressed = false;
+ }
+}
+
+module.exports = MouseControls;
+
+},{}],13:[function(require,module,exports){
+var Container = require("./Container.js"),
+ CanvasRenderer = require("./renderer/CanvasRenderer.js"),
+ Game = require("./Game.js"),
+ math = require("./utilities/math.js"),
+ KeyControls = require("./controls/KeyControls.js"),
+ MouseControls = require("./controls/MouseControls.js"),
+ Sprite = require("./Sprite.js"),
+ TileMap = require("./TileMap.js"),
+ TileMapXML = require("./TileMapXML.js"),
+ TileSprite = require("./TileSprite.js"),
+ TileSpriteXML = require("./TileSpriteXML.js"),
+ Text = require("./Text.js"),
+ Texture = require("./Texture.js"),
+ SpriteSheetXML = require("./SpriteSheetXML.js")
+;
+
+module.exports = {
+ CanvasRenderer,
+ Container,
+ Game,
+ math,
+ KeyControls,
+ MouseControls,
+ Sprite,
+ TileMap,
+ TileMapXML,
+ TileSprite,
+ SpriteSheetXML,
+ TileSpriteXML,
+ Text,
+ Texture
+};
+
+},{"./Container.js":1,"./Game.js":2,"./Sprite.js":3,"./SpriteSheetXML.js":4,"./Text.js":5,"./Texture.js":6,"./TileMap.js":7,"./TileMapXML.js":8,"./TileSprite.js":9,"./TileSpriteXML.js":10,"./controls/KeyControls.js":11,"./controls/MouseControls.js":12,"./renderer/CanvasRenderer.js":14,"./utilities/math.js":15}],14:[function(require,module,exports){
+class CanvasRenderer {
+
+ constructor(w, h) {
+ const canvas = document.createElement("canvas");
+ this.w = canvas.width = w;
+ this.h = canvas.height = h;
+ this.view = canvas;
+ this.ctx = canvas.getContext("2d");
+ this.ctx.textBaseLine = "top";
+ }
+
+ setPixelated() {
+ this.ctx['imageSmoothingEnabled'] = false; /* standard */
+ this.ctx['mozImageSmoothingEnabled'] = false; /* Firefox */
+ this.ctx['oImageSmoothingEnabled'] = false; /* Opera */
+ this.ctx['webkitImageSmoothingEnabled'] = false; /* Safari */
+ this.ctx['msImageSmoothingEnabled'] = false; /* IE */
+ }
+
+ render(container, clear = true) {
+ const { ctx } = this;
+ function renderRec(container) {
+ // Render container children
+ container.children.forEach(child => {
+ if (child.visible == false) {
+ return;
+ }
+
+ ctx.save();
+
+ if (child.pos) {
+ ctx.translate(Math.round(child.pos.x), Math.round(child.pos.y));
+ }
+
+ if (child.anchor) {
+ ctx.translate(child.anchor.x, child.anchor.y);
+ }
+
+ if (child.scale) {
+ ctx.scale(child.scale.x, child.scale.y);
+ }
+
+ if (child.rotation) {
+ const px = child.pivot ? child.pivot.x : 0;
+ const py = child.pivot ? child.pivot.y : 0;
+ ctx.translate(px, py);
+ ctx.rotate(child.rotation);
+ ctx.translate(-px, -py);
+ }
+
+ if (child.text) {
+ const { font, fill, align } = child.style;
+ if (font) ctx.font = font;
+ if (fill) ctx.fillStyle = fill;
+ if (align) ctx.textAlign = align;
+ ctx.fillText(child.text, 0, 0);
+ }
+
+ else if (child.texture) {
+ const img = child.texture.img;
+ if (child.tileW && child.tileH) {
+ ctx.drawImage(
+ img,
+ child.frame.x * child.tileW,
+ child.frame.y * child.tileH,
+ child.tileW, child.tileH,
+ 0, 0,
+ child.tileW, child.tileH
+ );
+ } else if (child.imgPos && child.width && child.height) {
+ ctx.drawImage(
+ img,
+ child.imgPos.x,
+ child.imgPos.y,
+ child.width, child.height,
+ 0, 0,
+ child.width, child.height
+ );
+ } else {
+ ctx.drawImage(img, 0, 0);
+ }
+ }
+
+ // Handle children with children
+ if (child.children) {
+ renderRec(child);
+ }
+ ctx.restore();
+ })
+ }
+ if (clear) {
+ ctx.clearRect(0, 0, this.w, this.h);
+ }
+ renderRec(container);
+ }
+}
+module.exports = CanvasRenderer;
+
+},{}],15:[function(require,module,exports){
+function rand(min, max) {
+ return Math.floor(randf(min, max));
+}
+
+function randf(min, max) {
+ if (max == null) {
+ max = min || 1;
+ min = 0;
+ }
+ return Math.random() * (max - min) + min;
+}
+
+function randOneFrom(items) {
+ return items[rand(items.length)];
+}
+
+function randOneIn(max = 2) {
+ return rand(0, max) === 0;
+}
+
+module.exports = {
+ rand,
+ randf,
+ randOneFrom,
+ randOneIn
+};
+},{}],16:[function(require,module,exports){
+var asdf = require("../../../asdf/index");
+const { Game, Container, CanvasRenderer, math, KeyControls, MouseControls, Text, Texture, Sprite } = asdf;
+
+const game = new Game(640, 320, false);
+const { scene, w, h } = game;
+
+const buildings = scene.add(new Container());
+const makeRandom = (b, x) => {
+ b.scale.x = math.randf(1,3);
+ b.scale.y = math.randf(1,3);
+ b.pos.x = x;
+ b.pos.y = h - b.scale.y * 64;
+};
+
+for (let x = 0; x < 50; x++) {
+ const b = buildings.add(new Sprite(new Texture("res/images/building.png")));
+ makeRandom(b, math.rand(w));
+}
+
+var rotation = 0;
+const ship = new Sprite(new Texture("res/images/spaceship.png"));
+ship.pivot = { x: 16, y: 16 };
+scene.add(ship);
+
+
+game.run((dt ,t) => {
+ ship.update = function(dt, t) {
+ const {scale} = this;
+ scale.x = Math.abs(Math.sin(t)) + 1;
+ scale.y = Math.abs(Math.sin(t)) + 1;
+
+ rotation = rotation + 0.2;
+ ship.rotation = rotation;
+
+ ship.pos.y = (Math.abs(Math.sin(t))) * 50 + (h / 2) - 16;
+ ship.pos.x += dt * 50;
+ if (ship.pos.x > w) {
+ ship.pos.x = -32;
+ }
+ }
+
+ buildings.map(b => {
+ b.pos.x -= 100 * dt;
+ if (b.pos.x < -80) {
+ makeRandom(b,w);
+ }
+ });
+});
+
+},{"../../../asdf/index":13}]},{},[16]);
diff --git a/examples/lib-test/index.html b/examples/lib-test/index.html
index 99632cd..f79df8f 100644
--- a/examples/lib-test/index.html
+++ b/examples/lib-test/index.html
@@ -8,6 +8,6 @@
-
+