images = ["", "tileset.png"]; var map = []; var boolMap = []; // 0 1 2 3 // 4 5 6 7 // 8 9 1011 // 12131415 // up right down left var types = [ [0, 0, 0, 0, 15], [0, 0, 0, 1, 14], [0, 0, 1, 0, 3], [0, 0, 1, 1, 2], [0, 1, 0, 0, 12], [0, 1, 0, 1, 13], [0, 1, 1, 0, 0], [0, 1, 1, 1, 1], [1, 0, 0, 0, 11], [1, 0, 0, 1, 10], [1, 0, 1, 0, 7], [1, 0, 1, 1, 6], [1, 1, 0, 0, 8], [1, 1, 0, 1, 9], [1, 1, 1, 0, 4], [1, 1, 1, 1, 5] ]; var brushSize = 1; var collisions = []; for (var y = 0; y < 216; y++) { var arr = []; var arr2 = []; for (var x = 0; x < 72; x++) { arr.push(0); arr2.push(false); } map.push(arr); boolMap.push(arr2); } setup(60); function onAssetsLoaded() { for (var y = 0; y < 4; y++) { for (var x = 0; x < 4; x++) { var newCanv = document.createElement("canvas"); newCanv.width = 10; newCanv.height = 10; var newCtx = newCanv.getContext("2d"); newCtx.drawImage(sprites.tileset.spr, x * 10, y * 10, 10, 10, 0, 0, 10, 10); sprites[x + y * 4] = { spr: newCanv, drawLimitSize: 10 }; } } parseMap(); } function update() {} function input() { if (keyDown[k.w]) { moveCamera(0, -5); } if (keyDown[k.s]) { moveCamera(0, 5); } if (keyDown[k.a]) { moveCamera(-5, 0); } if (keyDown[k.d]) { moveCamera(5, 0); } if (keyPress[k.q]) { if (brushSize > 1) { brushSize--; } } if (keyPress[k.e]) { brushSize++; } camera.zoom += scroll; if (camera.zoom < 1) { camera.zoom = 1; } if (keyPress[k.ENTER]) { renderMap(); } if (keyPress[k.SPACE]) { collisions = makeOptimizedCollision(); } var x = Math.floor(mousePosition().x / 10); var y = Math.floor(mousePosition().y / 10); x = x < 0 ? 0 : x; y = y < 0 ? 0 : y; x = x > map[0].length - 1 ? map[0].length - 1 : x; y = y > map.length - 1 ? map.length - 1 : y; if (mouseDown[0]) { for (var yy = -brushSize / 2; yy < brushSize / 2; yy++) { for (var xx = -brushSize / 2; xx < brushSize / 2; xx++) { var posX = ~~(1 + xx + x); var posY = ~~(1 + yy + y); if (posX > -1 && posY > -1 && posY < map.length && posX < map[0].length) { boolMap[posY][posX] = true; } } } } if (mouseDown[2]) { for (var yy = -brushSize / 2; yy < brushSize / 2; yy++) { for (var xx = -brushSize / 2; xx < brushSize / 2; xx++) { var posX = ~~(1 + xx + x); var posY = ~~(1 + yy + y); if (posX > -1 && posY > -1 && posY < map.length && posX < map[0].length) { boolMap[posY][posX] = false; } } } } } function draw() { parseMap(); var w = map[0].length * 10; var h = map.length * 10; rect(w / 2, h / 2, w, h, "blue"); for (var y = 0; y < map.length; y++) { for (var x = 0; x < map[0].length; x++) { if (map[y][x] !== -1) { img(sprites[map[y][x]], x * 10 + 5, y * 10 + 5); } } } for(var i=0;i -1 && posY > -1 && posY < map.length && posX < map[0].length) { if (boolMap[posY][posX] === false) { var distance = dist({ x: x, y: y }, { x: posX, y: posY }); if (distance < closest) { closest = distance; } } } } } if (closest > 1) { rect(x * 10 + 5, y * 10 + 5, 10, 10, `#000000${Math.round(map_range(closest, 1, 6, 50, 255)).toString(16)}`); } } } } } document.body.appendChild(renderCvs); collisions = makeOptimizedCollision(); var txt = document.createElement("textarea"); txt.innerText = JSON.stringify(collisions); document.body.appendChild(txt); } function map_range(value, low1, high1, low2, high2) { return low2 + ((high2 - low2) * (value - low1)) / (high1 - low1); } function parseMap() { for (var y = 0; y < map.length; y++) { for (var x = 0; x < map[0].length; x++) { if (boolMap[y][x] === false) { map[y][x] = -1; continue; } var t = 0, b = 0, l = 0, r = 0; if (y === 0) { t = 1; } else { t = boolMap[y - 1][x] ? 1 : 0; } if (x === 0) { l = 1; } else { l = boolMap[y][x - 1] ? 1 : 0; } if (y === map.length - 1) { b = 1; } else { b = boolMap[y + 1][x] ? 1 : 0; } if (x === map[0].length - 1) { r = 1; } else { r = boolMap[y][x + 1] ? 1 : 0; } for (var i = 0; i < 16; i++) { if (types[i][0] === t && types[i][1] === r && types[i][2] === b && types[i][3] === l) { map[y][x] = types[i][4]; break; } } } } } function makeOptimizedCollision() { var tileCount = 0; var worldW = map[0].length; var worldH = map.length; cols = []; // 2d array of booleans for if a tile has gotten a collision made for it var hasCollision = []; // fill arrays for (var y = 0; y < worldH; y++) { var hasCollisionRow = []; for (var x = 0; x < worldW; x++) { hasCollisionRow.push(false); } hasCollision.push(hasCollisionRow); } // try to make large rectangles that cover multiple walls to make collision more efficient for (var y = 0; y < worldH; y++) { for (var x = 0; x < worldW; x++) { if (!hasCollision[y][x] && boolMap[y][x]) { // find right limit var xPos = x; while (xPos < worldW && boolMap[y][xPos]) { xPos++; } xPos--; // find bottom limit var yPos = y; var fullRow = true; // go down row by row while (yPos < worldH-1 && boolMap[yPos][xPos] && fullRow) { yPos++; // go through the whole row, make sure it is full var rowX = xPos; while (rowX > -1 && boolMap[yPos][rowX]) { rowX--; } // if the row is not full, stop if (rowX + 1 !== x) { fullRow = false; yPos--; } } // track what tiles have gotten collision for (var y2 = y; y2 < yPos + 1; y2++) { for (var x2 = x; x2 < xPos + 1; x2++) { hasCollision[y2][x2] = true; tileCount++; } } // find collider dimensions var colX = (x + xPos + 1) / 2; var colY = (y + yPos + 1) / 2; var colW = xPos - x + 1; var colH = yPos - y + 1; // add collider cols.push({ x: colX * 10, y: colY * 10, width: colW * 10, height: colH * 10 }); } } } console.log(`tiles: ${tileCount}, boxes: ${cols.length}`) return cols; }