#javascript #алгоритм #canvas
Есть очень большой двумерный массив - игровая карта. Есть маленький двумерный массив - текущая, видимая часть игровой карты. Необходимо реализвать круговое (зацикленное) передвижение видимой части игровой карты. Чтобы при досттижении конца Глобальной карты, начинало отображаться начало Глобальной карты и так по кругу, в любую из сторон Ниже, в собственном ответе, я показываю свою реализацию. Cделал как мог. Но хочется увидеть вариант от профи).
Ответы
Ответ 1
Вам надо переписать зубодробительный код в функции getGlobalMapSector. Если я правильно понял, она выбирает из большого двумерного массива двумерный кусок с заворачиванием через границы большого массива. Все, что для этого нужно, - текущее положение левого-верхнего угла меньшего массива в большем и обращение к элементам большего массива с использованием остатка от деления. Вот одномерный случай: var sizeLarge = 10; var sizeSmall = 4; var start = 0; var large = []; for (var i = 0; i < sizeLarge; i++) { large.push(i + 1); } function getSmall() { if (start < 0) start += sizeLarge; var small = []; for (var j = 0; j < sizeSmall; j++) { small.push(large[(start + j) % sizeLarge]); } return small; } function showSmall() { console.log(JSON.stringify(getSmall())); } showSmall();Ответ 2
Выборка видимой части карты происходит в функции getGlobalMapSector. Все остальное для визуализации const GlobalMap = []; const numSection = 30; //длина GlobalMap const viewNumSection = 11; //длина видимой части карты //центр видимой части карты const centerMap = { x: 10, y: 10, }; //видимая часть карта let currentMap = []; const isoCoords = { x: 0, y: 200, }; const tileWidth = 36; const canvas = document.getElementById("canvas"); const viewX = document.getElementById('rombX') const viewY = document.getElementById('rombY') const ctx = canvas.getContext("2d"); canvas.addEventListener("mousemove", mouseMoveOnMap); const colors = { 0: "green", 1: "blue", 2: "black", 3: "yellow", }; for (let i = 0; i < numSection; i++) { const row = []; GlobalMap.push(row); for (let h = 0; h < numSection; h++) { const obj = { x: i, y: h, type: Math.floor(Math.random() * 4), }; row.push(obj); } } currentMap = getGlobalMapSector(); drawMap(); function getGlobalMapSector() { let rangeArr = []; let length = GlobalMap.length; let rangeSize = viewNumSection; rangeSize = rangeSize % 2 !== 0 ? rangeSize : rangeSize + 1; //костыль let halfSize = Math.floor(rangeSize / 2); let minX = centerMap.x - halfSize; let minY = centerMap.y - halfSize; let startX = minX; let startY = minY; let endX = minX + rangeSize; let endY = minY + rangeSize; //передвижение внутри карты if ( minX >= 0 && minY >= 0 && minX + rangeSize <= length && minY + rangeSize <= length ) { // console.log("передвижение внутри карты") let endX = minX + rangeSize; let endY = minY + rangeSize; rangeArr = getSectorMapList(minX, endX, minY, endY, rangeArr); rangeArr = formResultMap(rangeArr, rangeSize); } //верхний левый угол карты else if (minX < 0 && minY < 0) { let startX = length - Math.abs(minX); let endX = length; let startY = length - Math.abs(minY); let endY = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startY = 0; endY = 0 + (rangeSize - (length - (length - Math.abs(minY)))); rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startX = 0; endX = 0 + (rangeSize - (length - (length - Math.abs(minX)))); rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startY = length - Math.abs(minY); endY = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); sortArr_standart(rangeArr); changeArr(rangeArr, length - Math.abs(minX), "x"); rangeArr = formResultMap(rangeArr, rangeSize); rangeArr = sortArr_Y(rangeArr, length - Math.abs(minY)); } //нижний правый угол карты else if (minX + rangeSize >= length && minY + rangeSize >= length) { let startX = minX; let endX = length; let startY = minY; let endY = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startX = 0; endX = minX + rangeSize - length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startY = 0; endY = minY + rangeSize - length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startX = minX; endX = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); sortArr_standart(rangeArr); changeArr(rangeArr, minX, "x"); rangeArr = formResultMap(rangeArr, rangeSize); rangeArr = sortArr_Y(rangeArr, minY); } //верхний правый угол карты else if (minX < 0 && minY + rangeSize > length) { let startX = length - Math.abs(minX); let endX = length; let startY = minY; let endY = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startX = 0; endX = 0 + (rangeSize - (length - (length - Math.abs(minX)))); rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startY = 0; endY = minY + rangeSize - length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startX = length - Math.abs(minX); endX = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); sortArr_standart(rangeArr); changeArr(rangeArr, length - Math.abs(minX), "x"); rangeArr = formResultMap(rangeArr, rangeSize); rangeArr = sortArr_Y(rangeArr, minY); } //нижний левый угол карты else if (minY < 0 && minX + rangeSize > length) { let startX = minX; let endX = length; let startY = length - Math.abs(minY); let endY = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startY = 0; endY = 0 + (rangeSize - (length - (length - Math.abs(minY)))); rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startX = 0; endX = minX + rangeSize - length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startY = length - Math.abs(minY); endY = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); sortArr_standart(rangeArr); changeArr(rangeArr, length - Math.abs(minX), "x"); rangeArr = formResultMap(rangeArr, rangeSize); rangeArr = sortArr_Y(rangeArr, minX); } //по центру верхней линии карты else if (minX < 0 && minY >= 0 && minY + rangeSize <= length) { let startX = length - Math.abs(minX); let endX = length; let startY = minY; let endY = minY + rangeSize; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startX = 0; endX = 0 + (rangeSize - (length - (length - Math.abs(minX)))); rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); sortArr_standart(rangeArr); changeArr(rangeArr, length - Math.abs(minX), "x"); rangeArr = formResultMap(rangeArr, rangeSize); rangeArr = sortArr_Y(rangeArr, minX); } //по центру нижней линии карты else if ( minY >= 0 && minY + rangeSize < length && minX >= 0 && minX + rangeSize > length ) { let startX = minX; let endX = length; let startY = minY; let endY = minY + rangeSize; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startX = 0; endX = minX + rangeSize - length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); sortArr_standart(rangeArr); changeArr(rangeArr, minX, "x"); rangeArr = formResultMap(rangeArr, rangeSize); } //по центру правой линии else if ( minX >= 0 && minX + rangeSize < length && minY >= 0 && minY + rangeSize > length ) { let startX = minX; let endX = minX + rangeSize; let startY = minY; let endY = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startY = 0; endY = minY + rangeSize - length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); sortArr_standart(rangeArr); rangeArr = formResultMap(rangeArr, rangeSize); rangeArr = sortArr_Y(rangeArr, minY); } //по центру левой линии else if (minY < 0 && minX >= 0 && minX + rangeSize <= length) { startX = minX; endX = minX + rangeSize; startY = length - Math.abs(minY); endY = length; rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); startY = 0; endY = 0 + (rangeSize - (length - (length - Math.abs(minY)))); rangeArr = getSectorMapList(startX, endX, startY, endY, rangeArr); sortArr_standart(rangeArr); rangeArr = formResultMap(rangeArr, rangeSize); rangeArr = sortArr_Y(rangeArr, length - Math.abs(minY)); } let center = rangeArr.length - 1 - halfSize; let centerSection = rangeArr[center][center]; centerMap.x = centerSection.x; centerMap.y = centerSection.y; return rangeArr; //сортирую элементы по Х и по У function sortArr_standart(arr) { arr.sort((a, b) => { let z = a.x - b.x; if (z == 0) { return a.y - b.y; } else { return z; } }); } //сортирую массив по У function sortArr_Y(arr, num) { for (let i = 0; i < arr.length; i++) { let g = arr[i]; changeArr(g, num, "y"); } return arr; } //перекидываю с конца массива в начало необходимые елементы //num - число, начиная с которого нужно переместить елементы function changeArr(arr, num, os) { let g = []; for (let i = 0; i < arr.length; i++) { let sector = arr[i]; if (sector[os] >= num) { g = arr.splice(i, arr.length); break; } } for (let h = g.length - 1; h >= 0; h--) { arr.unshift(g[h]); } } //делаю выборку из исходного двумерного массива function getSectorMapList(startX, endX, startY, endY, arr) { for (let x = startX; x < endX; x++) { for (let y = startY; y < endY; y++) { arr.push(GlobalMap[x][y]); } } return arr; } //формирую двумерный массив из исходного списка function formResultMap(arr, size) { let count = 0; let itogArr = []; for (let i = 0; i < size; i++) { let f = []; itogArr.push(f); for (let h = 0; h < size; h++) { itogArr[i][h] = arr[count]; count++; } } return itogArr; } } // меняет значение centerMap, currentMap function moveOnMap(way) { let step = 2; let nowX = centerMap.x; let nowY = centerMap.y; if (way == "top") { centerMap.x = nowX + step; if (nowX + step > GlobalMap.length - 1) { centerMap.x = nowX + step - GlobalMap.length; } } else if (way === "bottom") { centerMap.x = nowX - step; if (nowX - step < 0) { centerMap.x = GlobalMap.length - Math.abs(nowX - step); } } else if (way === "left") { centerMap.y = nowY - step; if (nowY - step < 0) { centerMap.y = GlobalMap.length - Math.abs(nowY - step); } } else if (way === "right") { centerMap.y = nowY + step; if (nowY + step > GlobalMap.length - 1) { centerMap.y = nowY + step - GlobalMap.length; } } currentMap = getGlobalMapSector(); drawMap(); } function drawMap() { let mapArr = currentMap; ctx.clearRect(0, 0, 400, 400); let tileHeight = tileWidth / 2; let halfHeight = tileHeight / 2; let startX = isoCoords.x; let startY = isoCoords.y; let startCenterX = startX + tileHeight; let startCenterY = startY; for (let i = 0; i < mapArr.length; i++) { for (let h = 0; h < mapArr[i].length; h++) { let centerX = startCenterX + 2 * halfHeight * (i + h); let centerY = startCenterY - halfHeight * (i - h); currentMap[i][h].centerX = centerX; currentMap[i][h].centerY = centerY; drawRectAroundCenter(centerX, centerY, mapArr[i][h].type); } } function drawRectAroundCenter(centerX, centerY, grid) { const step = 0; ctx.beginPath(); ctx.fillStyle = colors[grid]; ctx.strokeStyle = "black"; ctx.moveTo(centerX, centerY - halfHeight + step); ctx.lineTo(centerX + step - tileHeight, centerY); ctx.lineTo(centerX, centerY + halfHeight - step); ctx.lineTo(centerX + tileHeight - step, centerY); ctx.lineTo(centerX, centerY - halfHeight + step); ctx.stroke(); ctx.fill(); ctx.closePath(); } } const mouseCoords = { x: 0, y: 0, }; function getCursorPositionOnScene(event) { const clientX = event.clientX; const clientY = event.clientY; const position = canvas.getBoundingClientRect(); const mouseX = Math.floor(clientX - position.left); const mouseY = Math.floor(clientY - position.top); mouseCoords.x = mouseX; mouseCoords.y = mouseY; return; } function getTileCoordsOnMap() { const halfHeight = tileWidth / 2 / 2; const isoX = isoCoords.x; const isoY = isoCoords.y; const stepX = mouseCoords.x - isoX; const stepY = mouseCoords.y - isoY; const topX = 0.5 * stepX - stepY + isoX; const topY = 0.5 * stepY - stepX / 4 + isoY; const downX = 0.5 * stepX + stepY + isoX; const downY = 0.25 * stepX + 0.5 * stepY + isoY; let q = Math.pow(topX - isoX, 2) + Math.pow(topY - isoY, 2); const l = halfHeight * Math.sqrt(5); const lineTop = Math.sqrt(q); const rombX = Math.floor(lineTop / l); q = Math.pow(downX - isoX, 2) + Math.pow(downY - isoY, 2); const lineDown = Math.sqrt(q); const rombY = Math.floor(lineDown / l); return (coords = { x: rombX, y: rombY, }); } function mouseMoveOnMap(event) { getCursorPositionOnScene(event); if (!checkMouseCoordsOnMap()) return; const rombCoords = getTileCoordsOnMap(); const tile = currentMap[rombCoords.x][rombCoords.y] viewX.innerText = "X:" + tile.x; viewY.innerText = "Y:" + tile.y; } const borderIsoMap = { left: { x: 0, y: 0 }, top: { x: 0, y: 0 }, right: { x: 0, y: 0 }, bottom: { x: 0, y: 0 }, }; setBorderIsoMap(); function setBorderIsoMap() { const currentLength = currentMap.length; const height = tileWidth / 2; borderIsoMap.left.x = isoCoords.x; borderIsoMap.left.y = isoCoords.y; borderIsoMap.top.x = borderIsoMap.left.x + (tileWidth * currentLength) / 2; borderIsoMap.top.y = borderIsoMap.left.y - (height * currentLength) / 2; borderIsoMap.right.x = borderIsoMap.left.x + tileWidth * currentLength; borderIsoMap.right.y = borderIsoMap.left.y; borderIsoMap.bottom.x = borderIsoMap.top.x; borderIsoMap.bottom.y = borderIsoMap.left.y + (height * currentLength) / 2; } function checkMouseCoordsOnMap() { const coords = borderIsoMap; const left = coords.left; const top = coords.top; const right = coords.right; const bottom = coords.bottom; ctx.beginPath(); ctx.strokeStyle = "transparent"; ctx.moveTo(left.x, left.y); ctx.lineTo(top.x, top.y); ctx.lineTo(right.x, right.y); ctx.lineTo(bottom.x, bottom.y); ctx.stroke(); ctx.closePath(); return ctx.isPointInPath(mouseCoords.x, mouseCoords.y); } #scene { width: 400px; height: 400px; border: 1px solid; position: relative; } button { position: absolute; } .bottom { bottom: 70px; left: 80px; } .left { top: 80px; left: 90px; } .top { right: 80px; top: 80px; } .right { bottom: 70px; right: 60px; } #rombX { position: absolute; top: 10px; left: 10px; } #rombY { position: absolute; top: 30px; left: 10px; }X: -1Y: -1
Комментариев нет:
Отправить комментарий