Added everything from chapter 4 and set up ESlint
This commit is contained in:
parent
3490dd07ae
commit
72633d8c0f
2
.eslintignore
Normal file
2
.eslintignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
projects
|
||||||
|
examples
|
33
.eslintrc.js
Normal file
33
.eslintrc.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
63
lib/AnimManager.js
Normal file
63
lib/AnimManager.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
class Anim {
|
||||||
|
constructor(frames, rate) {
|
||||||
|
this.frames = frames;
|
||||||
|
this.rate = rate;
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
update(dt) {
|
||||||
|
const { rate, frames } = this;
|
||||||
|
if ((this.curTime += dt) > rate) {
|
||||||
|
this.curFrame++;
|
||||||
|
this.frame = frames[this.curFrame % frames.length];
|
||||||
|
this.curTime -= rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.frame = this.frames[0];
|
||||||
|
this.curFrame = 0;
|
||||||
|
this.curTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnimManager {
|
||||||
|
constructor(e) {
|
||||||
|
this.anims = {};
|
||||||
|
this.running = false;
|
||||||
|
this.frameSource = e.frame || e;
|
||||||
|
this.currrent = 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);
|
||||||
|
|
||||||
|
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;
|
54
lib/Camera.js
Normal file
54
lib/Camera.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
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;
|
||||||
|
50
lib/Game.js
50
lib/Game.js
@ -1,40 +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();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
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;
|
14
lib/Rect.js
14
lib/Rect.js
@ -1,10 +1,10 @@
|
|||||||
class Rect {
|
class Rect {
|
||||||
constructor(w, h, style = { fill: "#333" }) {
|
constructor(w, h, style = { fill: "#333" }) {
|
||||||
this.pos = { x: 0, y: 0 };
|
this.pos = { x: 0, y: 0 };
|
||||||
this.w = w;
|
this.w = w;
|
||||||
this.h = h;
|
this.h = h;
|
||||||
this.style = style;
|
this.style = style;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Rect;
|
module.exports = Rect;
|
@ -1,10 +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.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;
|
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,25 +1,59 @@
|
|||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TileMap;
|
module.exports = TileMap;
|
@ -1,25 +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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TileMapXML;
|
module.exports = TileMapXML;
|
@ -1,12 +1,12 @@
|
|||||||
var Sprite = require("./Sprite");
|
var Sprite = require("./Sprite");
|
||||||
|
|
||||||
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 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TileSprite;
|
module.exports = TileSprite;
|
@ -1,13 +1,13 @@
|
|||||||
var Sprite = require("./Sprite");
|
var Sprite = require("./Sprite");
|
||||||
|
|
||||||
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"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TileSpriteXML;
|
module.exports = TileSpriteXML;
|
@ -1,61 +1,61 @@
|
|||||||
class KeyControls {
|
class KeyControls {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.keys = {};
|
this.keys = {};
|
||||||
// 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 x() {
|
get x() {
|
||||||
// Arrow Left or A (WASD)
|
// Arrow Left or A (WASD)
|
||||||
if (this.keys[37] || this.keys[65]) {
|
if (this.keys[37] || this.keys[65]) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Arrow Right or D (WASD)
|
// Arrow Right or D (WASD)
|
||||||
if (this.keys[39] || this.keys[68]) {
|
if (this.keys[39] || this.keys[68]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
get y() {
|
get y() {
|
||||||
// Arrow Up or W (WASD)
|
// Arrow Up or W (WASD)
|
||||||
if (this.keys[38] || this.keys[87]) {
|
if (this.keys[38] || this.keys[87]) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Arrow Down or S (WASD)
|
// Arrow Down or S (WASD)
|
||||||
if (this.keys[40] || this.keys[83]) {
|
if (this.keys[40] || this.keys[83]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
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,45 +1,45 @@
|
|||||||
class MouseControls {
|
class MouseControls {
|
||||||
constructor(container) {
|
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
|
// Handlers
|
||||||
document.addEventListener('mousemove', this.move.bind(this), false);
|
document.addEventListener("mousemove", this.move.bind(this), false);
|
||||||
document.addEventListener('mousedown', this.down.bind(this), false);
|
document.addEventListener("mousedown", this.down.bind(this), false);
|
||||||
document.addEventListener('mouseup', this.up.bind(this), false);
|
document.addEventListener("mouseup", this.up.bind(this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
mousePosFromEvent({ clientX, clientY }) {
|
mousePosFromEvent({ clientX, clientY }) {
|
||||||
const { el, pos } = this;
|
const { el, pos } = this;
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
const xr = el.width / el.clientWidth;
|
const xr = el.width / el.clientWidth;
|
||||||
const yr = el.height / el.clientHeight;
|
const yr = el.height / el.clientHeight;
|
||||||
pos.x = (clientX - rect.left) * xr;
|
pos.x = (clientX - rect.left) * xr;
|
||||||
pos.y = (clientY - rect.top) * yr;
|
pos.y = (clientY - rect.top) * yr;
|
||||||
}
|
}
|
||||||
|
|
||||||
move(e) {
|
move(e) {
|
||||||
this.mousePosFromEvent(e);
|
this.mousePosFromEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
down(e) {
|
down(e) {
|
||||||
this.isDown = true;
|
this.isDown = true;
|
||||||
this.pressed = true;
|
this.pressed = true;
|
||||||
this.mousePosFromEvent(e);
|
this.mousePosFromEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
up() {
|
up() {
|
||||||
this.isDown = false;
|
this.isDown = false;
|
||||||
this.released = true;
|
this.released = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
this.released = false;
|
this.released = false;
|
||||||
this.pressed = false;
|
this.pressed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = MouseControls;
|
module.exports = MouseControls;
|
||||||
|
68
lib/index.js
68
lib/index.js
@ -1,36 +1,40 @@
|
|||||||
var Container = require("./Container.js"),
|
var AnimManager = require("./AnimManager.js"),
|
||||||
CanvasRenderer = require("./renderer/CanvasRenderer.js"),
|
Camera = require("./Camera.js"),
|
||||||
Game = require("./Game.js"),
|
Container = require("./Container.js"),
|
||||||
math = require("./utilities/math.js"),
|
CanvasRenderer = require("./renderer/CanvasRenderer.js"),
|
||||||
entity = require("./utilities/entity.js"),
|
Game = require("./Game.js"),
|
||||||
Rect = require("./Rect.js"),
|
math = require("./utilities/math.js"),
|
||||||
KeyControls = require("./controls/KeyControls.js"),
|
entity = require("./utilities/entity.js"),
|
||||||
MouseControls = require("./controls/MouseControls.js"),
|
Rect = require("./Rect.js"),
|
||||||
Sprite = require("./Sprite.js"),
|
KeyControls = require("./controls/KeyControls.js"),
|
||||||
TileMap = require("./TileMap.js"),
|
MouseControls = require("./controls/MouseControls.js"),
|
||||||
TileMapXML = require("./TileMapXML.js"),
|
Sprite = require("./Sprite.js"),
|
||||||
TileSprite = require("./TileSprite.js"),
|
TileMap = require("./TileMap.js"),
|
||||||
TileSpriteXML = require("./TileSpriteXML.js"),
|
TileMapXML = require("./TileMapXML.js"),
|
||||||
Text = require("./Text.js"),
|
TileSprite = require("./TileSprite.js"),
|
||||||
Texture = require("./Texture.js"),
|
TileSpriteXML = require("./TileSpriteXML.js"),
|
||||||
SpriteSheetXML = require("./SpriteSheetXML.js")
|
Text = require("./Text.js"),
|
||||||
|
Texture = require("./Texture.js"),
|
||||||
|
SpriteSheetXML = require("./SpriteSheetXML.js")
|
||||||
;
|
;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
CanvasRenderer,
|
AnimManager,
|
||||||
Container,
|
CanvasRenderer,
|
||||||
Game,
|
Camera,
|
||||||
math,
|
Container,
|
||||||
entity,
|
Game,
|
||||||
Rect,
|
math,
|
||||||
KeyControls,
|
entity,
|
||||||
MouseControls,
|
Rect,
|
||||||
Sprite,
|
KeyControls,
|
||||||
TileMap,
|
MouseControls,
|
||||||
TileMapXML,
|
Sprite,
|
||||||
TileSprite,
|
TileMap,
|
||||||
SpriteSheetXML,
|
TileMapXML,
|
||||||
TileSpriteXML,
|
TileSprite,
|
||||||
Text,
|
SpriteSheetXML,
|
||||||
Texture
|
TileSpriteXML,
|
||||||
|
Text,
|
||||||
|
Texture
|
||||||
};
|
};
|
||||||
|
@ -1,100 +1,100 @@
|
|||||||
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 if (child.style && child.w && child.h) {
|
} else if (child.style && child.w && child.h) {
|
||||||
ctx.fillStyle = child.style.fill;
|
ctx.fillStyle = child.style.fill;
|
||||||
ctx.fillRect(0, 0, child.w, child.h)
|
ctx.fillRect(0, 0, child.w, child.h);
|
||||||
} else {
|
} else {
|
||||||
ctx.drawImage(img, 0, 0);
|
ctx.drawImage(img, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle children with children
|
// Handle children with children
|
||||||
if (child.children) {
|
if (child.children) {
|
||||||
renderRec(child);
|
renderRec(child);
|
||||||
}
|
}
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
if (clear) {
|
if (clear) {
|
||||||
ctx.clearRect(0, 0, this.w, this.h);
|
ctx.clearRect(0, 0, this.w, this.h);
|
||||||
}
|
}
|
||||||
renderRec(container);
|
renderRec(container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = CanvasRenderer;
|
module.exports = CanvasRenderer;
|
||||||
|
@ -1,79 +1,79 @@
|
|||||||
const math = require('./math');
|
const math = require("./math");
|
||||||
const Rect = require('../Rect');
|
const Rect = require("../Rect");
|
||||||
|
|
||||||
function addDebug(e) {
|
function addDebug(e) {
|
||||||
e.children = e.children || [];
|
e.children = e.children || [];
|
||||||
const bb = new Rect(e.w, e.h, { fill: "rgba(255, 0, 0, 0.3)" });
|
const bb = new Rect(e.w, e.h, { fill: "rgba(255, 0, 0, 0.3)" });
|
||||||
e.children.push(bb);
|
e.children.push(bb);
|
||||||
if (e.hitBox) {
|
if (e.hitBox) {
|
||||||
const { x, y, w, h } = e.hitBox;
|
const { x, y, w, h } = e.hitBox;
|
||||||
const hb = new Rect(w, h, { fill: "rgba(255, 0, 0, 0.5)" });
|
const hb = new Rect(w, h, { fill: "rgba(255, 0, 0, 0.5)" });
|
||||||
hb.pos.x = x;
|
hb.pos.x = x;
|
||||||
hb.pos.y = y;
|
hb.pos.y = y;
|
||||||
e.children.push(hb);
|
e.children.push(hb);
|
||||||
}
|
}
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
function angle(a, b) {
|
function angle(a, b) {
|
||||||
return math.angle(center(a), center(b));
|
return math.angle(center(a), center(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
function bounds(entity) {
|
function bounds(entity) {
|
||||||
const { w, h, pos, hitBox } = entity;
|
const { w, h, pos, hitBox } = entity;
|
||||||
const hit = hitBox || { x: 0, y: 0, w, h };
|
const hit = hitBox || { x: 0, y: 0, w, h };
|
||||||
return {
|
return {
|
||||||
x: hit.x + pos.x,
|
x: hit.x + pos.x,
|
||||||
y: hit.y + pos.y,
|
y: hit.y + pos.y,
|
||||||
w: hit.w - 1,
|
w: hit.w - 1,
|
||||||
h: hit.h - 1
|
h: hit.h - 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function center(entity) {
|
function center(entity) {
|
||||||
const { pos, w, h } = entity;
|
const { pos, w, h } = entity;
|
||||||
return {
|
return {
|
||||||
x: pos.x + w / 2,
|
x: pos.x + w / 2,
|
||||||
y: pos.y + h / 2
|
y: pos.y + h / 2
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function distance(a, b) {
|
function distance(a, b) {
|
||||||
return math.distance(center(a), center(b));
|
return math.distance(center(a), center(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
function hit(e1, e2) {
|
function hit(e1, e2) {
|
||||||
const a = bounds(e1);
|
const a = bounds(e1);
|
||||||
const b = bounds(e2);
|
const b = bounds(e2);
|
||||||
return (
|
return (
|
||||||
a.x + a.w >= b.x &&
|
a.x + a.w >= b.x &&
|
||||||
a.x <= b.x + b.w &&
|
a.x <= b.x + b.w &&
|
||||||
a.y + a.h >= b.y &&
|
a.y + a.h >= b.y &&
|
||||||
a.y <= b.y + b.h
|
a.y <= b.y + b.h
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hits(entity, container, hitCallback) {
|
function hits(entity, container, hitCallback) {
|
||||||
const a = bounds(entity);
|
const a = bounds(entity);
|
||||||
container.map(e2 => {
|
container.map(e2 => {
|
||||||
const b = bounds(e2);
|
const b = bounds(e2);
|
||||||
if (
|
if (
|
||||||
a.x + a.w >= b.x &&
|
a.x + a.w >= b.x &&
|
||||||
a.x <= b.x + b.w &&
|
a.x <= b.x + b.w &&
|
||||||
a.y + a.h >= b.y &&
|
a.y + a.h >= b.y &&
|
||||||
a.y <= b.y + b.h
|
a.y <= b.y + b.h
|
||||||
) {
|
) {
|
||||||
hitCallback(e2);
|
hitCallback(e2);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
addDebug,
|
addDebug,
|
||||||
angle,
|
angle,
|
||||||
bounds,
|
bounds,
|
||||||
center,
|
center,
|
||||||
distance,
|
distance,
|
||||||
hit,
|
hit,
|
||||||
hits
|
hits
|
||||||
};
|
};
|
@ -1,26 +1,48 @@
|
|||||||
|
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 = {
|
||||||
rand,
|
angle,
|
||||||
randf,
|
clamp,
|
||||||
randOneFrom,
|
distance,
|
||||||
randOneIn
|
rand,
|
||||||
|
randf,
|
||||||
|
randOneFrom,
|
||||||
|
randOneIn
|
||||||
};
|
};
|
1096
package-lock.json
generated
Normal file
1096
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,5 +17,8 @@
|
|||||||
"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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user