Compare commits
No commits in common. "master" and "1.0.0" have entirely different histories.
@ -1,2 +0,0 @@
|
|||||||
projects
|
|
||||||
examples
|
|
33
.eslintrc.js
33
.eslintrc.js
@ -1,33 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"commonjs": true,
|
|
||||||
"es6": true
|
|
||||||
},
|
|
||||||
"extends": "eslint:recommended",
|
|
||||||
"globals": {
|
|
||||||
"Atomics": "readonly",
|
|
||||||
"SharedArrayBuffer": "readonly"
|
|
||||||
},
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2018
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"indent": [
|
|
||||||
"error",
|
|
||||||
"tab"
|
|
||||||
],
|
|
||||||
"linebreak-style": [
|
|
||||||
"error",
|
|
||||||
"unix"
|
|
||||||
],
|
|
||||||
"quotes": [
|
|
||||||
"error",
|
|
||||||
"double"
|
|
||||||
],
|
|
||||||
"semi": [
|
|
||||||
"error",
|
|
||||||
"always"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
48
README.md
48
README.md
@ -1,48 +1,12 @@
|
|||||||
![asdf-games](https://gitea.arnweb.nl/arne/asdf-games/raw/branch/master/res/asdf-logo.png "asdf-games logo")
|
|
||||||
# asdf-games
|
# asdf-games
|
||||||
|
|
||||||
My attempt at making the framework featured in the book HTML5 Games: Novice to Ninja.
|
Me making games using HTML5 Games: Novice to Ninja by Sitepoint.
|
||||||
[You can find the book here.](https://www.sitepoint.com/premium/books/html5-games-novice-to-ninja)
|
[You can find the book here.](https://www.sitepoint.com/premium/books/html5-games-novice-to-ninja)
|
||||||
|
|
||||||
I turned the framework featured in the book into an npm package for use with browserify or Electron.
|
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.
|
||||||
If you are on Github or Gitea now, you can find the npm package [here](https://www.npmjs.com/package/asdf-games).
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
To use asdf framework in your projects, you need to:
|
|
||||||
* Install npm on your device (if you don't have it already)
|
|
||||||
* Run ```npm install asdf-games```
|
|
||||||
* Use the snippet below to start off or check out one of the examples, keep in mind that the examples are not comepletely up to date.
|
|
||||||
* Thanks to my friend [Job](https://jobbel.nl/), this project supports TypeScript typings. Make sure your editor supports them to make your life easier.
|
|
||||||
|
|
||||||
|
|
||||||
## Example usage
|
|
||||||
```javascript
|
|
||||||
// Require asdf
|
|
||||||
const asdf = require("asdf-games");
|
|
||||||
|
|
||||||
// Add whatever classes you need here
|
|
||||||
const [ Game, Sprite, Texture, KeyControls ] = asdf;
|
|
||||||
|
|
||||||
// Game(width, height, disable pixel smoothening)
|
|
||||||
var game = new Game(720, 480, true);
|
|
||||||
|
|
||||||
// Any picture URL used in new Texture() must be relative to the location of the HTML file
|
|
||||||
const playerTexture = new Texture('player.png');
|
|
||||||
|
|
||||||
var player = new Sprite(texture);
|
|
||||||
player.pos = {
|
|
||||||
x: (game.w / 2) - (player.w / 2),
|
|
||||||
y: (game.h / 2) - (player.h / 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add your entities to the game's scene
|
|
||||||
game.scene.add(player);
|
|
||||||
|
|
||||||
game.run(() => {
|
|
||||||
// Game loop
|
|
||||||
});
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
To try out asdf library and the projects for yourself, you need to:
|
||||||
|
* TODO
|
||||||
|
|
||||||
|
Releases will be featured on
|
||||||
|
[ARNweb Games](https://arnweb.nl/games/)
|
@ -1,65 +0,0 @@
|
|||||||
class Anim {
|
|
||||||
constructor(frames, rate) {
|
|
||||||
this.frames = frames;
|
|
||||||
this.rate = rate;
|
|
||||||
this.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.frame = this.frames[0];
|
|
||||||
this.curFrame = 0;
|
|
||||||
this.curTime = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(dt) {
|
|
||||||
const { rate, frames } = this;
|
|
||||||
if ((this.curTime += dt) > rate) {
|
|
||||||
this.curFrame++;
|
|
||||||
this.frame = frames[this.curFrame % frames.length];
|
|
||||||
this.curTime -= rate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AnimManager {
|
|
||||||
constructor(e = { x: 0, y: 0 }) {
|
|
||||||
this.anims = {};
|
|
||||||
this.running = false;
|
|
||||||
this.frameSource = e.frame || e;
|
|
||||||
this.current = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
add(name, frames, speed) {
|
|
||||||
this.anims[name] = new Anim(frames, speed);
|
|
||||||
return this.anims[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
update(dt) {
|
|
||||||
const { current, anims, frameSource } = this;
|
|
||||||
if (!current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const anim = anims[current];
|
|
||||||
anim.update(dt);
|
|
||||||
|
|
||||||
// Sync the tileSprite frame
|
|
||||||
frameSource.x = anim.frame.x;
|
|
||||||
frameSource.y = anim.frame.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
play(anim) {
|
|
||||||
const { current, anims } = this;
|
|
||||||
if (anim === current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.current = anim;
|
|
||||||
anims[anim].reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
this.current = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = AnimManager;
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
|||||||
const Container = require("./Container");
|
|
||||||
const math = require("./utilities/math");
|
|
||||||
|
|
||||||
class Camera extends Container {
|
|
||||||
constructor(subject, viewport, worldSize = viewport) {
|
|
||||||
super();
|
|
||||||
this.w = viewport.w;
|
|
||||||
this.h = viewport.h;
|
|
||||||
this.worldSize = worldSize;
|
|
||||||
this.setSubject(subject);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSubject(e) {
|
|
||||||
this.subject = e ? e.pos || e : this.pos;
|
|
||||||
this.offset = { x: 0, y: 0 };
|
|
||||||
|
|
||||||
// Center on the entity
|
|
||||||
if (e && e.w) {
|
|
||||||
this.offset.x += e.w / 2;
|
|
||||||
this.offset.y += e.h / 2;
|
|
||||||
}
|
|
||||||
if (e && e.anchor) {
|
|
||||||
this.offset.x -= e.anchor.x;
|
|
||||||
this.offset.y -= e.anchor.y;
|
|
||||||
}
|
|
||||||
this.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
focus() {
|
|
||||||
const { pos, w, h, worldSize, subject, offset } = this;
|
|
||||||
|
|
||||||
const centeredX = subject.x + offset.x - w / 2;
|
|
||||||
const maxX = worldSize.w - w;
|
|
||||||
const x = -math.clamp(centeredX, 0, maxX);
|
|
||||||
|
|
||||||
const centeredY = subject.y + offset.y - h / 2;
|
|
||||||
const maxY = worldSize.h - h;
|
|
||||||
const y = -math.clamp(centeredY, 0, maxY);
|
|
||||||
|
|
||||||
pos.x = x;
|
|
||||||
pos.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(dt, t) {
|
|
||||||
super.update(dt, t);
|
|
||||||
|
|
||||||
if (this.subject) {
|
|
||||||
this.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = Camera;
|
|
@ -1,30 +1,30 @@
|
|||||||
class Container {
|
class Container {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.pos = { x: 0, y: 0 };
|
this.pos = { x: 0, y: 0 };
|
||||||
this.children = [];
|
this.children = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
add(child) {
|
add(child) {
|
||||||
this.children.push(child);
|
this.children.push(child);
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(child) {
|
remove(child) {
|
||||||
this.children = this.children.filter(c => c !== child);
|
this.children = this.children.filter(c => c !== child);
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
map(f) {
|
map(f) {
|
||||||
return this.children.map(f);
|
return this.children.map(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(dt, t) {
|
update(dt, t) {
|
||||||
this.children = this.children.filter(child => {
|
this.children = this.children.filter(child => {
|
||||||
if (child.update) {
|
if (child.update) {
|
||||||
child.update(dt, t, this);
|
child.update(dt, t, this);
|
||||||
}
|
}
|
||||||
return child.dead ? false : true;
|
return child.dead ? false : true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = Container;
|
module.exports = Container;
|
||||||
|
53
lib/Game.js
53
lib/Game.js
@ -1,43 +1,40 @@
|
|||||||
var Container = require("./Container"),
|
var Container = require("./Container"),
|
||||||
CanvasRenderer = require("./renderer/CanvasRenderer")
|
CanvasRenderer = require('./renderer/CanvasRenderer')
|
||||||
;
|
;
|
||||||
|
|
||||||
const STEP = 1 / 60;
|
const STEP = 1 / 60;
|
||||||
const FRAME_MAX = 5 * STEP;
|
const FRAME_MAX = 5 * STEP;
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
constructor(w, h, pixelated, parent = "#board") {
|
constructor(w, h, pixelated, parent = "#board") {
|
||||||
this.w = w;
|
this.w = w;
|
||||||
this.h = h;
|
this.h = h;
|
||||||
this.renderer = new CanvasRenderer(w, h);
|
this.renderer = new CanvasRenderer(w, h);
|
||||||
document.querySelector(parent).appendChild(this.renderer.view);
|
document.querySelector(parent).appendChild(this.renderer.view);
|
||||||
|
|
||||||
if (pixelated) {
|
if (pixelated) {
|
||||||
this.renderer.setPixelated();
|
this.renderer.setPixelated();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scene = new Container();
|
this.scene = new Container();
|
||||||
this.paused = false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
run(gameUpdate = () => { }) {
|
run(gameUpdate = () => { }) {
|
||||||
let dt = 0;
|
let dt = 0;
|
||||||
let last = 0;
|
let last = 0;
|
||||||
const loop = ms => {
|
const loop = ms => {
|
||||||
requestAnimationFrame(loop);
|
requestAnimationFrame(loop);
|
||||||
|
|
||||||
const t = ms / 1000;
|
const t = ms / 1000;
|
||||||
dt = Math.min(t - last, FRAME_MAX);
|
dt = Math.min(t - last, FRAME_MAX);
|
||||||
last = t;
|
last = t;
|
||||||
|
|
||||||
if (!this.paused) {
|
this.scene.update(dt, t);
|
||||||
this.scene.update(dt, t);
|
gameUpdate(dt, t);
|
||||||
gameUpdate(dt, t);
|
this.renderer.render(this.scene);
|
||||||
this.renderer.render(this.scene);
|
};
|
||||||
}
|
requestAnimationFrame(loop);
|
||||||
};
|
}
|
||||||
requestAnimationFrame(loop);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Game;
|
module.exports = Game;
|
@ -1,9 +0,0 @@
|
|||||||
class Line {
|
|
||||||
constructor(x1, y1, x2, y2, style = "#000000") {
|
|
||||||
this.pos = { x: x1, y: y1 };
|
|
||||||
this.target = { x: x2, y: y2 };
|
|
||||||
this.style = style;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Line;
|
|
10
lib/Rect.js
10
lib/Rect.js
@ -1,10 +0,0 @@
|
|||||||
class Rect {
|
|
||||||
constructor(w, h, style = { fill: "#333" }) {
|
|
||||||
this.pos = { x: 0, y: 0 };
|
|
||||||
this.w = w;
|
|
||||||
this.h = h;
|
|
||||||
this.style = style;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Rect;
|
|
@ -1,11 +1,10 @@
|
|||||||
class Sprite {
|
class Sprite {
|
||||||
constructor(texture) {
|
constructor(texture) {
|
||||||
this.texture = texture;
|
this.texture = texture;
|
||||||
this.pos = { x: 0, y: 0 };
|
this.pos = { x: 0, y: 0 };
|
||||||
this.anchor = { x: 0, y: 0 };
|
this.anchor = { x: 0, y: 0 };
|
||||||
this.scale = { x: 1, y: 1 };
|
this.scale = { x: 1, y: 1 };
|
||||||
this.pivot = { x: 0, y: 0 };
|
this.rotation = 0;
|
||||||
this.rotation = 0;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
module.exports = Sprite;
|
module.exports = Sprite;
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
class SpriteSheetXML {
|
class SpriteSheetXML {
|
||||||
constructor(url) {
|
constructor(url) {
|
||||||
this.array = [];
|
this.array = [];
|
||||||
this.fetchXMLtoArray(url);
|
this.fetchXMLtoArray(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchXMLtoArray(url) {
|
fetchXMLtoArray(url) {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open("GET", url, false);
|
xhr.open('GET', url, false);
|
||||||
xhr.send(null);
|
xhr.send(null);
|
||||||
|
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
var children = xhr.responseXML.children[0].children;
|
var children = xhr.responseXML.children[0].children;
|
||||||
for (let index = 0; index < children.length; index++) {
|
for (let index = 0; index < children.length; index++) {
|
||||||
const element = children[index];
|
const element = children[index];
|
||||||
this.array.push({
|
this.array.push({
|
||||||
name: element.attributes.name.nodeValue,
|
name: element.attributes.name.nodeValue,
|
||||||
x: element.attributes.x.nodeValue,
|
x: element.attributes.x.nodeValue,
|
||||||
y: element.attributes.y.nodeValue,
|
y: element.attributes.y.nodeValue,
|
||||||
width: element.attributes.width.nodeValue,
|
width: element.attributes.width.nodeValue,
|
||||||
height: element.attributes.height.nodeValue
|
height: element.attributes.height.nodeValue
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error("XML file cannot be loaded!");
|
console.error('XML file cannot be loaded!')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findIndex(attribute, value) {
|
findIndex(attribute, value) {
|
||||||
for (let index = 0; index < this.array.length; index++) {
|
for (let index = 0; index < this.array.length; index++) {
|
||||||
const element = this.array[index];
|
const element = this.array[index];
|
||||||
if (element[attribute] == value) {
|
if (element[attribute] == value) {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = SpriteSheetXML;
|
module.exports = SpriteSheetXML;
|
29
lib/State.js
29
lib/State.js
@ -1,29 +0,0 @@
|
|||||||
class State {
|
|
||||||
constructor(state) {
|
|
||||||
this.set(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
set(state) {
|
|
||||||
this.last = this.state;
|
|
||||||
this.state = state;
|
|
||||||
this.time = 0;
|
|
||||||
this.justSetState = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(dt) {
|
|
||||||
this.first = this.justSetState;
|
|
||||||
this.justSetStrate = false;
|
|
||||||
|
|
||||||
this.time += this.first ? 0 : dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
is(state) {
|
|
||||||
return this.state === state;
|
|
||||||
}
|
|
||||||
|
|
||||||
isIn(...states) {
|
|
||||||
return states.some(s => this.is(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = State;
|
|
10
lib/Text.js
10
lib/Text.js
@ -1,8 +1,8 @@
|
|||||||
class Text {
|
class Text {
|
||||||
constructor(text = "", style = {}) {
|
constructor(text = "", style = {}) {
|
||||||
this.pos = { x: 0, y: 0 };
|
this.pos = { x: 0, y: 0 };
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.style = style;
|
this.style = style;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = Text;
|
module.exports = Text;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
class Texture {
|
class Texture {
|
||||||
constructor(url) {
|
constructor(url) {
|
||||||
this.img = new Image();
|
this.img = new Image();
|
||||||
this.img.src = url;
|
this.img.src = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = Texture;
|
module.exports = Texture;
|
||||||
|
@ -1,73 +1,25 @@
|
|||||||
var Container = require("./Container"),
|
var Container = require("./Container"),
|
||||||
TileSprite = require("./TileSprite")
|
TileSprite = require("./TileSprite")
|
||||||
;
|
;
|
||||||
|
|
||||||
class TileMap extends Container {
|
class TileMap extends Container {
|
||||||
constructor(tiles, mapW, mapH, tileW, tileH, texture) {
|
constructor(tiles, mapW, mapH, tileW, tileH, texture) {
|
||||||
super();
|
super();
|
||||||
this.mapW = mapW;
|
this.mapW = mapW;
|
||||||
this.mapH = mapH;
|
this.mapH = mapH;
|
||||||
this.tileW = tileW;
|
this.tileW = tileW;
|
||||||
this.tileH = tileH;
|
this.tileH = tileH;
|
||||||
this.w = mapW * tileW;
|
this.w = mapW * tileW;
|
||||||
this.h = mapH * tileH;
|
this.h = mapH * tileH;
|
||||||
|
|
||||||
this.children = tiles.map((frame, i) => {
|
this.children = tiles.map((frame, i) => {
|
||||||
const s = new TileSprite(texture, tileW, tileH);
|
const s = new TileSprite(texture, tileW, tileH);
|
||||||
s.frame = frame;
|
s.frame = frame;
|
||||||
s.pos.x = i % mapW * tileW;
|
s.pos.x = i % mapW * tileW;
|
||||||
s.pos.y = Math.floor(i / mapW) * tileH;
|
s.pos.y = Math.floor(i / mapW) * tileH;
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pixelToMapPos(pos) {
|
|
||||||
const { tileW, tileH } = this;
|
|
||||||
return {
|
|
||||||
x: Math.floor(pos.x / tileW),
|
|
||||||
y: Math.floor(pos.y / tileH)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
mapToPixelPos(mapPos) {
|
|
||||||
const { tileW, tileH } = this;
|
|
||||||
return {
|
|
||||||
x: mapPos.x * tileW,
|
|
||||||
y: mapPos.y * tileH
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
tileAtMapPos(mapPos) {
|
|
||||||
return this.children[mapPos.y * this.mapW + mapPos.x];
|
|
||||||
}
|
|
||||||
|
|
||||||
tileAtPixelPos(pos) {
|
|
||||||
return this.tileAtMapPos(this.pixelToMapPos(pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
setFrameAtMapPos(mapPos, frame) {
|
|
||||||
const tile = this.tileAtMapPos(mapPos);
|
|
||||||
tile.frame = frame;
|
|
||||||
return tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
setFrameAtPixelPos(pos, frame) {
|
|
||||||
return this.setFrameAtMapPos(this.pixelToMapPos(pos), frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
tilesAtCorners(bounds, xo = 0, yo = 0) {
|
|
||||||
return [
|
|
||||||
[bounds.x, bounds.y], // Top-left
|
|
||||||
[bounds.x + bounds.w, bounds.y], // Top-right
|
|
||||||
[bounds.x, bounds.y + bounds.h], // Bottom-left
|
|
||||||
[bounds.x + bounds.w, bounds.y + bounds.h] // Bottom-right
|
|
||||||
].map(([x, y]) =>
|
|
||||||
this.tileAtPixelPos({
|
|
||||||
x: x + xo,
|
|
||||||
y: y + yo
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TileMap;
|
module.exports = TileMap;
|
@ -1,73 +1,25 @@
|
|||||||
var Container = require("./Container"),
|
var Container = require("./Container"),
|
||||||
TileSpriteXML = require("./TileSpriteXML")
|
TileSpriteXML = require("./TileSpriteXML")
|
||||||
;
|
;
|
||||||
|
|
||||||
class TileMapXML extends Container {
|
class TileMapXML extends Container {
|
||||||
constructor(tiles, mapW, mapH, texture, xml) {
|
constructor(tiles, mapW, mapH, texture, xml) {
|
||||||
super(texture);
|
super(texture);
|
||||||
this.mapW = mapW;
|
this.mapW = mapW;
|
||||||
this.mapH = mapH;
|
this.mapH = mapH;
|
||||||
this.tileW = xml.array[tiles[0]].width;
|
this.tileW = xml.array[tiles[0]].width;
|
||||||
this.tileH = xml.array[tiles[0]].height;
|
this.tileH = xml.array[tiles[0]].height;
|
||||||
this.w = mapW * this.tileW;
|
this.w = mapW * this.tileW;
|
||||||
this.h = mapH * this.tileH;
|
this.h = mapH * this.tileH;
|
||||||
|
|
||||||
this.children = tiles.map((frame, i) => {
|
this.children = tiles.map((frame, i) => {
|
||||||
const s = new TileSpriteXML(texture, xml, frame);
|
const s = new TileSpriteXML(texture, xml, frame);
|
||||||
s.frame = frame;
|
s.frame = frame;
|
||||||
s.pos.x = i % mapW * this.tileW;
|
s.pos.x = i % mapW * this.tileW;
|
||||||
s.pos.y = Math.floor(i / mapW) * this.tileH;
|
s.pos.y = Math.floor(i / mapW) * this.tileH;
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pixelToMapPos(pos) {
|
|
||||||
const { tileW, tileH } = this;
|
|
||||||
return {
|
|
||||||
x: Math.floor(pos.x / tileW),
|
|
||||||
y: Math.floor(pos.y / tileH)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
mapToPixelPos(mapPos) {
|
|
||||||
const { tileW, tileH } = this;
|
|
||||||
return {
|
|
||||||
x: mapPos.x * tileW,
|
|
||||||
y: mapPos.y * tileH
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
tileAtMapPos(mapPos) {
|
|
||||||
return this.children[mapPos.y * this.mapW + mapPos.x];
|
|
||||||
}
|
|
||||||
|
|
||||||
tileAtPixelPos(pos) {
|
|
||||||
return this.tileAtMapPos(this.pixelToMapPos(pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
setFrameAtMapPos(mapPos, frame) {
|
|
||||||
const tile = this.tileAtMapPos(mapPos);
|
|
||||||
tile.frame = frame;
|
|
||||||
return tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
setFrameAtPixelPos(pos, frame) {
|
|
||||||
return this.setFrameAtMapPos(this.pixelToMapPos(pos), frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
tilesAtCorners(bounds, xo = 0, yo = 0) {
|
|
||||||
return [
|
|
||||||
[bounds.x, bounds.y], // Top-left
|
|
||||||
[bounds.x + bounds.w, bounds.y], // Top-right
|
|
||||||
[bounds.x, bounds.y + bounds.h], // Bottom-left
|
|
||||||
[bounds.x + bounds.w, bounds.y + bounds.h] // Bottom-right
|
|
||||||
].map(([x, y]) =>
|
|
||||||
this.tileAtPixelPos({
|
|
||||||
x: x + xo,
|
|
||||||
y: y + yo
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TileMapXML;
|
module.exports = TileMapXML;
|
@ -1,26 +1,12 @@
|
|||||||
var Sprite = require("./Sprite"),
|
var Sprite = require("./Sprite");
|
||||||
AnimManager = require("./AnimManager");
|
|
||||||
|
|
||||||
class TileSprite extends Sprite {
|
class TileSprite extends Sprite {
|
||||||
constructor(texture, w, h) {
|
constructor(texture, w, h) {
|
||||||
super(texture);
|
super(texture);
|
||||||
this.tileW = w;
|
this.tileW = w;
|
||||||
this.tileH = h;
|
this.tileH = h;
|
||||||
this.frame = { x: 0, y: 0 };
|
this.frame = { x: 0, y: 0 };
|
||||||
this.anims = new AnimManager(this);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
update(dt) {
|
|
||||||
this.anims.update(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
get w() {
|
|
||||||
return this.tileW * Math.abs(this.scale.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
get h() {
|
|
||||||
return this.tileH * Math.abs(this.scale.y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TileSprite;
|
module.exports = TileSprite;
|
@ -1,27 +1,13 @@
|
|||||||
var Sprite = require("./Sprite"),
|
var Sprite = require("./Sprite");
|
||||||
AnimManager = require("./AnimManager");
|
|
||||||
|
|
||||||
class TileSpriteXML extends Sprite {
|
class TileSpriteXML extends Sprite {
|
||||||
constructor(texture, xml, index) {
|
constructor(texture, xml, index) {
|
||||||
super(texture);
|
super(texture);
|
||||||
var src = xml.array[index];
|
var src = xml.array[index];
|
||||||
this.imgPos = { x: src["x"], y: src["y"] };
|
this.imgPos = { x: src['x'], y: src['y'] };
|
||||||
this.width = src["width"];
|
this.width = src['width'];
|
||||||
this.height = src["height"];
|
this.height = src['height'];
|
||||||
this.anims = new AnimManager(this);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
update(dt) {
|
|
||||||
this.anims.update(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
get w() {
|
|
||||||
return this.width * Math.abs(this.scale.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
get h() {
|
|
||||||
return this.height * Math.abs(this.scale.y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TileSpriteXML;
|
module.exports = TileSpriteXML;
|
@ -1,78 +1,61 @@
|
|||||||
class KeyControls {
|
class KeyControls {
|
||||||
|
|
||||||
constructor(listen = true) {
|
constructor() {
|
||||||
this.keys = {};
|
this.keys = {};
|
||||||
if (listen) {
|
// Bind event handlers
|
||||||
// Bind event handlers
|
document.addEventListener("keydown", e => {
|
||||||
document.addEventListener("keydown", e => {
|
if ([37, 38, 39, 40].indexOf(e.which) >= 0) {
|
||||||
if ([37, 38, 39, 40].indexOf(e.which) >= 0) {
|
e.preventDefault();
|
||||||
e.preventDefault();
|
}
|
||||||
}
|
this.keys[e.which] = true;
|
||||||
this.keys[e.which] = true;
|
}, false);
|
||||||
}, false);
|
document.addEventListener('keyup', e => {
|
||||||
document.addEventListener("keyup", e => {
|
this.keys[e.which] = false;
|
||||||
this.keys[e.which] = false;
|
}, false);
|
||||||
}, false);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get action() {
|
get action() {
|
||||||
// Spacebar
|
// Spacebar
|
||||||
return this.keys[32];
|
return this.keys[32];
|
||||||
}
|
}
|
||||||
|
|
||||||
get ctrl() {
|
get x() {
|
||||||
// Control
|
// Arrow Left or A (WASD)
|
||||||
return this.keys[17];
|
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 shift() {
|
get y() {
|
||||||
// Shift
|
// Arrow Up or W (WASD)
|
||||||
return this.keys[16];
|
if (this.keys[38] || this.keys[87]) {
|
||||||
}
|
return -1;
|
||||||
|
}
|
||||||
get escape() {
|
// Arrow Down or S (WASD)
|
||||||
// Escape
|
if (this.keys[40] || this.keys[83]) {
|
||||||
return this.keys[27];
|
return 1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
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) {
|
key(key, value) {
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
this.keys[key] = value;
|
this.keys[key] = value;
|
||||||
}
|
}
|
||||||
return this.keys[key];
|
return this.keys[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
for (let key in this.keys) {
|
for (let key in this.keys) {
|
||||||
this.keys[key] = false;
|
this.keys[key] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,49 +1,45 @@
|
|||||||
class MouseControls {
|
class MouseControls {
|
||||||
constructor(container, listen = true) {
|
constructor(container) {
|
||||||
this.el = container || document.body;
|
this.el = container || document.body;
|
||||||
// State
|
// State
|
||||||
this.pos = { x: 0, y: 0 };
|
this.pos = { x: 0, y: 0 };
|
||||||
this.isDown = false;
|
this.isDown = false;
|
||||||
this.pressed = false;
|
this.pressed = false;
|
||||||
this.released = 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);
|
||||||
|
}
|
||||||
|
|
||||||
if (listen) {
|
mousePosFromEvent({ clientX, clientY }) {
|
||||||
// Handlers
|
const { el, pos } = this;
|
||||||
document.addEventListener("mousemove", this.move.bind(this), false);
|
const rect = el.getBoundingClientRect();
|
||||||
document.addEventListener("mousedown", this.down.bind(this), false);
|
const xr = el.width / el.clientWidth;
|
||||||
document.addEventListener("mouseup", this.up.bind(this), false);
|
const yr = el.height / el.clientHeight;
|
||||||
}
|
pos.x = (clientX - rect.left) * xr;
|
||||||
|
pos.y = (clientY - rect.top) * yr;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
move(e) {
|
||||||
|
this.mousePosFromEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
mousePosFromEvent({ clientX, clientY }) {
|
down(e) {
|
||||||
const { el, pos } = this;
|
this.isDown = true;
|
||||||
const rect = el.getBoundingClientRect();
|
this.pressed = true;
|
||||||
const xr = el.width / el.clientWidth;
|
this.mousePosFromEvent(e);
|
||||||
const yr = el.height / el.clientHeight;
|
}
|
||||||
pos.x = (clientX - rect.left) * xr;
|
|
||||||
pos.y = (clientY - rect.top) * yr;
|
|
||||||
}
|
|
||||||
|
|
||||||
move(e) {
|
up() {
|
||||||
this.mousePosFromEvent(e);
|
this.isDown = false;
|
||||||
}
|
this.released = true;
|
||||||
|
}
|
||||||
|
|
||||||
down(e) {
|
update() {
|
||||||
this.isDown = true;
|
this.released = false;
|
||||||
this.pressed = true;
|
this.pressed = false;
|
||||||
this.mousePosFromEvent(e);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
up() {
|
|
||||||
this.isDown = false;
|
|
||||||
this.released = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
this.released = false;
|
|
||||||
this.pressed = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = MouseControls;
|
module.exports = MouseControls;
|
||||||
|
370
lib/index.d.ts
vendored
370
lib/index.d.ts
vendored
@ -2,11 +2,6 @@ export as namespace asdf;
|
|||||||
|
|
||||||
type Coordinates = {x: number, y: number};
|
type Coordinates = {x: number, y: number};
|
||||||
|
|
||||||
class Renderable {
|
|
||||||
visible?: boolean;
|
|
||||||
dead?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TileSpriteXML class
|
* TileSpriteXML class
|
||||||
*/
|
*/
|
||||||
@ -92,52 +87,6 @@ export class TileMap extends Container<TileSprite> {
|
|||||||
* @param texture Texture instance of source image file
|
* @param texture Texture instance of source image file
|
||||||
*/
|
*/
|
||||||
constructor(tiles: Coordinates[], mapW: number, mapH: number, tileW: number, tileH: number, texture: Texture);
|
constructor(tiles: Coordinates[], mapW: number, mapH: number, tileW: number, tileH: number, texture: Texture);
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates in which tile a pixel is located.
|
|
||||||
* @param pos The position of the pixel.
|
|
||||||
*/
|
|
||||||
pixelToMapPos(pos: Coordinates): Coordinates
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the pixel position of a tile in a map.
|
|
||||||
* @param pos The position of the tile in the map.
|
|
||||||
*/
|
|
||||||
mapToPixelPos(pos: Coordinates): Coordinates
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the TileSprite at a given map position.
|
|
||||||
* @param mapPos the tile of a given position.
|
|
||||||
*/
|
|
||||||
tileAtMapPos(mapPos: Coordinates): TileSprite
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the TileSprite at a given pixel position.
|
|
||||||
* @param pos The pixel position of the tile
|
|
||||||
*/
|
|
||||||
tileAtPixelPos(pos: Coordinates): TileSprite
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the frame attribute of the TileSprite at the given mapPos.
|
|
||||||
* @param mapPos the map position of the tile.
|
|
||||||
* @param frame the new value for the frame attribute.
|
|
||||||
*/
|
|
||||||
setFrameAtMapPos(mapPos: Coordinates, frame: Coordinates): TileSprite
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the frame attribute of the TileSprite at the given pixel position.
|
|
||||||
* @param mapPos the pixel position of the tile.
|
|
||||||
* @param frame the new value for the frame attribute.
|
|
||||||
*/
|
|
||||||
setFrameAtPixelPos(pos: Coordinates, frame: Coordinates): TileSprite
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the tiles at the corner of the bounds.
|
|
||||||
* @param bounds a rectangle which defines what the corner are.
|
|
||||||
* @param xo offset to the x values.
|
|
||||||
* @param yo offset to the y values.
|
|
||||||
*/
|
|
||||||
tilesAtCorners(bounds: {x: number, y: number, w: number, h: number}, xo?: number, yo?: number): TileSprite[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -154,29 +103,27 @@ export class Texture {
|
|||||||
constructor(url: string);
|
constructor(url: string);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TextStyleOptions {
|
|
||||||
font?: string,
|
|
||||||
fill?: string | CanvasGradient | CanvasPattern,
|
|
||||||
align?: CanvasTextAlign
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Text class
|
* Text class
|
||||||
*/
|
*/
|
||||||
export class Text extends Renderable {
|
export class Text {
|
||||||
|
|
||||||
pos: Coordinates;
|
pos: Coordinates;
|
||||||
text: string;
|
text: string;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
update?: (dt?: number, t?: number) => void;
|
update?: (dt?: number, t?: number) => void;
|
||||||
style: TextStyleOptions;
|
style: {
|
||||||
|
font?: string,
|
||||||
|
fill?: string | CanvasGradient | CanvasPattern,
|
||||||
|
align?: CanvasTextAlign
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints styled text on canvas
|
* Prints styled text on canvas
|
||||||
* @param text Text to print
|
* @param text Text to print
|
||||||
* @param style Styles to apply to text
|
* @param style Styles to apply to text
|
||||||
*/
|
*/
|
||||||
constructor(text: string, style: TextStyleOptions);
|
constructor(text: string, style: {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,13 +171,15 @@ export class SpriteSheetXML {
|
|||||||
/**
|
/**
|
||||||
* Sprite class
|
* Sprite class
|
||||||
*/
|
*/
|
||||||
export class Sprite extends Renderable {
|
export class Sprite {
|
||||||
texture: Texture;
|
texture: Texture;
|
||||||
pos: Coordinates;
|
pos: Coordinates;
|
||||||
anchor: Coordinates;
|
anchor: Coordinates;
|
||||||
scale: Coordinates;
|
scale: Coordinates;
|
||||||
pivot: Coordinates;
|
pivot: Coordinates;
|
||||||
|
visible: boolean;
|
||||||
rotation: number;
|
rotation: number;
|
||||||
|
dead: boolean;
|
||||||
|
|
||||||
update?: (dt?: number, t?: number) => void;
|
update?: (dt?: number, t?: number) => void;
|
||||||
|
|
||||||
@ -249,7 +198,6 @@ export class Game {
|
|||||||
h: number;
|
h: number;
|
||||||
renderer: CanvasRenderer;
|
renderer: CanvasRenderer;
|
||||||
scene: Container<unknown>;
|
scene: Container<unknown>;
|
||||||
paused: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the games parameters
|
* Set the games parameters
|
||||||
@ -264,14 +212,14 @@ export class Game {
|
|||||||
* Start game loop
|
* Start game loop
|
||||||
* @param gameUpdate Function to run next to scene updates such as debug logging, etc.
|
* @param gameUpdate Function to run next to scene updates such as debug logging, etc.
|
||||||
*/
|
*/
|
||||||
run(gameUpdate?: (dt?: number, t?: number) => void): void;
|
run(gameUpdate: (dt?: number, t?: number) => void): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container class
|
* Container class
|
||||||
*/
|
*/
|
||||||
export class Container<T> {
|
export class Container<T> {
|
||||||
pos: Coordinates;
|
pos: {x: number, y: number};
|
||||||
children: T[];
|
children: T[];
|
||||||
|
|
||||||
constructor();
|
constructor();
|
||||||
@ -301,9 +249,9 @@ export class Container<T> {
|
|||||||
* Updates all children when called
|
* Updates all children when called
|
||||||
* @param dt Delta time
|
* @param dt Delta time
|
||||||
* @param t Total time
|
* @param t Total time
|
||||||
* @returns Returns anything
|
* @returns Returns if the child is dead or not
|
||||||
*/
|
*/
|
||||||
update(dt: number, t: number): any;
|
update(dt: number, t: number): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -373,24 +321,6 @@ export class KeyControls {
|
|||||||
*/
|
*/
|
||||||
get action(): boolean;
|
get action(): boolean;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns value of ctrl key.
|
|
||||||
* @returns Key value
|
|
||||||
*/
|
|
||||||
get ctrl(): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns value of shift key.
|
|
||||||
* @returns Key value
|
|
||||||
*/
|
|
||||||
get shift(): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns value of escape key.
|
|
||||||
* @returns Key value
|
|
||||||
*/
|
|
||||||
get escape(): boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns -1 on Arrow Left or A
|
* Returns -1 on Arrow Left or A
|
||||||
*
|
*
|
||||||
@ -413,10 +343,10 @@ export class KeyControls {
|
|||||||
* @param value Value to set to key
|
* @param value Value to set to key
|
||||||
* @return Value of key
|
* @return Value of key
|
||||||
*/
|
*/
|
||||||
key(key: number, value?: boolean): boolean;
|
key(key: number, value: boolean): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets default value (false) to all keys
|
* Resets default value to all keys
|
||||||
*/
|
*/
|
||||||
reset(): void;
|
reset(): void;
|
||||||
}
|
}
|
||||||
@ -451,275 +381,7 @@ export class CanvasRenderer {
|
|||||||
render(container: Container<unknown>, clear?: boolean): void
|
render(container: Container<unknown>, clear?: boolean): void
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Anim represents a single animation.
|
|
||||||
*/
|
|
||||||
declare class Anim {
|
|
||||||
|
|
||||||
curTime: number;
|
|
||||||
frames: Coordinates[];
|
|
||||||
rate: number;
|
|
||||||
curFrame: number;
|
|
||||||
frame: Coordinates;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for an animation.
|
|
||||||
* @param frames A collection of coordinates for each frame in the texture file.
|
|
||||||
* @param rate The rate at which the animation plays.
|
|
||||||
*/
|
|
||||||
constructor(frames: Coordinates[], rate: number);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the animation to the first frame.
|
|
||||||
*/
|
|
||||||
reset(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Causes the animation to update based on dt.
|
|
||||||
* @param dt Delta time
|
|
||||||
*/
|
|
||||||
update(dt: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The AnimManager class
|
|
||||||
*/
|
|
||||||
export class AnimManager {
|
|
||||||
|
|
||||||
anims: {
|
|
||||||
[name: string]: Anim
|
|
||||||
}
|
|
||||||
running: boolean;
|
|
||||||
frameSource: Coordinates;
|
|
||||||
current: string | null;
|
|
||||||
|
|
||||||
constructor(e: Coordinates);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an animation to the AnimManager
|
|
||||||
* @param name The name for the animation
|
|
||||||
* @param frames Where each frame is located in the texture
|
|
||||||
* @param speed The speed at which the animation plays.
|
|
||||||
*/
|
|
||||||
add(name: string, frames: Coordinates[], speed: number): Anim;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the current animation.
|
|
||||||
* @param dt delta time
|
|
||||||
*/
|
|
||||||
update(dt: number): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts playing an animation.
|
|
||||||
* @param anim The name of the animation
|
|
||||||
*/
|
|
||||||
play(anim: string): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops playing any animation
|
|
||||||
*/
|
|
||||||
stop(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Rect class
|
|
||||||
*/
|
|
||||||
export class Rect {
|
|
||||||
|
|
||||||
pos: Coordinates
|
|
||||||
w: number;
|
|
||||||
h: number;
|
|
||||||
style: {
|
|
||||||
fill: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a rectangle.
|
|
||||||
* @param w The width of the rectangle
|
|
||||||
* @param h The height of the rectangle
|
|
||||||
* @param style The styles of the rectangle
|
|
||||||
*/
|
|
||||||
constructor(w: number, h: number, style: { fill: string })
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Camera extends Container<unknown> {
|
|
||||||
|
|
||||||
w: number;
|
|
||||||
h: number;
|
|
||||||
worldSize: {w: number, h: number};
|
|
||||||
offset: Coordinates;
|
|
||||||
subject: Coordinates;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a camera object. This can be fed into the main scene: `scene.add(camera);`
|
|
||||||
* @param subject The entity on which should be focused
|
|
||||||
* @param viewport the size of the viewport - how much should be visible.
|
|
||||||
* @param worldSize the size of the whole map.
|
|
||||||
*/
|
|
||||||
constructor(subject: NumericalEntity | Coordinates, viewport: {w: number, h: number}, worldSize: {w: number, h: number})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the subject of the camera.
|
|
||||||
* @param e The entity that needs to be set as subject.
|
|
||||||
*/
|
|
||||||
setSubject(e: NumericalEntity | Coordinates): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the camera to the subject
|
|
||||||
*/
|
|
||||||
focus(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* update function for the container.
|
|
||||||
* @param t the elapsed time
|
|
||||||
* @param dt delta time
|
|
||||||
*/
|
|
||||||
update(t: number, dt: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SoundOptions {
|
|
||||||
loop?: boolean,
|
|
||||||
volume?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Sound {
|
|
||||||
|
|
||||||
src: string;
|
|
||||||
options: SoundOptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiates HTML5 audio element for source audio file with control methods
|
|
||||||
* @param src Source audio file
|
|
||||||
* @param options Play settings
|
|
||||||
*/
|
|
||||||
constructor(src: string, options?: SoundOptions);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts playing the audio file
|
|
||||||
* @param overrides sets options for playing the sound using different setting as defined in `constructor()`
|
|
||||||
*/
|
|
||||||
play(overrides?: SoundOptions): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops playing the audio file
|
|
||||||
*/
|
|
||||||
stop(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NumericalEntityBase {pos: Coordinates}
|
|
||||||
interface NumericalSprite {w: number, h: number}
|
|
||||||
interface NumericalTileSprite {tileW: number, tileH: number}
|
|
||||||
|
|
||||||
type NumericalEntity = NumericalSprite | NumericalTileSprite
|
|
||||||
|
|
||||||
type NumericalEntityWithHitbox = {hitBox: NumericalEntity} & NumericalEntity
|
|
||||||
|
|
||||||
export namespace deadInTracks {
|
|
||||||
/**
|
|
||||||
* This functions checks whether ent walks against a non-walkable object and whether it should move in the x and y position and how much.
|
|
||||||
* The difference with wallslide is that deadInTracks stops the entity entirely when it touches a non-walkable surface.
|
|
||||||
* wallslide will move the entity in x or y if possible.
|
|
||||||
* @param ent The entity that is moving.
|
|
||||||
* @param map The TileMap the entity moves on.
|
|
||||||
* @param x The maximal movement on the x. default is 0
|
|
||||||
* @param y The maximal movement on the y. default is 0
|
|
||||||
* @returns Coordinates of how much the entity walks in x and y.
|
|
||||||
*/
|
|
||||||
export function deadInTracks(ent: NumericalEntity | NumericalEntityWithHitbox, map: TileMap, x?: number, y?: number): Coordinates;
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace wallslide {
|
|
||||||
/**
|
|
||||||
* This functions checks whether ent walks against a non-walkable object and whether it should move in the x and y position and how much.
|
|
||||||
* The difference with wallslide is that deadInTracks stops the entity entirely when it touches a non-walkable surface.
|
|
||||||
* wallslide will move the entity in x or y if possible.
|
|
||||||
* @param ent The entity that is moving.
|
|
||||||
* @param map The TileMap the entity moves on.
|
|
||||||
* @param x The maximal movement on the x. default is 0
|
|
||||||
* @param y The maximal movement on the y. default is 0
|
|
||||||
* @returns Coordinates of how much the entity walks in x and y.
|
|
||||||
*/
|
|
||||||
export function wallslide(ent: NumericalEntity | NumericalEntityWithHitbox, map: TileMap, x?: number, y?: number): Coordinates;
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace entity {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* addDebug adds a red border around the hitboxes of an entity.
|
|
||||||
* @param e The entity.
|
|
||||||
*/
|
|
||||||
export function addDebug<T extends Container<unknown> | NumericalEntityWithHitbox>(e: T): T;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function checks if an entity hits anything in a container.
|
|
||||||
* @param entity The entity.
|
|
||||||
* @param container The container.
|
|
||||||
* @param hitCallback The callback that is executed when an entity hits something in the container.
|
|
||||||
*/
|
|
||||||
export function hits<T extends NumericalEntityWithHitbox | NumericalEntity>(entity: NumericalEntityWithHitbox | NumericalEntity, container: Container<T>, hitCallback: (e2: T) => any): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This functions calculates whether two entities hit each other.
|
|
||||||
* @param e1 The first entity.
|
|
||||||
* @param e2 The second entity.
|
|
||||||
*/
|
|
||||||
export function hit(e1: NumericalEntityWithHitbox | NumericalEntity, e2: NumericalEntityWithHitbox | NumericalEntity): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function calculates the angle relative to the x-axis between the centers of two entities.
|
|
||||||
* @param a The first entity.
|
|
||||||
* @param b The second entity.
|
|
||||||
* @returns the angle in radians.
|
|
||||||
*/
|
|
||||||
export function angle(a: NumericalEntity, b: NumericalEntity): number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function calculates the full hitbox of an entity.
|
|
||||||
* @param entity The enitity
|
|
||||||
*/
|
|
||||||
export function bounds(entity: NumericalEntityWithHitbox | NumericalEntity): {x: number, y: number, w: number, h: number};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function calculates the distance between the centers of two entities.
|
|
||||||
* @param a The first entity.
|
|
||||||
* @param b The second entity.
|
|
||||||
*/
|
|
||||||
export function distance(a: NumericalEntity, b: NumericalEntity): number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function calculates the center of an entity.
|
|
||||||
* @param entity The entity to calculate the center of.
|
|
||||||
*/
|
|
||||||
export function center(entity: NumericalEntity): number;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace math {
|
export namespace math {
|
||||||
|
|
||||||
/**
|
|
||||||
* This function calculates the angle relative from the x-axis between two points.
|
|
||||||
* @param a The first point.
|
|
||||||
* @param b The second point.
|
|
||||||
* @returns The angle in radians.
|
|
||||||
*/
|
|
||||||
export function angle(a: Coordinates, b: Coordinates): number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function calculates if x is between min and max.
|
|
||||||
* @param x A numerical value
|
|
||||||
* @param min A numerical value
|
|
||||||
* @param max A numerical value
|
|
||||||
* @returns x if x is between min and max.
|
|
||||||
*/
|
|
||||||
export function clamp(x: number, min: number, max: number): number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the distance between two points
|
|
||||||
* @param a The first point.
|
|
||||||
* @param b The second point.
|
|
||||||
*/
|
|
||||||
export function distance(a: Coordinates, b: Coordinates): number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns random integer between min and max
|
* Returns random integer between min and max
|
||||||
* @param min Minimum value
|
* @param min Minimum value
|
||||||
|
74
lib/index.js
74
lib/index.js
@ -1,50 +1,32 @@
|
|||||||
var AnimManager = require("./AnimManager.js"),
|
var Container = require("./Container.js"),
|
||||||
Camera = require("./Camera.js"),
|
CanvasRenderer = require("./renderer/CanvasRenderer.js"),
|
||||||
Container = require("./Container.js"),
|
Game = require("./Game.js"),
|
||||||
CanvasRenderer = require("./renderer/CanvasRenderer.js"),
|
math = require("./utilities/math.js"),
|
||||||
Game = require("./Game.js"),
|
KeyControls = require("./controls/KeyControls.js"),
|
||||||
math = require("./utilities/math.js"),
|
MouseControls = require("./controls/MouseControls.js"),
|
||||||
entity = require("./utilities/entity.js"),
|
Sprite = require("./Sprite.js"),
|
||||||
wallslide = require("./movement/wallslide.js"),
|
TileMap = require("./TileMap.js"),
|
||||||
deadInTracks = require("./movement/deadInTracks.js"),
|
TileMapXML = require("./TileMapXML.js"),
|
||||||
State = require("./State.js"),
|
TileSprite = require("./TileSprite.js"),
|
||||||
Sound = require("./sound/Sound.js"),
|
TileSpriteXML = require("./TileSpriteXML.js"),
|
||||||
Rect = require("./Rect.js"),
|
Text = require("./Text.js"),
|
||||||
Line = require("./Line.js"),
|
Texture = require("./Texture.js"),
|
||||||
KeyControls = require("./controls/KeyControls.js"),
|
SpriteSheetXML = require("./SpriteSheetXML.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 = {
|
module.exports = {
|
||||||
AnimManager,
|
CanvasRenderer,
|
||||||
CanvasRenderer,
|
Container,
|
||||||
Camera,
|
Game,
|
||||||
Container,
|
math,
|
||||||
Game,
|
KeyControls,
|
||||||
math,
|
MouseControls,
|
||||||
entity,
|
Sprite,
|
||||||
wallslide,
|
TileMap,
|
||||||
deadInTracks,
|
TileMapXML,
|
||||||
State,
|
TileSprite,
|
||||||
Sound,
|
SpriteSheetXML,
|
||||||
Rect,
|
TileSpriteXML,
|
||||||
Line,
|
Text,
|
||||||
KeyControls,
|
Texture
|
||||||
MouseControls,
|
|
||||||
Sprite,
|
|
||||||
TileMap,
|
|
||||||
TileMapXML,
|
|
||||||
TileSprite,
|
|
||||||
SpriteSheetXML,
|
|
||||||
TileSpriteXML,
|
|
||||||
Text,
|
|
||||||
Texture
|
|
||||||
};
|
};
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
const entity = require("../utilities/entity");
|
|
||||||
|
|
||||||
function deadInTracks(ent, map, x = 0, y = 0) {
|
|
||||||
const bounds = entity.bounds(ent);
|
|
||||||
const tiles = map.tilesAtCorners(bounds, x, y);
|
|
||||||
const walks = tiles.map(t => t && t.frame.walkable);
|
|
||||||
const blocked = walks.some(w => !w);
|
|
||||||
if (blocked) {
|
|
||||||
x = 0,
|
|
||||||
y = 0;
|
|
||||||
}
|
|
||||||
return { x, y };
|
|
||||||
}
|
|
||||||
module.exports = {
|
|
||||||
deadInTracks
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
const entity = require("../utilities/entity.js");
|
|
||||||
|
|
||||||
function wallslide(ent, map, x = 0, y = 0) {
|
|
||||||
let tiles;
|
|
||||||
let tileEdge;
|
|
||||||
const bounds = entity.bounds(ent);
|
|
||||||
|
|
||||||
// Final amounts of movement to allow
|
|
||||||
let xo = x;
|
|
||||||
let yo = y;
|
|
||||||
|
|
||||||
// Check vertical movement
|
|
||||||
if (y !== 0) {
|
|
||||||
tiles = map.tilesAtCorners(bounds, 0, yo);
|
|
||||||
const [tl, tr, bl, br] = tiles.map(t => t && t.frame.walkable);
|
|
||||||
|
|
||||||
// Hit your head
|
|
||||||
if (y < 0 && !(tl && tr)) {
|
|
||||||
tileEdge = tiles[0].pos.y + tiles[0].h;
|
|
||||||
yo = tileEdge - bounds.y;
|
|
||||||
}
|
|
||||||
// Hit your feet
|
|
||||||
if (y > 0 && !(bl && br)) {
|
|
||||||
tileEdge = tiles[2].pos.y - 1;
|
|
||||||
yo = tileEdge - (bounds.y + bounds.h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check horizontal movement
|
|
||||||
if (x !== 0) {
|
|
||||||
tiles = map.tilesAtCorners(bounds, xo, yo);
|
|
||||||
const [tl, tr, bl, br] = tiles.map(t => t && t.frame.walkable);
|
|
||||||
|
|
||||||
// Hit left edge
|
|
||||||
if (x < 0 && !(tl && bl)) {
|
|
||||||
tileEdge = tiles[0].pos.x + tiles[0].w;
|
|
||||||
xo = tileEdge - bounds.x;
|
|
||||||
}
|
|
||||||
// Hit right edge
|
|
||||||
if (x > 0 && !(tr && br)) {
|
|
||||||
tileEdge = tiles[1].pos.x - 1;
|
|
||||||
xo = tileEdge - (bounds.x + bounds.w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// xo & yo contain the amount we're allowed to move by.
|
|
||||||
return { x: xo, y: yo };
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
wallslide
|
|
||||||
};
|
|
@ -1,115 +1,97 @@
|
|||||||
class CanvasRenderer {
|
class CanvasRenderer {
|
||||||
|
|
||||||
constructor(w, h) {
|
constructor(w, h) {
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
this.w = canvas.width = w;
|
this.w = canvas.width = w;
|
||||||
this.h = canvas.height = h;
|
this.h = canvas.height = h;
|
||||||
this.view = canvas;
|
this.view = canvas;
|
||||||
this.ctx = canvas.getContext("2d");
|
this.ctx = canvas.getContext("2d");
|
||||||
this.ctx.textBaseLine = "top";
|
this.ctx.textBaseLine = "top";
|
||||||
}
|
}
|
||||||
|
|
||||||
setPixelated() {
|
setPixelated() {
|
||||||
this.ctx["imageSmoothingEnabled"] = false; /* standard */
|
this.ctx['imageSmoothingEnabled'] = false; /* standard */
|
||||||
this.ctx["mozImageSmoothingEnabled"] = false; /* Firefox */
|
this.ctx['mozImageSmoothingEnabled'] = false; /* Firefox */
|
||||||
this.ctx["oImageSmoothingEnabled"] = false; /* Opera */
|
this.ctx['oImageSmoothingEnabled'] = false; /* Opera */
|
||||||
this.ctx["webkitImageSmoothingEnabled"] = false; /* Safari */
|
this.ctx['webkitImageSmoothingEnabled'] = false; /* Safari */
|
||||||
this.ctx["msImageSmoothingEnabled"] = false; /* IE */
|
this.ctx['msImageSmoothingEnabled'] = false; /* IE */
|
||||||
}
|
}
|
||||||
|
|
||||||
render(container, clear = true) {
|
render(container, clear = true) {
|
||||||
const { ctx } = this;
|
const { ctx } = this;
|
||||||
function renderRec(container) {
|
function renderRec(container) {
|
||||||
// Render container children
|
// Render container children
|
||||||
container.children.forEach(child => {
|
container.children.forEach(child => {
|
||||||
if (child.visible == false) {
|
if (child.visible == false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
if (child.pos) {
|
if (child.pos) {
|
||||||
ctx.translate(Math.round(child.pos.x), Math.round(child.pos.y));
|
ctx.translate(Math.round(child.pos.x), Math.round(child.pos.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child.anchor) {
|
if (child.anchor) {
|
||||||
ctx.translate(child.anchor.x, child.anchor.y);
|
ctx.translate(child.anchor.x, child.anchor.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child.scale) {
|
if (child.scale) {
|
||||||
ctx.scale(child.scale.x, child.scale.y);
|
ctx.scale(child.scale.x, child.scale.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child.rotation) {
|
if (child.rotation) {
|
||||||
const px = child.pivot ? child.pivot.x : 0;
|
const px = child.pivot ? child.pivot.x : 0;
|
||||||
const py = child.pivot ? child.pivot.y : 0;
|
const py = child.pivot ? child.pivot.y : 0;
|
||||||
ctx.translate(px, py);
|
ctx.translate(px, py);
|
||||||
ctx.rotate(child.rotation);
|
ctx.rotate(child.rotation);
|
||||||
ctx.translate(-px, -py);
|
ctx.translate(-px, -py);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child.text) {
|
if (child.text) {
|
||||||
const { font, fill, align } = child.style;
|
const { font, fill, align } = child.style;
|
||||||
if (font) ctx.font = font;
|
if (font) ctx.font = font;
|
||||||
if (fill) ctx.fillStyle = fill;
|
if (fill) ctx.fillStyle = fill;
|
||||||
if (align) ctx.textAlign = align;
|
if (align) ctx.textAlign = align;
|
||||||
ctx.fillText(child.text, 0, 0);
|
ctx.fillText(child.text, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (child.texture) {
|
else if (child.texture) {
|
||||||
const img = child.texture.img;
|
const img = child.texture.img;
|
||||||
if (child.tileW && child.tileH) {
|
if (child.tileW && child.tileH) {
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
img,
|
img,
|
||||||
child.frame.x * child.tileW,
|
child.frame.x * child.tileW,
|
||||||
child.frame.y * child.tileH,
|
child.frame.y * child.tileH,
|
||||||
child.tileW, child.tileH,
|
child.tileW, child.tileH,
|
||||||
0, 0,
|
0, 0,
|
||||||
child.tileW, child.tileH
|
child.tileW, child.tileH
|
||||||
);
|
);
|
||||||
} else if (child.imgPos && child.width && child.height) {
|
} else if (child.imgPos && child.width && child.height) {
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
img,
|
img,
|
||||||
child.imgPos.x,
|
child.imgPos.x,
|
||||||
child.imgPos.y,
|
child.imgPos.y,
|
||||||
child.width, child.height,
|
child.width, child.height,
|
||||||
0, 0,
|
0, 0,
|
||||||
child.width, child.height
|
child.width, child.height
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
ctx.drawImage(img, 0, 0);
|
ctx.drawImage(img, 0, 0);
|
||||||
}
|
}
|
||||||
} else if (child.style && child.w && child.h) {
|
}
|
||||||
ctx.fillStyle = child.style.fill;
|
|
||||||
ctx.fillRect(0, 0, child.w, child.h);
|
|
||||||
} else if (child.style && child.radius) {
|
|
||||||
var gradient = ctx.createRadialGradient(0, 0, 50, 0, 0, 50);
|
|
||||||
gradient.addColorStop(0, child.style.start);
|
|
||||||
gradient.addColorStop(1, child.style.stop);
|
|
||||||
|
|
||||||
ctx.arc(0, 0, child.radius, 0, 2 * Math.PI);
|
// Handle children with children
|
||||||
ctx.fillStyle = gradient;
|
if (child.children) {
|
||||||
|
renderRec(child);
|
||||||
ctx.fill();
|
}
|
||||||
} else if (child.style && child.target) {
|
ctx.restore();
|
||||||
ctx.beginPath();
|
})
|
||||||
ctx.moveTo(0,0);
|
}
|
||||||
ctx.lineTo(child.target.x, child.target.y);
|
if (clear) {
|
||||||
ctx.strokeStyle = child.style;
|
ctx.clearRect(0, 0, this.w, this.h);
|
||||||
ctx.stroke();
|
}
|
||||||
}
|
renderRec(container);
|
||||||
|
}
|
||||||
// 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;
|
module.exports = CanvasRenderer;
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
class Sound {
|
|
||||||
constructor(src, options = {}) {
|
|
||||||
this.playing = false;
|
|
||||||
this.src = src;
|
|
||||||
this.options = Object.assign({ volume: 1 }, options);
|
|
||||||
|
|
||||||
// Configure audio element
|
|
||||||
const audio = new Audio();
|
|
||||||
audio.src = src;
|
|
||||||
if (options.loop) {
|
|
||||||
audio.loop = true;
|
|
||||||
}
|
|
||||||
audio.addEventListener(
|
|
||||||
"error",
|
|
||||||
() => {
|
|
||||||
throw Error(`Error loading audio: ${src}`);
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
audio.addEventListener(
|
|
||||||
"ended",
|
|
||||||
() => {
|
|
||||||
this.playing = false;
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
this.audio = audio;
|
|
||||||
}
|
|
||||||
|
|
||||||
play(overrides) {
|
|
||||||
const { audio, options } = this;
|
|
||||||
const opts = Object.assign({ time: 0 }, options, overrides);
|
|
||||||
audio.volume = opts.volume;
|
|
||||||
audio.currentTime = opts.time;
|
|
||||||
audio.play();
|
|
||||||
this.playing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
this.audio.pause();
|
|
||||||
this.playing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get volume() {
|
|
||||||
return this.audio.volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
set volume(volume) {
|
|
||||||
this.options.volume = this.audio.volume = volume;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Sound;
|
|
@ -1,96 +0,0 @@
|
|||||||
const math = require("./math");
|
|
||||||
const Rect = require("../Rect");
|
|
||||||
|
|
||||||
function addDebug(e) {
|
|
||||||
e.children = e.children || [];
|
|
||||||
const bb = new Rect(e.w, e.h, { fill: "rgba(255, 0, 0, 0.3)" });
|
|
||||||
e.children.push(bb);
|
|
||||||
if (e.hitBox) {
|
|
||||||
const { x, y, w, h } = e.hitBox;
|
|
||||||
const hb = new Rect(w, h, { fill: "rgba(255, 0, 0, 0.5)" });
|
|
||||||
hb.pos.x = x;
|
|
||||||
hb.pos.y = y;
|
|
||||||
e.children.push(hb);
|
|
||||||
}
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
function angle(a, b) {
|
|
||||||
return math.angle(center(a), center(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
function bounds(entity) {
|
|
||||||
let pos, w, h, hitBox;
|
|
||||||
// Object.prototype.hasOwnProperty.call is needed because of eslint
|
|
||||||
if (Object.prototype.hasOwnProperty.call(entity, "tileW") && Object.prototype.hasOwnProperty.call(entity, "tileH")) {
|
|
||||||
({pos, w, h} = {pos: entity.pos, w: entity.tileW, h: entity.tileH});
|
|
||||||
} else {
|
|
||||||
({pos, w, h} = entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity.hitBox) hitBox = entity.hitBox;
|
|
||||||
|
|
||||||
const hit = hitBox || { x: 0, y: 0, w, h };
|
|
||||||
return {
|
|
||||||
x: hit.x + pos.x,
|
|
||||||
y: hit.y + pos.y,
|
|
||||||
w: hit.w - 1,
|
|
||||||
h: hit.h - 1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function center(entity) {
|
|
||||||
let pos, w, h;
|
|
||||||
|
|
||||||
// Object.prototype.hasOwnProperty.call is needed because of eslint
|
|
||||||
if (Object.prototype.hasOwnProperty.call(entity, "tileW") && Object.prototype.hasOwnProperty.call(entity, "tileH")) {
|
|
||||||
({pos, w, h} = {pos: entity.pos, w: entity.tileW, h: entity.tileH});
|
|
||||||
} else {
|
|
||||||
({pos, w, h} = entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
x: pos.x + w / 2,
|
|
||||||
y: pos.y + h / 2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function distance(a, b) {
|
|
||||||
return math.distance(center(a), center(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
function hit(e1, e2) {
|
|
||||||
const a = bounds(e1);
|
|
||||||
const b = bounds(e2);
|
|
||||||
return (
|
|
||||||
a.x + a.w >= b.x &&
|
|
||||||
a.x <= b.x + b.w &&
|
|
||||||
a.y + a.h >= b.y &&
|
|
||||||
a.y <= b.y + b.h
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hits(entity, container, hitCallback) {
|
|
||||||
const a = bounds(entity);
|
|
||||||
container.map(e2 => {
|
|
||||||
const b = bounds(e2);
|
|
||||||
if (
|
|
||||||
a.x + a.w >= b.x &&
|
|
||||||
a.x <= b.x + b.w &&
|
|
||||||
a.y + a.h >= b.y &&
|
|
||||||
a.y <= b.y + b.h
|
|
||||||
) {
|
|
||||||
hitCallback(e2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
addDebug,
|
|
||||||
angle,
|
|
||||||
bounds,
|
|
||||||
center,
|
|
||||||
distance,
|
|
||||||
hit,
|
|
||||||
hits
|
|
||||||
};
|
|
@ -1,48 +1,26 @@
|
|||||||
function angle(a, b) {
|
|
||||||
const dx = a.x - b.x;
|
|
||||||
const dy = a.y - b.y;
|
|
||||||
const angle = Math.atan2(dy, dx);
|
|
||||||
|
|
||||||
return angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
function clamp(x, min, max) {
|
|
||||||
return Math.max(min, Math.min(x, max));
|
|
||||||
}
|
|
||||||
|
|
||||||
function distance (a, b) {
|
|
||||||
const dx = a.x - b.x;
|
|
||||||
const dy = a.y - b.y;
|
|
||||||
|
|
||||||
return Math.sqrt(dx * dx + dy * dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rand(min, max) {
|
function rand(min, max) {
|
||||||
return Math.floor(randf(min, max));
|
return Math.floor(randf(min, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
function randf(min, max) {
|
function randf(min, max) {
|
||||||
if (max == null) {
|
if (max == null) {
|
||||||
max = min || 1;
|
max = min || 1;
|
||||||
min = 0;
|
min = 0;
|
||||||
}
|
}
|
||||||
return Math.random() * (max - min) + min;
|
return Math.random() * (max - min) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
function randOneFrom(items) {
|
function randOneFrom(items) {
|
||||||
return items[rand(items.length)];
|
return items[rand(items.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
function randOneIn(max = 2) {
|
function randOneIn(max = 2) {
|
||||||
return rand(0, max) === 0;
|
return rand(0, max) === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
angle,
|
rand,
|
||||||
clamp,
|
randf,
|
||||||
distance,
|
randOneFrom,
|
||||||
rand,
|
randOneIn
|
||||||
randf,
|
|
||||||
randOneFrom,
|
|
||||||
randOneIn
|
|
||||||
};
|
};
|
1109
package-lock.json
generated
1109
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "asdf-games",
|
"name": "asdf-games",
|
||||||
"version": "1.1.6",
|
"version": "1.0.0",
|
||||||
"description": "Javascript gaming framework, based upon the framework made in the book HTML5 Games: Novice to Ninja by Sitepoint.",
|
"description": "Javascript gaming framework, based upon the framework made in the book HTML5 Games: Novice to Ninja by Sitepoint.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -17,11 +17,5 @@
|
|||||||
"name": "Arne van Iterson",
|
"name": "Arne van Iterson",
|
||||||
"url": "https://gitea.arnweb.nl/arne/"
|
"url": "https://gitea.arnweb.nl/arne/"
|
||||||
},
|
},
|
||||||
"license": "ISC",
|
"license": "ISC"
|
||||||
"devDependencies": {
|
|
||||||
"eslint": "^6.8.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"easystarjs": "^0.4.3"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB |
Loading…
Reference in New Issue
Block a user