diff options
author | Juan J. Martinez <jjm@usebox.net> | 2023-12-28 19:43:05 +0000 |
---|---|---|
committer | Juan J. Martinez <jjm@usebox.net> | 2023-12-28 19:47:11 +0000 |
commit | ed0e61af2c9fb7b016cb72a91d207b761859c676 (patch) | |
tree | 7a64f254ecb1b921acf561d3aebc47672d0d9714 /js | |
download | js-canvas-2023-ed0e61af2c9fb7b016cb72a91d207b761859c676.tar.gz js-canvas-2023-ed0e61af2c9fb7b016cb72a91d207b761859c676.zip |
Initial import
Diffstat (limited to 'js')
-rw-r--r-- | js/game.js | 251 | ||||
-rw-r--r-- | js/main.js | 11 | ||||
-rw-r--r-- | js/mygame.js | 40 |
3 files changed, 302 insertions, 0 deletions
diff --git a/js/game.js b/js/game.js new file mode 100644 index 0000000..85b0f91 --- /dev/null +++ b/js/game.js @@ -0,0 +1,251 @@ +class Game { + constructor(canvas) { + this.canvas = canvas; + this.ctx = canvas.getContext("2d"); + + // override this for a differnt size + this.width = 320; + this.height = 240; + + // override this with your data to be loaded: + // + // { id: "file.png" } + // + // Supports .png, .ogg and .json files. + // + // and also override dataSize with: + // + // this.dataSize = Object.keys(this.data).length + // + this.data = {}; + this.dataSize = 0; + + // override to change keys + this.controls = { + 80: "pause", + 83: "start", + 37: "left", + 38: "up", + 39: "right", + 40: "down", + 90: "a", + 88: "b" + }; + + this.scale = 1; + + // will store the resouces indexed by id + this.res = {}; + this.resSize = 0; + + // override if you want to change the limit + // defaults to 8 "channels" + this.playLimit = 8; + this.playCount = 0; + + // test to see if a key is down or not + this.keys = { + pause: false, + start: false, + left: false, + up: false, + right: false, + down: false, + a: false, + b: false + }; + + this.minFps = 60; + this.then = -1 / 60; + + this.loadingError = undefined; + } + + start() { + this.canvas.style.background = "rgb(21, 21, 21)"; + this.resize(); + + window.onresize = (ev) => { + this.resize(); + }; + + this.loader(); + } + + // override this + init() {} + // override this + update(dt) {} + // override this + draw() {} + + _update(dt) {} + _draw() {} + + resize() { + this.scale = Math.floor(window.innerHeight / this.height); + this.canvas.width = this.width * this.scale; + this.canvas.height = this.height * this.scale; + + if (this.ctx != undefined) { + this.ctx.imageSmoothingEnabled = false; + } + } + + loop(now) { + let dt = Math.min(1 / this.minFps, now - this.then); + this._update(dt); + + this._draw(); + + this.then = now; + requestAnimationFrame((now) => { + this.loop(now) + }); + } + + loader() { + this._draw = this.drawLoading; + this.loop(0); + + const onError = (ev) => { + console.log(ev); + this.loadingError = true; + }; + + for (const id in this.data) { + if (this.data[id].indexOf(".png") != -1) { + this.res[id] = new Image(); + this.res[id].src = this.data[id]; + this.res[id].onerror = onError + this.res[id].onload = (ev) => { + this.res[id].onload = null; + ev.currentTarget.removeEventListener("error", onError); + this.resSize += 1; + }; + continue; + } + if (this.data[id].indexOf(".ogg") != -1) { + this.res[id] = new Audio(); + this.res[id].src = this.data[id]; + this.res[id].autoplay = false; + this.res[id].addEventListener("error", onError); + this.res[id].oncanplaythrough = (ev) => { + this.res[id].oncanplaythrough = null; + ev.currentTarget.removeEventListener("error", onError); + this.resSize += 1; + }; + continue; + } + if (this.data[id].indexOf(".json") != -1) { + let xhr = new window.XMLHttpRequest(); + xhr.open("GET", this.data[id]); + xhr.responseType = "json"; + xhr.addEventListener("error", onError); + xhr.onload = (ev) => { + ev.currentTarget.removeEventListener("error", onError); + xhr.onload = null; + if (xhr.status == 200) { + this.res[id] = xhr.response; + this.resSize += 1; + } else { + console.log(ev); + this.loadingError = true; + } + }; + xhr.send(); + continue; + } + } + } + + // erases the canvas and sets the scaling + drawStart() { + this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); + this.ctx.save(); + this.ctx.scale(this.scale, this.scale); + } + + // restores the context + drawEnd() { + this.ctx.restore(); + } + + // won't use drawStart/drawEnd because may render regular fonts + drawLoading() { + this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); + this.ctx.save(); + + // height of the loading bar + const h = 6; + + if (this.loadingError == true) { + this.ctx.fillStyle = "rgb(255, 255, 255)"; + this.ctx.font = "caption"; + this.ctx.fillText( + "ERROR Loading Resources", + Math.floor(this.width * 0.1 * this.scale), + Math.floor((this.height / 2 - h - 2) * this.scale) + ); + } + + this.ctx.scale(this.scale, this.scale); + + this.ctx.fillStyle = "rgb(128, 128, 128)"; + this.ctx.fillRect(Math.floor(this.width * 0.1), Math.floor(this.height / 2) - h, this.width - Math.floor(this.width * 0.2), h); + this.ctx.fillStyle = "rgb(255, 255, 255)"; + this.ctx.fillRect(Math.floor(this.width * 0.1), Math.floor(this.height / 2) - h, ( + Math.floor(this.resSize * (this.width - Math.floor(this.width * 0.2)) / this.dataSize) + ), h); + + this.ctx.restore(); + + // we don't do this on update because we want + // the progress bar to finish drawing + if (this.resSize == this.dataSize) { + console.log("Loader done"); + + document.addEventListener("keydown", (ev) => { + this.keyDown(ev) + }, false); + document.addEventListener("keyup", (ev) => { + this.keyUp(ev) + }, false); + + this.init(); + this._update = this.update; + this._draw = this.draw; + } + } + + playSnd(playable, loop, clone) { + if (this.playCount < this.playLimit) { + this.playCount += 1; + + if (clone || false) { + playable = playable.cloneNode(true) + } + playable.onended = (ev) => { + playable.onended = null; + this.playCount -= 1; + }; + playable.loop = loop || false; + playable.play(); + } + } + + keyDown(ev) { + let key = this.controls[ev.keyCode]; + if (key != undefined) { + this.keys[key] = true; + ev.preventDefault(); + } + } + + keyUp(ev) { + let key = this.controls[ev.keyCode]; + if (key != undefined) { + this.keys[key] = false; + } + } +} diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..808ff4a --- /dev/null +++ b/js/main.js @@ -0,0 +1,11 @@ +window.addEventListener("DOMContentLoaded", (ev) => { + var canvas = document.getElementById("game"); + if (canvas.getContext) { + var game = new MyGame(canvas); + game.start(); + } else { + canvas.style.backgroundColor = "rgb(21, 21, 21)"; + canvas.insertAdjacentHTML("afterend", "<p>No Canvas 2D support found, please try a different browser.</p>"); + console.log("No canvas 2D support found"); + } +}); diff --git a/js/mygame.js b/js/mygame.js new file mode 100644 index 0000000..6293150 --- /dev/null +++ b/js/mygame.js @@ -0,0 +1,40 @@ +const floor = Math.floor; +const max = Math.max; +const min = Math.min; + +class MyGame extends Game { + constructor(canvas) { + super(canvas); + this.width = 320; + this.height = 240; + + this.data = { + sound: "snd/test.ogg", + world: "json/world.json", + player: "img/player.png" + }; + this.dataSize = Object.keys(this.data).length; + } + + init() { + /* log the JSON */ + console.log(this.res.world); + } + + update(dt) { + } + + draw() { + this.drawStart(); + + /* draw an image */ + this.ctx.drawImage(this.res.player, 0, 0); + + /* play a sound then z is pressed */ + if (this.keys["a"]) { + this.playSnd(this.res.sound); + } + + this.drawEnd(); + } +} |