diff --git a/game/Bitmap.js b/game/Bitmap.js deleted file mode 100644 index 6556195..0000000 --- a/game/Bitmap.js +++ /dev/null @@ -1,78 +0,0 @@ -import BoundingRectangle from './BoundingRectangle.js' - -export default class Bitmap { - constructor(width, height, rgba = null) { - this._w = width - this._h = height - this._com = 4 // number of components per pixel (RGBA) - this._boundingRect = new BoundingRectangle(0, this._w - 1, 0, this._h - 1) - const len = this._w * this._h * this._com - this._data = new Uint8ClampedArray(len) - - if (rgba) { - for (let i = 0; i < len; i += 4) { - this._data[i] = rgba[0] - this._data[i + 1] = rgba[1] - this._data[i + 2] = rgba[2] - this._data[i + 3] = rgba[3] - } - } - - // public - this.width = this._w - this.height = this._h - } - - toImage() { - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d'); - - canvas.width = this._w; - canvas.height = this._h; - - const imgData = ctx.createImageData(canvas.width, canvas.height); - imgData.data.set(this._data); - ctx.putImageData(imgData, 0, 0); - - return new Promise((resolve) => { - - const img = document.createElement('img') - img.onload = () => { - resolve(img) - } - img.src = canvas.toDataURL() - return img - }) - } - - getPix(x, y, out) { - if (x < 0 || y < 0 || x >= this._w || y >= this._h) { - return false - } - x = Math.round(x) - y = Math.round(y) - const idx = (y * 4 * this._w) + (x * 4) - out[0] = this._data[idx] - out[1] = this._data[idx + 1] - out[2] = this._data[idx + 2] - out[3] = this._data[idx + 3] - return true - } - - putPix(x, y, rgba) { - if (x < 0 || y < 0 || x >= this._w || y >= this._h) { - return - } - x = Math.round(x) - y = Math.round(y) - const idx = (y * this._com * this._w) + (x * this._com) - this._data[idx] = rgba[0] - this._data[idx + 1] = rgba[1] - this._data[idx + 2] = rgba[2] - this._data[idx + 3] = rgba[3] - } - - getBoundingRect() { - return this._boundingRect - } -} diff --git a/game/BoundingRectangle.js b/game/BoundingRectangle.js deleted file mode 100644 index 8312034..0000000 --- a/game/BoundingRectangle.js +++ /dev/null @@ -1,46 +0,0 @@ -import Point from './Point.js' - -export default class BoundingRectangle { - constructor(x0, x1, y0, y1) { - this.x0 = x0 - this.x1 = x1 - this.y0 = y0 - this.y1 = y1 - this.width = (x1 - x0) + 1 - this.height = (y1 - y0) + 1 - } - - div(d) { - this.x0 /= d - this.x1 /= d - this.y0 /= d - this.y1 /= d - } - - move(x, y) { - this.x0 += x - this.x1 += x - this.y0 += y - this.y1 += y - } - - moved(x, y) { - return new BoundingRectangle( - this.x0 + x, - this.x1 + x, - this.y0 + y, - this.y1 + y - ) - } - - center() { - return new Point( - this.x0 + this.width / 2, - this.y0 + this.height / 2, - ) - } - - centerDistance(other) { - return this.center().distance(other.center()) - } -} \ No newline at end of file diff --git a/game/Camera.js b/game/Camera.js index cd4cc4a..b51adc5 100644 --- a/game/Camera.js +++ b/game/Camera.js @@ -1,5 +1,3 @@ -import BoundingRectangle from "./BoundingRectangle.js" - export default class Camera { constructor(canvas) { this.x = 0 @@ -17,12 +15,12 @@ export default class Camera { } rect() { - return new BoundingRectangle( - - this.x, - - this.x + (this.width / this.zoom), - - this.y, - - this.y + (this.height / this.zoom), - ) + return { + x: -this.x, + y: -this.y, + w: this.width / this.zoom, + h: this.height / this.zoom, + } } move(x, y) { @@ -79,4 +77,11 @@ export default class Camera { y: (coord.y + this.y) * this.zoom, } } + + worldDimToViewport(dim) { + return { + w: dim.w * this.zoom, + h: dim.h * this.zoom, + } + } } diff --git a/game/CanvasAdapter.js b/game/CanvasAdapter.js deleted file mode 100644 index 5fc73c8..0000000 --- a/game/CanvasAdapter.js +++ /dev/null @@ -1,99 +0,0 @@ -import BoundingRectangle from './BoundingRectangle.js' - -export default class CanvasAdapter { - constructor(canvas) { - this._canvas = canvas - /** @type {CanvasRenderingContext2D} */ - this._ctx = this._canvas.getContext('2d') - this._w = this._canvas.width - this._h = this._canvas.height - this._boundingRect = new BoundingRectangle(0, this._w - 1, 0, this._h - 1) - - this._imageData = this._ctx.createImageData(this._w, this._h) - this._data = this._imageData.data - - this._dirty = false - this._dirtyRect = {x0: 0, x1: 0, y0: 0, y1: 0} - this.width = this._w - this.height = this._h - } - - clear() { - this._imageData = this._ctx.createImageData(this._w, this._h) - this._data = this._imageData.data - this._dirty = false - } - clearRect(rects) { - for (let rect of rects) { - for (let x = rect.x0; x< rect.x1; x++) { - for (let y = rect.y0; y< rect.y1; y++) { - this.putPix(x, y, [0,0,0,0]) - } - } - } - } - - getPix(x, y, out) { - if (x < 0 || y < 0 || x >= this._w || y >= this._h) { - return false; - } - x = Math.round(x) - y = Math.round(y) - const idx = (y * 4 * this._w) + (x * 4) - out[0] = this._data[idx] - out[1] = this._data[idx + 1] - out[2] = this._data[idx + 2] - out[3] = this._data[idx + 3] - return true - } - - putPix(x, y, rgba) { - if (x < 0 || y < 0 || x >= this._w || y >= this._h) { - return null; - } - - x = Math.round(x) - y = Math.round(y) - const idx = (y * 4 * this._w) + (x * 4) - this._data[idx] = rgba[0] - this._data[idx + 1] = rgba[1] - this._data[idx + 2] = rgba[2] - this._data[idx + 3] = rgba[3] - - if (this._dirty) { - // merge - this._dirtyRect.x0 = Math.min(this._dirtyRect.x0, x) - this._dirtyRect.x1 = Math.max(this._dirtyRect.x1, x) - this._dirtyRect.y0 = Math.min(this._dirtyRect.y0, y) - this._dirtyRect.y1 = Math.max(this._dirtyRect.y1, y) - } else { - // set - this._dirty = true - this._dirtyRect.x0 = x - this._dirtyRect.x1 = x - this._dirtyRect.y0 = y - this._dirtyRect.y1 = y - } - } - - getBoundingRect() { - return this._boundingRect - } - - apply() { - if (this._dirty) { - this._ctx.putImageData( - this._imageData, - 0, - 0, - this._dirtyRect.x0, - this._dirtyRect.y0, - this._dirtyRect.x1 - this._dirtyRect.x0, - this._dirtyRect.y1 - this._dirtyRect.y0 - ) - this._dirty = null - } else { - this._ctx.putImageData(this._imageData, 0, 0) - } - } -} diff --git a/game/Color.js b/game/Color.js deleted file mode 100644 index 10484fb..0000000 --- a/game/Color.js +++ /dev/null @@ -1,22 +0,0 @@ -export function tint(c, f) { - return [ - Math.max(0, Math.min(255, Math.round((255 - c[0]) * f))), - Math.max(0, Math.min(255, Math.round((255 - c[1]) * f))), - Math.max(0, Math.min(255, Math.round((255 - c[2]) * f))), - c[3] - ] -} - -export function shade(c, f) { - return [ - Math.max(0, Math.min(255, Math.round(c[0] * f))), - Math.max(0, Math.min(255, Math.round(c[1] * f))), - Math.max(0, Math.min(255, Math.round(c[2] * f))), - c[3] - ] -} - -export default { - tint, - shade -} diff --git a/game/Graphics.js b/game/Graphics.js index ff668f0..ed09947 100644 --- a/game/Graphics.js +++ b/game/Graphics.js @@ -1,10 +1,4 @@ -import Bitmap from './Bitmap.js' - -function copyUint8ClampedArray(src) { - const arr = new Uint8ClampedArray(src.length) - arr.set(new Uint8ClampedArray(src)); - return arr -} +// import Bitmap from './Bitmap.js' function createCanvas(width = 0, height = 0) { const c = document.createElement('canvas') @@ -13,227 +7,33 @@ function createCanvas(width = 0, height = 0) { return c } -function dataToBitmap(w, h, data) { - const bitmap = new Bitmap(w, h) - bitmap._data = copyUint8ClampedArray(data) - return bitmap -} - -function canvasToBitmap( - /** @type {HTMLCanvasElement} */ c, - /** @type {CanvasRenderingContext2D} */ ctx -) { - const data = ctx.getImageData(0, 0, c.width, c.height).data - return dataToBitmap(c.width, c.height, data) -} - -function imageToBitmap(img) { - const c = createCanvas(img.width, img.height) - const ctx = c.getContext('2d') - ctx.drawImage(img, 0, 0) - return canvasToBitmap(c, ctx) -} - async function loadImageToBitmap(imagePath) { const img = new Image() await new Promise((resolve) => { img.onload = resolve img.src = imagePath }); - return imageToBitmap(img) + return await createImageBitmap(img, 0, 0, img.width, img.height) } -function resizeBitmap (bitmap, width, height) { - const tmp = new Bitmap(width, height) - mapBitmapToBitmap( - bitmap, - bitmap.getBoundingRect(), - tmp, - tmp.getBoundingRect() - ) - return tmp +async function resizeBitmap (bitmap, width, height) { + const c = createCanvas(width, height) + const ctx = c.getContext('2d') + ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, width, height) + return await createImageBitmap(c) } -function mapBitmapToBitmap( - /** @type {Bitmap} */src, - /** @type {BoundingRectangle} */ rect_src, - /** @type {Bitmap} */ dst, - /** @type {BoundingRectangle} */ rect_dst -) { - const tmp = new Uint8ClampedArray(4) - const w_f = rect_src.width / rect_dst.width - const h_f = rect_src.height / rect_dst.height - - const startX = Math.max(rect_dst.x0, Math.floor((-rect_src.x0 / w_f) + rect_dst.x0)) - const startY = Math.max(rect_dst.y0, Math.floor((-rect_src.y0 / h_f) + rect_dst.y0)) - - const endX = Math.min(rect_dst.x1, Math.ceil(((src.width - rect_src.x0) / w_f) + rect_dst.x0)) - const endY = Math.min(rect_dst.y1, Math.ceil(((src.height - rect_src.y0) / h_f) + rect_dst.y0)) - - for (let x = startX; x < endX; x++) { - for (let y = startY; y < endY; y++) { - const src_x = rect_src.x0 + Math.floor((x - rect_dst.x0) * w_f) - const src_y = rect_src.y0 + Math.floor((y - rect_dst.y0) * h_f) - if (src.getPix(src_x, src_y, tmp)) { - if (tmp[3] === 255) { - dst.putPix(x, y, tmp) - } - } - } - } -} - -function mapBitmapToBitmapCapped( - /** @type {Bitmap} */ src, - /** @type {BoundingRectangle} */ rect_src, - /** @type {Bitmap} */ dst, - /** @type {BoundingRectangle} */ rect_dst, - rects_cap -) { - if (!rects_cap) { - return mapBitmapToBitmap(src, rect_src, dst, rect_dst) - } - const tmp = new Uint8ClampedArray(4) - const w_f = rect_src.width / rect_dst.width - const h_f = rect_src.height / rect_dst.height - - for (let rect_cap of rects_cap) { - const startX = Math.floor(Math.max(rect_cap.x0, rect_dst.x0, (-rect_src.x0 / w_f) + rect_dst.x0)) - const startY = Math.floor(Math.max(rect_cap.y0, rect_dst.y0, (-rect_src.y0 / h_f) + rect_dst.y0)) - - const endX = Math.ceil(Math.min(rect_cap.x1, rect_dst.x1, ((src.width - rect_src.x0) / w_f) + rect_dst.x0)) - const endY = Math.ceil(Math.min(rect_cap.y1, rect_dst.y1, ((src.height - rect_src.y0) / h_f) + rect_dst.y0)) - - for (let x = startX; x < endX; x++) { - for (let y = startY; y < endY; y++) { - const src_x = rect_src.x0 + Math.floor((x - rect_dst.x0) * w_f) - const src_y = rect_src.y0 + Math.floor((y - rect_dst.y0) * h_f) - if (src.getPix(src_x, src_y, tmp)) { - if (tmp[3] === 255) { - dst.putPix(x, y, tmp) - } - } - } - } - } -} - -function fillBitmap (bitmap, rgba) { - const len = bitmap.width * bitmap.height * 4 - bitmap._data = new Uint8ClampedArray(len) - for (let i = 0; i < len; i+=4) { - bitmap._data[i] = rgba[0] - bitmap._data[i + 1] = rgba[1] - bitmap._data[i + 2] = rgba[2] - bitmap._data[i + 3] = rgba[3] - } -} - -function fillBitmapCapped(bitmap, rgba, rects_cap) { - if (!rects_cap) { - return fillBitmap(bitmap, rgba) - } - for (let rect_cap of rects_cap) { - let startX = Math.floor(rect_cap.x0) - let startY = Math.floor(rect_cap.y0) - - let endX = Math.ceil(rect_cap.x1) - let endY = Math.ceil(rect_cap.y1) - - for (let x = startX; x < endX; x++) { - for (let y = startY; y < endY; y++) { - bitmap.putPix(x, y, rgba) - } - } - } -} - -function mapBitmapToAdapterCapped ( - /** @type {Bitmap} */ src, - /** @type {BoundingRectangle} */ rect_src, - /** @type {CanvasAdapter} */ dst, - /** @type {BoundingRectangle} */ rect_dst, - rects_cap -) { - if (!rects_cap) { - return mapBitmapToAdapter(src, rect_src, dst, rect_dst) - } - const tmp = new Uint8ClampedArray(4) - const w_f = rect_src.width / rect_dst.width - const h_f = rect_src.height / rect_dst.height - - for (let rect_cap of rects_cap) { - let startX = Math.floor(Math.max(rect_cap.x0, rect_dst.x0, (-rect_src.x0 / w_f) + rect_dst.x0)) - let startY = Math.floor(Math.max(rect_cap.y0, rect_dst.y0, (-rect_src.y0 / h_f) + rect_dst.y0)) - - let endX = Math.ceil(Math.min(rect_cap.x1, rect_dst.x1, ((src.width - rect_src.x0) / w_f) + rect_dst.x0)) - let endY = Math.ceil(Math.min(rect_cap.y1, rect_dst.y1, ((src.height - rect_src.y0) / h_f) + rect_dst.y0)) - - for (let x = startX; x < endX; x++) { - for (let y = startY; y < endY; y++) { - const src_x = rect_src.x0 + Math.floor((x - rect_dst.x0) * w_f) - const src_y = rect_src.y0 + Math.floor((y - rect_dst.y0) * h_f) - if (src.getPix(src_x, src_y, tmp)) { - if (tmp[3] === 255) { - dst.putPix(x, y, tmp) - } - } - } - } - } -} - -function mapBitmapToAdapter( - /** @type {Bitmap} */ src, - /** @type {BoundingRectangle} */ rect_src, - /** @type {CanvasAdapter} */ dst, - /** @type {BoundingRectangle} */ rect_dst -) { - const tmp = new Uint8ClampedArray(4) - const w_f = rect_src.width / rect_dst.width - const h_f = rect_src.height / rect_dst.height - - let startX = Math.max(rect_dst.x0, Math.floor((-rect_src.x0 / w_f) + rect_dst.x0)) - let startY = Math.max(rect_dst.y0, Math.floor((-rect_src.y0 / h_f) + rect_dst.y0)) - - let endX = Math.min(rect_dst.x1, Math.ceil(((src.width - rect_src.x0) / w_f) + rect_dst.x0)) - let endY = Math.min(rect_dst.y1, Math.ceil(((src.height - rect_src.y0) / h_f) + rect_dst.y0)) - - for (let x = startX; x < endX; x++) { - for (let y = startY; y < endY; y++) { - const src_x = rect_src.x0 + Math.floor((x - rect_dst.x0) * w_f) - const src_y = rect_src.y0 + Math.floor((y - rect_dst.y0) * h_f) - if (src.getPix(src_x, src_y, tmp)) { - if (tmp[3] === 255) { - dst.putPix(x, y, tmp) - } - } - } - } -} - -function drawBitmap(adapter, bitmap, pos) { - const rect = bitmap.getBoundingRect() - mapBitmapToAdapter( - bitmap, - rect, - adapter, - rect.moved(pos.x, pos.y) - ) +async function createBitmap(width, height, color) { + const c = createCanvas(width, height) + const ctx = c.getContext('2d') + ctx.fillStyle = color + ctx.fillRect(0, 0, width, height) + return await createImageBitmap(c) } export default { + createBitmap, createCanvas, - dataToBitmap, - canvasToBitmap, - imageToBitmap, loadImageToBitmap, resizeBitmap, - mapBitmapToBitmap, - mapBitmapToBitmapCapped, - fillBitmap, - fillBitmapCapped, - mapBitmapToAdapter, - mapBitmapToAdapterCapped, - drawBitmap, } diff --git a/game/Point.js b/game/Point.js index fa855b1..68c8526 100644 --- a/game/Point.js +++ b/game/Point.js @@ -19,9 +19,4 @@ export default class Point { this.y - other.y ) } - distance(other) { - const diffX = this.x - other.x - const diffY = this.y - other.y - return Math.sqrt(diffX * diffX + diffY * diffY) - } } diff --git a/game/index.js b/game/index.js index ba8a40c..4e0b0cb 100644 --- a/game/index.js +++ b/game/index.js @@ -1,7 +1,4 @@ "use strict" -import CanvasAdapter from './CanvasAdapter.js' -import BoundingRectangle from './BoundingRectangle.js' -import Bitmap from './Bitmap.js' import {run} from './gameloop.js' import Camera from './Camera.js' import EventAdapter from './EventAdapter.js' @@ -12,18 +9,44 @@ import Communication from './Communication.js' if (typeof GAME_ID === 'undefined') throw '[ GAME_ID not set ]' if (typeof WS_ADDRESS === 'undefined') throw '[ WS_ADDRESS not set ]' -if (typeof DEBUG === 'undefined') window.DEBUG = false +if (typeof DEBUG === 'undefined') window.DEBUG = true function addCanvasToDom(canvas) { document.body.append(canvas) return canvas } +function pointDistance(a, b) { + const diffX = a.x - b.x + const diffY = a.y - b.y + return Math.sqrt(diffX * diffX + diffY * diffY) +} + +function rectMoved(rect, x, y) { + return { + x: rect.x + x, + y: rect.y + y, + w: rect.w, + h: rect.h, + } +} + +const rectCenter = (rect) => { + return { + x: rect.x + (rect.w / 2), + y: rect.y + (rect.h / 2), + } +} + +function rectCenterDistance(a, b) { + return pointDistance(rectCenter(a), rectCenter(b)) +} + function pointInBounds(pt, rect) { - return pt.x >= rect.x0 - && pt.x <= rect.x1 - && pt.y >= rect.y0 - && pt.y <= rect.y1 + return pt.x >= rect.x + && pt.x <= rect.x + rect.w + && pt.y >= rect.y + && pt.y <= rect.y + rect.h } function getSurroundingTilesByIdx(puzzle, idx) { @@ -42,8 +65,7 @@ function getSurroundingTilesByIdx(puzzle, idx) { ] } -async function createPuzzleTileBitmaps(bitmap, tiles, info) { - let img = await bitmap.toImage() +async function createPuzzleTileBitmaps(img, tiles, info) { var tileSize = info.tileSize var tileMarginWidth = info.tileMarginWidth var tileDrawSize = info.tileDrawSize @@ -105,7 +127,6 @@ async function createPuzzleTileBitmaps(bitmap, tiles, info) { const srcRect = srcRectByIdx(info, tile.idx) const path = pathForShape(info.shapes[tile.idx]) - const c = Graphics.createCanvas(tileDrawSize, tileDrawSize) const ctx = c.getContext('2d') // ----------------------------------------------------------- @@ -118,8 +139,8 @@ async function createPuzzleTileBitmaps(bitmap, tiles, info) { ctx.clip(path) ctx.drawImage( img, - srcRect.x0 - tileMarginWidth, - srcRect.y0 - tileMarginWidth, + srcRect.x - tileMarginWidth, + srcRect.y - tileMarginWidth, tileDrawSize, tileDrawSize, 0, @@ -130,9 +151,7 @@ async function createPuzzleTileBitmaps(bitmap, tiles, info) { ctx.stroke(path) ctx.restore(); - const bitmap = Graphics.canvasToBitmap(c, ctx) - - bitmaps[tile.idx] = bitmap + bitmaps[tile.idx] = await createImageBitmap(c) } return bitmaps @@ -142,12 +161,12 @@ function srcRectByIdx(puzzleInfo, idx) { let c = puzzleInfo.coords[idx] let cx = c.x * puzzleInfo.tileSize let cy = c.y * puzzleInfo.tileSize - return new BoundingRectangle( - cx, - cx + puzzleInfo.tileSize, - cy, - cy + puzzleInfo.tileSize - ) + return { + x: cx, + y: cy, + w: puzzleInfo.tileSize, + h: puzzleInfo.tileSize, + } } const pointSub = (a, b) => ({ x: a.x - b.x, y: a.y - b.y }) @@ -165,12 +184,12 @@ const unfinishedTileByPos = (puzzle, pos) => { continue } - const collisionRect = new BoundingRectangle( - tile.pos.x, - tile.pos.x + puzzle.info.tileSize - 1, - tile.pos.y, - tile.pos.y + puzzle.info.tileSize - 1, - ) + const collisionRect = { + x: tile.pos.x, + y: tile.pos.y, + w: puzzle.info.tileSize, + h: puzzle.info.tileSize, + } if (pointInBounds(pos, collisionRect)) { if (maxZ === -1 || tile.z > maxZ) { maxZ = tile.z @@ -215,7 +234,7 @@ async function loadPuzzleBitmaps(puzzle) { // creation of tile bitmaps // then create the final puzzle bitmap // NOTE: this can decrease OR increase in size! - const bmpResized = Graphics.resizeBitmap(bmp, puzzle.info.width, puzzle.info.height) + const bmpResized = await Graphics.resizeBitmap(bmp, puzzle.info.width, puzzle.info.height) return await createPuzzleTileBitmaps(bmpResized, puzzle.tiles, puzzle.info) } @@ -274,7 +293,7 @@ async function main () { // Create a dom and attach adapters to it so we can work with it const canvas = addCanvasToDom(Graphics.createCanvas()) - const adapter = new CanvasAdapter(canvas) + const ctx = canvas.getContext('2d') const evts = new EventAdapter(canvas) // initialize some view data @@ -314,8 +333,8 @@ async function main () { // The actual place for the puzzle. The tiles may // not be moved around infinitely, just on the (invisible) // puzzle table. however, the camera may move away from the table - const puzzleTableColor = [40, 40, 40, 0] - const puzzleTable = new Bitmap( + const puzzleTableColor = '#222' + const puzzleTable = await Graphics.createBitmap( puzzle.info.table.width, puzzle.info.table.height, puzzleTableColor @@ -323,8 +342,8 @@ async function main () { // In the middle of the table, there is a board. this is to // tell the player where to place the final puzzle - const boardColor = [80, 80, 80, 255] - const board = new Bitmap( + const boardColor = '#505050' + const board = await Graphics.createBitmap( puzzle.info.width, puzzle.info.height, boardColor @@ -391,18 +410,19 @@ async function main () { // get the center position of a tile const tileCenterPos = (tile) => { - return tileRectByTile(tile).center() + + return rectCenter(tileRectByTile(tile)) } // get the would-be visible bounding rect if a tile was // in given position const tileRectByPos = (pos) => { - return new BoundingRectangle( - pos.x, - pos.x + puzzle.info.tileSize, - pos.y, - pos.y + puzzle.info.tileSize - ) + return { + x: pos.x, + y: pos.y, + w: puzzle.info.tileSize, + h: puzzle.info.tileSize, + } } // get the current visible bounding rect for a tile @@ -540,11 +560,11 @@ async function main () { let pt = pointSub(tile.pos, boardPos) let dst = tileRectByPos(pt) let srcRect = srcRectByIdx(puzzle.info, grabbingTileIdx) - if (srcRect.centerDistance(dst) < puzzle.info.snapDistance) { + if (rectCenterDistance(srcRect, dst) < puzzle.info.snapDistance) { // Snap the tile to the final destination moveGroupedTiles(tile, { - x: srcRect.x0 + boardPos.x, - y: srcRect.y0 + boardPos.y, + x: srcRect.x + boardPos.x, + y: srcRect.y + boardPos.y, }) finishGroupedTiles(tile) rectTable.add(tp, puzzle.info.tileDrawSize) @@ -554,13 +574,14 @@ async function main () { if (!other || (other.owner === -1) || areGrouped(t, other)) { return false } - let trec_ = tileRectByTile(t) - let otrec = tileRectByTile(other).moved( + const trec_ = tileRectByTile(t) + const otrec = rectMoved( + tileRectByTile(other), off[0] * puzzle.info.tileSize, off[1] * puzzle.info.tileSize ) - if (trec_.centerDistance(otrec) < puzzle.info.snapDistance) { - moveGroupedTiles(t, { x: otrec.x0, y: otrec.y0 }) + if (rectCenterDistance(trec_, otrec) < puzzle.info.snapDistance) { + moveGroupedTiles(t, { x: otrec.x, y: otrec.y }) groupTiles(t, other) setGroupedZIndex(t, t.z) rectTable.add(tileCenterPos(t), puzzle.info.tileDrawSize) @@ -614,7 +635,7 @@ async function main () { // if it improves performance: // 1. background // 2. tiles - // 3. (moving tiles) + // 3. (moving tiles // 4. (players) // (currently, if a player moves, everthing needs to be // rerendered at that position manually, maybe it is faster @@ -624,103 +645,57 @@ async function main () { return } - if (DEBUG) Debug.checkpoint_start(20) + let pos + let dim - // draw the puzzle table - if (rerenderTable) { + if (DEBUG) Debug.checkpoint_start(0) - Graphics.fillBitmapCapped(puzzleTable, puzzleTableColor, rectTable.get()) + ctx.fillStyle = puzzleTableColor + ctx.fillRect(0, 0, canvas.width, canvas.height) + if (DEBUG) Debug.checkpoint('clear done') - if (DEBUG) Debug.checkpoint('after fill') + // DRAW BOARD + // --------------------------------------------------------------- + pos = viewport.worldToViewport(boardPos) + dim = viewport.worldDimToViewport({w: board.width, h: board.height}) + ctx.drawImage(board, + 0, 0, board.width, board.height, + pos.x, pos.y, dim.w, dim.h + ) + if (DEBUG) Debug.checkpoint('board done') - // draw the puzzle board on the table - Graphics.mapBitmapToBitmapCapped( - board, - board.getBoundingRect(), - puzzleTable, - new BoundingRectangle( - boardPos.x, - boardPos.x + board.width - 1, - boardPos.y, - boardPos.y + board.height - 1, - ), - rectTable.get() + // DRAW TILES + // --------------------------------------------------------------- + for (let tile of tilesSortedByZIndex()) { + let bmp = bitmaps[tile.idx] + pos = viewport.worldToViewport({ + x: puzzle.info.tileDrawOffset + tile.pos.x, + y: puzzle.info.tileDrawOffset + tile.pos.y, + }) + dim = viewport.worldDimToViewport({ + w: puzzle.info.tileDrawSize, + h: puzzle.info.tileDrawSize, + }) + ctx.drawImage(bmp, + 0, 0, bmp.width, bmp.height, + pos.x, pos.y, dim.w, dim.h ) - - if (DEBUG) Debug.checkpoint('imgtoimg') - - // draw all the tiles on the table - - for (let tile of tilesSortedByZIndex()) { - let rect = new BoundingRectangle( - puzzle.info.tileDrawOffset + tile.pos.x, - puzzle.info.tileDrawOffset + tile.pos.x + puzzle.info.tileDrawSize, - puzzle.info.tileDrawOffset + tile.pos.y, - puzzle.info.tileDrawOffset + tile.pos.y + puzzle.info.tileDrawSize, - ) - let bmp = bitmaps[tile.idx] - Graphics.mapBitmapToBitmapCapped( - bmp, - bmp.getBoundingRect(), - puzzleTable, - rect, - rectTable.get() - ) - } - - if (DEBUG) Debug.checkpoint('tiles') } + if (DEBUG) Debug.checkpoint('tiles done') - if (rerenderTable || rerender) { - // finally draw the finished table onto the canvas - // only part of the table may be visible, depending on the - // camera - adapter.clear() - adapter.apply() - - if (DEBUG) Debug.checkpoint('afterclear_1') - - // TODO: improve the rendering - // atm it is pretty slow (~40-50ms) - Graphics.mapBitmapToAdapter( - puzzleTable, - viewport.rect(), - adapter, - adapter.getBoundingRect() - ) - - if (DEBUG) Debug.checkpoint('to_adapter_1') - - } else if (rerenderPlayer) { - adapter.clearRect(rectPlayer.get()) - - if (DEBUG) Debug.checkpoint('afterclear_2') - - Graphics.mapBitmapToAdapterCapped( - puzzleTable, - viewport.rect(), - adapter, - adapter.getBoundingRect(), - rectPlayer.get() - ) - - if (DEBUG) Debug.checkpoint('to_adapter_2') + // DRAW PLAYERS + // --------------------------------------------------------------- + for (let id of Object.keys(players)) { + const p = players[id] + const cursor = p.down ? cursorGrab : cursorHand + const pos = viewport.worldToViewport(p) + ctx.drawImage(cursor, pos.x, pos.y) } + // + if (DEBUG) Debug.checkpoint('players done') - if (rerenderPlayer) { - for (let id of Object.keys(players)) { - const p = players[id] - const cursor = p.down ? cursorGrab : cursorHand - const pos = viewport.worldToViewport(p) - Graphics.drawBitmap(adapter, cursor, pos) - } - if (DEBUG) Debug.checkpoint('after_players') - } - - adapter.apply() - - if (DEBUG) Debug.checkpoint('finals') + if (DEBUG) Debug.checkpoint('all done') rerenderTable = false rerenderPlayer = false