move puzzle generation to server

This commit is contained in:
Zutatensuppe 2020-11-08 14:13:43 +01:00
parent e74a6fd62f
commit 3917c591b0
7 changed files with 207 additions and 213 deletions

View file

@ -17,24 +17,12 @@ export default class Camera {
}
rect() {
// when no zoom is relevant:
return new BoundingRectangle(
this.x,
this.x + this.width - 1,
this.y,
this.y + this.height - 1
)
// when zoom is relevant:
// TODO: check if still true
const w_final = this.width * this.zoom
const h_final = this.height * this.zoom
return new BoundingRectangle(
this.x + (this.width - w_final) / 2,
this.x + (this.width + w_final) / 2,
this.y + (this.height - h_final) / 2,
this.y + (this.height + h_final) / 2
)
return new BoundingRectangle(
- this.x,
- this.x + (this.width / this.zoom),
- this.y,
- this.y + (this.height / this.zoom),
)
}
move(x, y) {

View file

@ -5,23 +5,10 @@ import Bitmap from './Bitmap.js'
import {run} from './gameloop.js'
import Camera from './Camera.js'
import EventAdapter from './EventAdapter.js'
import { choice } from './util.js'
import WsClient from './WsClient.js'
if (!WS_ADDRESS) throw '[ WS_ADDRESS not set ]'
const TILE_SIZE = 64 // cut size of each puzzle tile in the
// final resized version of the puzzle image
const TARGET_TILES = 1000 // desired number of tiles
// actual calculated number can be higher
const IMAGES = [
'./example-images/ima_86ec3fa.jpeg',
'./example-images/bleu.png',
'./example-images/saechsische_schweiz.jpg',
'./example-images/132-2048x1365.jpg',
]
const IMAGE_URL = IMAGES[0]
function createCanvas(width = 0, height = 0) {
const canvas = document.createElement('canvas')
canvas.width = width === 0 ? window.innerWidth : width
@ -235,55 +222,6 @@ function pointInBounds(pt, rect) {
&& pt.y <= rect.y1
}
const determinePuzzleInfo = (w, h, targetTiles) => {
let tileSize = 0
let tiles = 0
do {
tileSize++
tiles = tilesFit(w, h, tileSize)
} while (tiles >= targetTiles)
tileSize--
tiles = tilesFit(w, h, tileSize)
const tiles_x = Math.round(w / tileSize)
const tiles_y = Math.round(h / tileSize)
tiles = tiles_x * tiles_y
// then resize to final TILE_SIZE (which is always the same)
tileSize = TILE_SIZE
const width = tiles_x * tileSize
const height = tiles_y * tileSize
const coords = coordsByNum({ width, height, tileSize, tiles })
const tileMarginWidth = tileSize * .5;
const tileDrawSize = Math.round(tileSize + tileMarginWidth * 2)
return {
width,
height,
tileSize,
tileMarginWidth,
tileDrawSize,
tiles,
tiles_x,
tiles_y,
coords,
}
}
const tilesFit = (w, h, size) => Math.floor(w / size) * Math.floor(h / size)
const coordsByNum = (puzzleInfo) => {
const w_tiles = puzzleInfo.width / puzzleInfo.tileSize
const coords = new Array(puzzleInfo.tiles)
for (let i = 0; i < puzzleInfo.tiles; i++) {
const y = Math.floor(i / w_tiles)
const x = i % w_tiles
coords[i] = { x, y }
}
return coords
}
const resizeBitmap = (bitmap, width, height) => {
const tmp = new Bitmap(width, height)
mapBitmapToBitmap(
@ -311,21 +249,6 @@ function getSurroundingTilesByIdx(puzzle, idx) {
]
}
function determinePuzzleTileShapes(info) {
const tabs = [-1, 1]
const shapes = new Array(info.tiles)
for (let i = 0; i < info.tiles; i++) {
shapes[i] = {
top: info.coords[i].y === 0 ? 0 : shapes[i - info.tiles_x].bottom * -1,
right: info.coords[i].x === info.tiles_x - 1 ? 0 : choice(tabs),
left: info.coords[i].x === 0 ? 0 : shapes[i - 1].right * -1,
bottom: info.coords[i].y === info.tiles_y - 1 ? 0 : choice(tabs),
}
}
return shapes
}
async function createPuzzleTileBitmaps(bitmap, tiles, info) {
let img = await bitmap.toImage()
var tileSize = info.tileSize
@ -475,82 +398,6 @@ async function loadPuzzleBitmaps(puzzle) {
return await createPuzzleTileBitmaps(bmpResized, puzzle.tiles, puzzle.info)
}
async function createPuzzle(targetTiles, imageUrl) {
// load bitmap, to determine the original size of the image
let bmp = await loadImageToBitmap(imageUrl)
// determine puzzle information from the bitmap
let info = determinePuzzleInfo(bmp.width, bmp.height, targetTiles)
let tiles = new Array(info.tiles)
for (let i = 0; i < tiles.length; i++) {
tiles[i] = {
idx: i,
}
}
const shapes = determinePuzzleTileShapes(info)
// Complete puzzle object
const p = {
// tiles array
tiles: tiles.map(tile => {
return {
idx: tile.idx, // index of tile in the array
group: 0, // if grouped with other tiles
z: 0, // z index of the tile
owner: 0, // who owns the tile
// 0 = free for taking
// -1 = finished
// other values: id of player who has the tile
// physical current position of the tile (x/y in pixels)
// this position is the initial position only and is the
// value that changes when moving a tile
// TODO: scatter the tiles on the table at the beginning
pos: {
x: info.coords[tile.idx].x * info.tileSize,
y: info.coords[tile.idx].y * info.tileSize,
},
}
}),
// game data for puzzle, data changes during the game
data: {
// TODO: maybe calculate this each time?
maxZ: 0, // max z of all pieces
maxGroup: 0, // max group of all pieces
},
// static puzzle information. stays same for complete duration of
// the game
info: {
// information that was used to create the puzzle
targetTiles: targetTiles,
imageUrl: imageUrl,
width: info.width, // actual puzzle width (same as bitmap.width)
height: info.height, // actual puzzle height (same as bitmap.height)
tileSize: info.tileSize, // width/height of each tile (without tabs)
tileDrawSize: info.tileDrawSize, // width/height of each tile (with tabs)
tileMarginWidth: info.tileMarginWidth,
// offset in x and y when drawing tiles, so that they appear to be at pos
tileDrawOffset: (info.tileDrawSize - info.tileSize) / -2,
// max distance between tile and destination that
// makes the tile snap to destination
snapDistance: info.tileSize / 2,
tiles: info.tiles, // the final number of tiles in the puzzle
tiles_x: info.tiles_x, // number of tiles each row
tiles_y: info.tiles_y, // number of tiles each col
coords: info.coords, // map of tile index to its coordinates
// ( index => {x, y} )
// this is not the physical coordinate, but
// the tile_coordinate
// this can be used to determine where the
// final destination of a tile is
shapes: shapes, // tile shapes
},
}
return p
}
function uniqId() {
return Date.now().toString(36) + Math.random().toString(36).substring(2)
}
@ -584,27 +431,10 @@ async function main () {
conn.send(JSON.stringify({ type: 'init' }))
conn.onSocket('message', async ({data}) => {
const d = JSON.parse(data)
let game
if (d.type === 'init') {
game = d.game
if (game.puzzle) {
console.log('loaded from server')
} else {
// The game doesnt exist yet on the server, so load puzzle
// and then give the server some info about the puzzle
// Load puzzle and determine information about it
// TODO: move puzzle creation to server
game.puzzle = await createPuzzle(TARGET_TILES, IMAGE_URL)
conn.send(JSON.stringify({
type: 'init_puzzle',
puzzle: game.puzzle,
}))
console.log('loaded from local config')
}
console.log('the game ', game)
let bitmaps = await loadPuzzleBitmaps(game.puzzle)
startGame(game, bitmaps, conn)
console.log('the game ', d.game)
let bitmaps = await loadPuzzleBitmaps(d.game.puzzle)
startGame(d.game, bitmaps, conn)
} else {
// console.log(d)
}
@ -1153,22 +983,23 @@ async function main () {
// TODO: improve the rendering
// atm it is pretty slow (~40-50ms)
mapBitmapToAdapter(puzzleTable, new BoundingRectangle(
- cam.x,
- cam.x + (cam.width / cam.zoom),
- cam.y,
- cam.y + (cam.height / cam.zoom),
), adapter, adapter.getBoundingRect())
mapBitmapToAdapter(
puzzleTable,
cam.rect(),
adapter,
adapter.getBoundingRect()
)
checkpoint('to_adapter_1')
} else if (rerenderPlayer) {
adapter.clearRect(rectPlayer.get())
checkpoint('afterclear_2')
mapBitmapToAdapterCapped(puzzleTable, new BoundingRectangle(
- cam.x,
- cam.x + (cam.width / cam.zoom),
- cam.y,
- cam.y + (cam.height / cam.zoom),
), adapter, adapter.getBoundingRect(), rectPlayer.get())
mapBitmapToAdapterCapped(
puzzleTable,
cam.rect(),
adapter,
adapter.getBoundingRect(),
rectPlayer.get()
)
checkpoint('to_adapter_2')
}

View file

@ -1,25 +0,0 @@
// get a random int between min and max (inclusive)
export const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min
// get one random item from the given array
export const choice = (array) => array[randomInt(0, array.length - 1)]
// return a shuffled (shallow) copy of the given array
export const shuffle = (array) => {
let arr = array.slice()
for (let i = 0; i <= arr.length - 2; i++)
{
const j = randomInt(i, arr.length -1);
const tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
return arr
}
export default {
randomInt,
choice,
shuffle,
}