(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i c !== child); return child; } map(f) { return this.children.map(f); } update(dt, t) { this.children = this.children.filter(child => { if (child.update) { child.update(dt, t, this); } return child.dead ? false : true; }); } } module.exports = Container; },{}],2:[function(require,module,exports){ var Container = require("./Container"), CanvasRenderer = require('./renderer/CanvasRenderer') ; const STEP = 1 / 60; const FRAME_MAX = 5 * STEP; class Game { constructor(w, h, pixelated, parent = "#board") { this.w = w; this.h = h; this.renderer = new CanvasRenderer(w, h); document.querySelector(parent).appendChild(this.renderer.view); if (pixelated) { this.renderer.setPixelated(); } this.scene = new Container(); } run(gameUpdate = () => { }) { let dt = 0; let last = 0; const loop = ms => { requestAnimationFrame(loop); const t = ms / 1000; dt = Math.min(t - last, FRAME_MAX); last = t; this.scene.update(dt, t); gameUpdate(dt, t); this.renderer.render(this.scene); }; requestAnimationFrame(loop); } } module.exports = Game; },{"./Container":1,"./renderer/CanvasRenderer":14}],3:[function(require,module,exports){ class Sprite { constructor(texture) { this.texture = texture; this.pos = { x: 0, y: 0 }; this.anchor = { x: 0, y: 0 }; this.scale = { x: 1, y: 1 }; this.rotation = 0; } } module.exports = Sprite; },{}],4:[function(require,module,exports){ class SpriteSheetXML { constructor(url) { this.array = []; this.fetchXMLtoArray(url); } fetchXMLtoArray(url) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); xhr.send(null); if (xhr.status === 200) { var children = xhr.responseXML.children[0].children; for (let index = 0; index < children.length; index++) { const element = children[index]; this.array.push({ name: element.attributes.name.nodeValue, x: element.attributes.x.nodeValue, y: element.attributes.y.nodeValue, width: element.attributes.width.nodeValue, height: element.attributes.height.nodeValue }); } } else { console.error('XML file cannot be loaded!') } } findIndex(attribute, value) { for (let index = 0; index < this.array.length; index++) { const element = this.array[index]; if (element[attribute] == value) { return index; } } } } module.exports = SpriteSheetXML; },{}],5:[function(require,module,exports){ class Text { constructor(text = "", style = {}) { this.pos = { x: 0, y: 0 }; this.text = text; this.style = style; } } module.exports = Text; },{}],6:[function(require,module,exports){ class Texture { constructor(url) { this.img = new Image(); this.img.src = url; } } module.exports = Texture; },{}],7:[function(require,module,exports){ var Container = require("./Container"), TileSprite = require("./TileSprite") ; class TileMap extends Container { constructor(tiles, mapW, mapH, tileW, tileH, texture) { super(); this.mapW = mapW; this.mapH = mapH; this.tileW = tileW; this.tileH = tileH; this.w = mapW * tileW; this.h = mapH * tileH; this.children = tiles.map((frame, i) => { const s = new TileSprite(texture, tileW, tileH); s.frame = frame; s.pos.x = i % mapW * tileW; s.pos.y = Math.floor(i / mapW) * tileH; return s; }); } } module.exports = TileMap; },{"./Container":1,"./TileSprite":9}],8:[function(require,module,exports){ var Container = require("./Container"), TileSpriteXML = require("./TileSpriteXML") ; class TileMapXML extends Container { constructor(tiles, mapW, mapH, texture, xml) { super(texture); this.mapW = mapW; this.mapH = mapH; this.tileW = xml.array[tiles[0]].width; this.tileH = xml.array[tiles[0]].height; this.w = mapW * this.tileW; this.h = mapH * this.tileH; this.children = tiles.map((frame, i) => { const s = new TileSpriteXML(texture, xml, frame); s.frame = frame; s.pos.x = i % mapW * this.tileW; s.pos.y = Math.floor(i / mapW) * this.tileH; return s; }); } } module.exports = TileMapXML; },{"./Container":1,"./TileSpriteXML":10}],9:[function(require,module,exports){ var Sprite = require("./Sprite"); class TileSprite extends Sprite { constructor(texture, w, h) { super(texture); this.tileW = w; this.tileH = h; this.frame = { x: 0, y: 0 }; } } module.exports = TileSprite; },{"./Sprite":3}],10:[function(require,module,exports){ var Sprite = require("./Sprite"); class TileSpriteXML extends Sprite { constructor(texture, xml, index) { super(texture); var src = xml.array[index]; this.imgPos = { x: src['x'], y: src['y'] }; this.width = src['width']; this.height = src['height']; } } module.exports = TileSpriteXML; },{"./Sprite":3}],11:[function(require,module,exports){ class KeyControls { constructor() { this.keys = {}; // Bind event handlers document.addEventListener("keydown", e => { if ([37, 38, 39, 40].indexOf(e.which) >= 0) { e.preventDefault(); } this.keys[e.which] = true; }, false); document.addEventListener('keyup', e => { this.keys[e.which] = false; }, false); } get action() { // Spacebar return this.keys[32]; } get x() { // Arrow Left or A (WASD) if (this.keys[37] || this.keys[65]) { return -1; } // Arrow Right or D (WASD) if (this.keys[39] || this.keys[68]) { return 1; } return 0; } get y() { // Arrow Up or W (WASD) if (this.keys[38] || this.keys[87]) { return -1; } // Arrow Down or S (WASD) if (this.keys[40] || this.keys[83]) { return 1; } return 0; } key(key, value) { if (value !== undefined) { this.keys[key] = value; } return this.keys[key]; } reset() { for (let key in this.keys) { this.keys[key] = false; } } } module.exports = KeyControls; },{}],12:[function(require,module,exports){ class MouseControls { constructor(container) { this.el = container || document.body; // State this.pos = { x: 0, y: 0 }; this.isDown = false; this.pressed = false; this.released = false; // Handlers document.addEventListener('mousemove', this.move.bind(this), false); document.addEventListener('mousedown', this.down.bind(this), false); document.addEventListener('mouseup', this.up.bind(this), false); } mousePosFromEvent({ clientX, clientY }) { const { el, pos } = this; const rect = el.getBoundingClientRect(); const xr = el.width / el.clientWidth; const yr = el.height / el.clientHeight; pos.x = (clientX - rect.left) * xr; pos.y = (clientY - rect.top) * yr; } move(e) { this.mousePosFromEvent(e); } down(e) { this.isDown = true; this.pressed = true; this.mousePosFromEvent(e); } up() { this.isDown = false; this.released = true; } update() { this.released = false; this.pressed = false; } } module.exports = MouseControls; },{}],13:[function(require,module,exports){ var Container = require("./Container.js"), CanvasRenderer = require("./renderer/CanvasRenderer.js"), Game = require("./Game.js"), math = require("./utilities/math.js"), KeyControls = require("./controls/KeyControls.js"), MouseControls = require("./controls/MouseControls.js"), Sprite = require("./Sprite.js"), TileMap = require("./TileMap.js"), TileMapXML = require("./TileMapXML.js"), TileSprite = require("./TileSprite.js"), TileSpriteXML = require("./TileSpriteXML.js"), Text = require("./Text.js"), Texture = require("./Texture.js"), SpriteSheetXML = require("./SpriteSheetXML.js") ; module.exports = { CanvasRenderer, Container, Game, math, KeyControls, MouseControls, Sprite, TileMap, TileMapXML, TileSprite, SpriteSheetXML, TileSpriteXML, Text, Texture }; },{"./Container.js":1,"./Game.js":2,"./Sprite.js":3,"./SpriteSheetXML.js":4,"./Text.js":5,"./Texture.js":6,"./TileMap.js":7,"./TileMapXML.js":8,"./TileSprite.js":9,"./TileSpriteXML.js":10,"./controls/KeyControls.js":11,"./controls/MouseControls.js":12,"./renderer/CanvasRenderer.js":14,"./utilities/math.js":15}],14:[function(require,module,exports){ class CanvasRenderer { constructor(w, h) { const canvas = document.createElement("canvas"); this.w = canvas.width = w; this.h = canvas.height = h; this.view = canvas; this.ctx = canvas.getContext("2d"); this.ctx.textBaseLine = "top"; } setPixelated() { this.ctx['imageSmoothingEnabled'] = false; /* standard */ this.ctx['mozImageSmoothingEnabled'] = false; /* Firefox */ this.ctx['oImageSmoothingEnabled'] = false; /* Opera */ this.ctx['webkitImageSmoothingEnabled'] = false; /* Safari */ this.ctx['msImageSmoothingEnabled'] = false; /* IE */ } render(container, clear = true) { const { ctx } = this; function renderRec(container) { // Render container children container.children.forEach(child => { if (child.visible == false) { return; } ctx.save(); if (child.pos) { ctx.translate(Math.round(child.pos.x), Math.round(child.pos.y)); } if (child.anchor) { ctx.translate(child.anchor.x, child.anchor.y); } if (child.scale) { ctx.scale(child.scale.x, child.scale.y); } if (child.rotation) { const px = child.pivot ? child.pivot.x : 0; const py = child.pivot ? child.pivot.y : 0; ctx.translate(px, py); ctx.rotate(child.rotation); ctx.translate(-px, -py); } if (child.text) { const { font, fill, align } = child.style; if (font) ctx.font = font; if (fill) ctx.fillStyle = fill; if (align) ctx.textAlign = align; ctx.fillText(child.text, 0, 0); } else if (child.texture) { const img = child.texture.img; if (child.tileW && child.tileH) { ctx.drawImage( img, child.frame.x * child.tileW, child.frame.y * child.tileH, child.tileW, child.tileH, 0, 0, child.tileW, child.tileH ); } else if (child.imgPos && child.width && child.height) { ctx.drawImage( img, child.imgPos.x, child.imgPos.y, child.width, child.height, 0, 0, child.width, child.height ); } else { ctx.drawImage(img, 0, 0); } } // Handle children with children if (child.children) { renderRec(child); } ctx.restore(); }) } if (clear) { ctx.clearRect(0, 0, this.w, this.h); } renderRec(container); } } module.exports = CanvasRenderer; },{}],15:[function(require,module,exports){ function rand(min, max) { return Math.floor(randf(min, max)); } function randf(min, max) { if (max == null) { max = min || 1; min = 0; } return Math.random() * (max - min) + min; } function randOneFrom(items) { return items[rand(items.length)]; } function randOneIn(max = 2) { return rand(0, max) === 0; } module.exports = { rand, randf, randOneFrom, randOneIn }; },{}],16:[function(require,module,exports){ var asdf = require('../../../asdf/index'); const { Container, CanvasRenderer, KeyControls, MouseControls, Text, Texture, Sprite } = asdf; // Board Setup const w = 640; const h = 300; const renderer = new CanvasRenderer(w, h); document.querySelector("#board").appendChild(renderer.view); // Setup game variables let dt = 0; let last = 0; let lastShot = 0; let lastSpawn = 0; let spawnSpeed = 1.0; let scoreAmount = 0; let gameOver = false; // Setup game objects const scene = new Container(); // Load game textures const textures = { background: new Texture("./res/images/bg.png"), spaceship: new Texture("./res/images/spaceship.png"), bullet: new Texture("./res/images/bullet.png"), baddie: new Texture("./res/images/baddie.png") } // Spaceship const controls = new KeyControls(); const ship = new Sprite(textures.spaceship); ship.pos.x = 120; ship.pos.y = h / 2 - 16; ship.update = function (dt, t) { const { pos } = this; pos.x += controls.x * dt * 300; pos.y += controls.y * dt * 300; if (pos.x < 0) pos.x = 0; if (pos.x > w - 32) pos.x = w - 32; if (pos.y < 0) pos.y = 0; if (pos.y > h - 32) pos.y = h - 32; } // Bullets const bullets = new Container(); function fireBullet(x, y) { const bullet = new Sprite(textures.bullet); bullet.pos.x = x; bullet.pos.y = y; bullet.update = function (dt, t) { bullet.pos.x += 400 * dt; } bullets.add(bullet); } // Bad guys const baddies = new Container(); function spawnBaddie(x, y, speed) { const baddie = new Sprite(textures.baddie); baddie.pos.x = x; baddie.pos.y = y; baddie.update = function (dt) { this.pos.x += speed * dt; this.pos.y += Math.sin(this.pos.x / 15) * 1; }; baddies.add(baddie); } // Show score const score = new Text(`${scoreAmount}`, { font: "15pt Visitor", fill: "#000000", align: "left" }); score.pos.x = 50; score.pos.y = 15; score.update = function () { if (gameOver) { score.pos.x = w / 2; score.pos.y = (h / 3) * 2; score.text = `Score: ` + `${scoreAmount}`; score.style.align = "center"; score.style.font = "24pt Visitor" } else { score.text = `${scoreAmount}`; } } // Gameover function doGameOver() { const gameOverMessage = new Text(`Game Over`, { font: "45pt Visitor", fill: "#000000", align: "center" }); gameOverMessage.pos.x = w / 2; gameOverMessage.pos.y = h / 3; scene.add(gameOverMessage); scene.remove(ship); scene.remove(baddies); scene.remove(bullets); gameOver = true; } // Add game objects scene.add(new Sprite(textures.background)); scene.add(ship); scene.add(bullets); scene.add(baddies); scene.add(score); // Looping Code function loopme(ms) { requestAnimationFrame(loopme); const t = ms / 1000; dt = t - last; last = t; // Game logic code if (controls.action && t - lastShot > 0.15) { lastShot = t; fireBullet(ship.pos.x + 24, ship.pos.y + 10); } // Spawn bad guys if (t - lastSpawn > spawnSpeed) { lastSpawn = t; const speed = -50 - (Math.random() * Math.random() * 100); const position = Math.random() * (h - 24); spawnBaddie(w, position, speed); spawnSpeed = spawnSpeed < 0.05 ? 0.6 : spawnSpeed * 0.97 + 0.001; } // Destroy bullets when they go out of the screen baddies.children.forEach(baddie => { bullets.children.forEach(bullet => { let dx_b = baddie.pos.x + 16 - (bullet.pos.x + 8); let dy_b = baddie.pos.y + 16 - (bullet.pos.y + 8); if (Math.sqrt(dx_b * dx_b + dy_b * dy_b) < 24) { bullet.dead = true; baddie.dead = true; if (!gameOver) { scoreAmount += Math.floor(t); } } if (bullet.pos.x > w + 20) { bullet.dead = true; } }); let dx_s = baddie.pos.x + 16 - (ship.pos.x + 16) let dy_s = baddie.pos.y + 16 - (ship.pos.y + 16) if (Math.sqrt(dx_s * dx_s + dy_s * dy_s) < 32) { if (!gameOver) { doGameOver(); } baddie.dead = true; } if (baddie.pos.x < -32) { if (!gameOver) { doGameOver(); } baddie.dead = true; } }); scene.update(dt, t); renderer.render(scene); } requestAnimationFrame(loopme); },{"../../../asdf/index":13}]},{},[16]);