diff --git a/public/static/js/lib/pallet.js b/public/static/js/lib/pallet.js new file mode 100644 index 0000000..b1f7f83 --- /dev/null +++ b/public/static/js/lib/pallet.js @@ -0,0 +1,184 @@ +function Pallet(canvas, options) { + var self = this; + + options = options || {}; + + if(typeof canvas == 'string') { + canvas = document.getElementById(canvas.replace('#', '')); + } else if(!canvas) { + canvas = document.getElementsByTagName('canvas')[0]; + if(!canvas) return false; + } else if(canvas.tagName != 'CANVAS') { + return false; + } + + var context = canvas.getContext('2d'); + + this.canvas = canvas; + this.context = context; + + if (!context.imageSmoothingEnabled) { + context.webkitImageSmoothingEnabled = options.imageSmoothing || true; + context.mozImageSmoothingEnabled = options.imageSmoothing || true; + } else { + context.imageSmoothingEnabled = options.imageSmoothing || true; + } + + context.save(); + + // Render single colour unstroked circle. + this.circle = function(color, x, y, radius) { + context.fillStyle = color; + context.beginPath(); + context.arc(x, y, radius, 0, Math.PI * 2, false); + context.fill(); + }; + + // Clear canvas. + this.clear = function(x, y, w, h, color) { + if (!h) { + context.clearRect(0, 0, canvas.width, canvas.height); + } else { + context.clearRect(x, y, w, h); + } + }; + + this.clipRect = function(x, y, w, h) { + this.context.beginPath(); + this.context.rect(x, y, w, h); + this.context.clip(); + this.context.closePath(); + }; + + // Returns the entire canvas as a base64-encoded image string. + this.dataURL = function() { + return canvas.toDataURL(); + } + + // Fill screen with color. + this.fill = function(color) { + context.fillStyle = color; + context.fillRect(0, 0, canvas.width, canvas.height); + } + + // Resize canvas to window. + this.fillScreen = function(minX, minY) { + canvas.width = Math.max(window.innerWidth, minX || 0); + canvas.height = Math.max(window.innerHeight, minY || 0); + canvas.style.width = canvas.width + 'px'; + canvas.style.height = canvas.height + 'px'; + + self.normalizeSize(); + }; + + // Draw image. If only width is given, it will be used a scale factor. + this.image = function (image, x, y, rotation, w, h) { + if (typeof image == 'string') { + var src = image; + var img = new Image(); + img.src = src; + } else { + var src = image.src; + var img = image; + } + + if (w && !h) { + w = img.width * w; + var h = img.height * w; + } else { + var w = w || img.width; + var h = h || img.height; + } + + x = x || 0; + y = y || 0; + rotation = rotation || 0; + + if (rotation) { + context.save(); + context.translate(x + w / 2, y + h / 2); + context.rotate(rotation); + context.drawImage(img, -w / 2, -h / 2, w, h); + context.restore(); + } else { + context.drawImage(img, x, y, w, h); + } + }; + + // Set canvas size to canvas element size. + this.normalizeSize = function() { + var style = window.getComputedStyle(canvas, null); + + canvas.width = +style.width.replace('px', ''); + canvas.height = +style.height.replace('px', ''); + + context.save(); + }; + + // Set default opacity. + this.opacity = function(alpha) { + alpha = alpha || 1; + context.globalAlpha = alpha; + }; + + // Draw rectangular outline. + this.outline = function(color, x, y, w, h, s) { + context.strokeStyle = color; + context.lineWidth = s || 1; + context.strokeRect(x + 0.5, y + 0.5, w - 1, h - 1); + }; + + // Render single colour unstroked rectangle. + this.rect = function(color, x, y, w, h) { + context.fillStyle = color; + context.fillRect(x, y, w, h); + }; + + // Restore canvas then save again. + this.reset = function() { + context.restore(); + context.save(); + }; + + // Resize canvas. + this.resize = function(w, h) { + h = h || canvas.width; + + canvas.width = w; + canvas.height = h; + canvas.style.width = w + 'px'; + canvas.style.height = h + 'px'; + } + + // Just restore. + this.restore = function() { + context.restore(); + }; + + this.save = function() { + context.save(); + }; + + // Render rect with equal sides. + this.square = function(color, x, y, l) { + self.rect(color, x, y, l, l); + }; + + // Render text. + this.text = function(string, x, y, color, font, size, align, baseline) { + context.fillStyle = color || '#fff'; + if(+size == '' + size) size = size + 'px'; + context.font = size + ' ' + font; + context.textAlign = align || 'left'; + context.textBaseline = baseline || 'top'; + context.fillText(string, x, y); + }; + + // Transform canvas. + this.view = function (x, y, zoom, rotation) { + context.save(); + context.translate(x, y); + context.rotate(rotation); + if (zoom) this.context.scale(zoom, zoom); + } +} diff --git a/public/static/js/wingbase/render/grid.js b/public/static/js/wingbase/render/grid.js new file mode 100644 index 0000000..a8550b6 --- /dev/null +++ b/public/static/js/wingbase/render/grid.js @@ -0,0 +1,166 @@ +class GridRenderer { + constructor(renderer) { + this.pallet = renderer.pallet; + this.dummyPallet = renderer.dummyPallet; + this.canvas = renderer.canvas; + this.context = renderer.context; + + this.panels = new Map(); + } + + render() { + let cpos = game.world.center; + let cx = cpos.x; + let cy = cpos.y; + let cw = this.canvas.width; + let ch = this.canvas.height; + + let gridx = cx % 100; + let gridy = cy % 100; + let lastBlue = false; + + const PANEL_SIZE = 300; + const TILE_SIZE = 50; + + window.ren = []; + this.pallet.opacity(1); + /* + let sx = Math.floor((cx - cw / 2) / PANEL_SIZE) * PANEL_SIZE; + let sy = Math.floor((cy - ch / 2) / PANEL_SIZE) * PANEL_SIZE; + for (var x = sx; x < cx + cw / 2 + PANEL_SIZE; x += PANEL_SIZE) { + for (var y = sy; y < ch + cy / 2 + PANEL_SIZE; y += PANEL_SIZE) { + let px = x; + let py = y; + let key = px + '.' + py; + + if (!this.panels.has(key)) { + this.generate(px, py, PANEL_SIZE, PANEL_SIZE); + } + + this.context.drawImage(this.panels.get(key), px, py); + } + } + this.pallet.opacity(1); + */ + let sx = Math.floor((cx - cw / 2) / TILE_SIZE) * TILE_SIZE; + let sy = Math.floor((cy - ch / 2) / TILE_SIZE) * TILE_SIZE; + let ex = sx + cw + TILE_SIZE; + let ey = sy + ch + TILE_SIZE; + this.context.beginPath(); + this.context.strokeStyle = '#fff'; + this.context.lineWidth = 1; + + let b = game.world.bounds; + b = { + left: b.left * SCALE, + right: b.right * SCALE, + top: b.top * SCALE, + bottom: b.bottom * SCALE + }; + let ts = TILE_SIZE + 1; + let tss = ts / SCALE; + + for (let x = sx; x < sx + cw * 2; x += TILE_SIZE) { + this.context.beginPath(); + this.context.moveTo(x, sy); + this.context.strokeStyle = '#fff'; + this.context.globalAlpha = 0.05; + if (sy < b.top) { + this.context.globalAlpha = 0.17; + this.context.strokeStyle = '#8af'; + this.context.lineTo(x, b.top); + this.context.stroke(); + this.context.globalAlpha = 0.05; + this.context.strokeStyle = '#fff'; + } + if (x < b.left || x > b.right) { + this.context.globalAlpha = 0.17; + this.context.strokeStyle = '#8af'; + } + this.context.lineTo(x, ey); + this.context.stroke(); + if (ey > b.bottom) { + this.context.globalAlpha = 0.17; + this.context.strokeStyle = '#8af'; + this.context.beginPath(); + this.context.moveTo(x, b.bottom); + this.context.lineTo(x, ey); + this.context.stroke(); + } + } + for (let y = sy; y < sy + ch * 2; y += TILE_SIZE) { + this.context.beginPath(); + this.context.moveTo(sx, y); + this.context.strokeStyle = '#fff'; + this.context.globalAlpha = 0.05; + if (sx < b.left) { + this.context.globalAlpha = 0.17; + this.context.strokeStyle = '#8af'; + this.context.lineTo(b.left, y); + this.context.stroke(); + this.context.globalAlpha = 0.05; + this.context.strokeStyle = '#fff'; + } + if (y < b.top || y > b.bottom) { + this.context.globalAlpha = 0.17; + this.context.strokeStyle = '#8af'; + } + this.context.lineTo(ex, y); + this.context.stroke(); + if (ex > b.right) { + this.context.globalAlpha = 0.17; + this.context.strokeStyle = '#8af'; + this.context.beginPath(); + this.context.moveTo(b.right, y); + this.context.lineTo(ex, y); + this.context.stroke(); + } + } + this.context.globalAlpha = 1; + + } + + generate(x, y, w, h) { + this.dummyPallet.resize(w, h); + + const TILE_SIZE = 50; + + let sx = Math.floor(x / TILE_SIZE) * TILE_SIZE; + let sy = Math.floor(y / TILE_SIZE) * TILE_SIZE; + let ex = sx + w; + let ey = sy + h; + + for (let tx = sx; tx < ex; tx += TILE_SIZE) { + for (let ty = sy; ty < ey; ty += TILE_SIZE) { + let rx = tx - sx; + let ry = ty - sy; + + let wx = (tx / SCALE) | 0; + let wy = (ty / SCALE) | 0; + + let b = game.world.bounds; + let ts = TILE_SIZE + 1; + let tss = ts / SCALE; + + if (wx > b.right - tss || wx < b.left + tss + || wy > b.bottom - tss || wy < b.top + tss) { + let context = this.dummtPallet.context; + context.save(); + context.globalCompositeOperation="xor"; + context.beginPath(); + //context.rect(0, +// Was here, clip inverse + this.dummyPallet.outline('#fff', rx, ry, ts, ts, 0.03); + this.dummyPallet.restore(); + this.dummyPallet.outline('#8af', rx, ry, ts, ts, 0.17); + } else { + this.dummyPallet.outline('#fff', rx, ry, ts, ts, 0.03); + } + } + } + + let img = new Image(); + img.src = this.dummyPallet.dataURL(); + this.panels.set(x + '.' + y, img); + } +} diff --git a/public/static/js/wingbase/render/render.js b/public/static/js/wingbase/render/render.js index 74f3d06..c5ecb80 100644 --- a/public/static/js/wingbase/render/render.js +++ b/public/static/js/wingbase/render/render.js @@ -2,13 +2,15 @@ class Renderer { constructor() { - let pallet = new Pallet(); + let pallet = new Pallet('#wingbase-canvas'); + let dummyPallet = new Pallet('#dummy-canvas'); let canvas = pallet.canvas; let context = pallet.context; - this.pallet = pallet; + this.dummyPallet = dummyPallet; this.canvas = canvas; this.context = context; + this.pallet = pallet; this.effects = new Set(); @@ -16,6 +18,7 @@ class Renderer { window.addEventListener('resize', _ => pallet.fillScreen(1000, 600)); this.bodyRenderer = new BodyRenderer(this); + this.gridRenderer = new GridRenderer(this); this.dischargeRenderer = new DischargeRenderer(this); } @@ -52,12 +55,12 @@ class Renderer { this.pallet.image(img, bgx, bgy, 0, img.width * 1.5, img.height * 1.5); this.pallet.opacity(1); - this.renderGrid(); - let vx = -game.world.center.x; let vy = -game.world.center.y; this.pallet.view(vx, vy, false, 0); + this.gridRenderer.render(); + for (var id in game.world.bodies) { this.bodyRenderer.render(game.world.bodies[id]); } @@ -80,42 +83,6 @@ class Renderer { this.pallet.restore(); } - renderGrid() { - let cpos = game.world.center; - let cx = -cpos.x; - let cy = -cpos.y; - let cw = this.canvas.width; - let ch = this.canvas.height; - - let gridx = cx % 50; - let gridy = cy % 50; - let lastBlue = false; - - let b = game.world.bounds; - - this.pallet.opacity(0.05); - for (var x = gridx - cw / 2 - 50; x < cw + 50; x += 50) { - for (var y = gridy - ch / 2 - 50; y < ch + 50; y += 50) { - var wx = ((-cx + x) / SCALE) | 0; - var wy = ((-cy + y) / SCALE) | 0; - if (wx > b.right || wx < b.left || wy > b.bottom || wy < b.top) { - if (!lastBlue) { - this.pallet.opacity(0.2); - lastBlue = true; - } - this.pallet.outline('#8af', x, y, 51, 51, 1); - } else { - if (lastBlue) { - this.pallet.opacity(0.05); - lastBlue = false; - } - this.pallet.outline('#fff', x, y, 51, 51, 1); - } - } - } - this.pallet.opacity(1); - } - addEffect(data) { this.effects.add(new Effect(data)); } diff --git a/public/static/js/wingbase/utils.js b/public/static/js/wingbase/utils.js new file mode 100644 index 0000000..1b80abd --- /dev/null +++ b/public/static/js/wingbase/utils.js @@ -0,0 +1,12 @@ +class Utils { + static rotatedImage(context, img, x, y, rotation) { + let w = img.width; + let h = img.height; + + context.save(); + context.translate(x + w / 2, y + h / 2); + context.rotate(rotation); + context.drawImage(img, -w / 2, -h / 2, w, h); + context.restore(); + } +} diff --git a/public/static/js/wingbase/world/discharge.js b/public/static/js/wingbase/world/discharge.js index 8c7468d..fe9c854 100644 --- a/public/static/js/wingbase/world/discharge.js +++ b/public/static/js/wingbase/world/discharge.js @@ -30,7 +30,7 @@ class Discharge { update(data) { let values = {}; - console.log(data); + //console.log(data); this.interface.order.forEach(v => values[v] = data.shift()); this.x = values.x; this.y = values.y; diff --git a/public/static/js/wingbase/world/physics.js b/public/static/js/wingbase/world/physics.js index f739abb..a55c414 100644 --- a/public/static/js/wingbase/world/physics.js +++ b/public/static/js/wingbase/world/physics.js @@ -11,7 +11,7 @@ class Physics { var b2DebugDraw = Box2D.Dynamics.b2DebugDraw; var debugDraw = new b2DebugDraw(); - debugDraw.SetSprite(document.getElementById("wingbase_canvas").getContext("2d")); + debugDraw.SetSprite(document.getElementById("wingbase-canvas").getContext("2d")); debugDraw.SetDrawScale(SCALE); debugDraw.SetFillAlpha(0.3); debugDraw.SetLineThickness(1.0); diff --git a/public/static/js/wingbase/world/world.js b/public/static/js/wingbase/world/world.js index 0fda3db..501adea 100644 --- a/public/static/js/wingbase/world/world.js +++ b/public/static/js/wingbase/world/world.js @@ -16,7 +16,7 @@ class World { } add(data) { - if(data.form != 'body') console.log(data); + //if(data.form != 'body') console.log(data); if (data.form == 'body') { this.addBody(data); } else if (data.form == 'discharge') { diff --git a/public/stylus/styles.styl b/public/stylus/styles.styl index 0649526..51bdb60 100644 --- a/public/stylus/styles.styl +++ b/public/stylus/styles.styl @@ -21,7 +21,10 @@ canvas -khtml-user-select none -moz-user-select none -ms-user-select none - user-select: none + user-select none + +canvas#dummy-canvas + display none .small font-family PixelArial diff --git a/public/views/game.pug b/public/views/game.pug index f72cc73..a429239 100644 --- a/public/views/game.pug +++ b/public/views/game.pug @@ -8,11 +8,12 @@ block head script(src='js/lib/domeventslevel3.shim.min.js') script(src='socket.io/socket.io.js') script(src='js/lib/box2dweb.min.js') - script(src='https://rawgit.com/Asraelite/pallet.js/master/pallet.js') + script(src='js/lib/pallet.js') script(src='wingbase.min.js') - + block body - canvas#wingbase_canvas + canvas#wingbase-canvas | Sorry, your browser does not currently support HTML5 Canvas. + canvas#dummy-canvas #gui include gui/gui.pug