Ger*_*ard 5 javascript canvas game-development isometric
我在画布上绘制了一个等距网格。它使用 30 度角偏移,我使用一些脚本来绘制基本网格。对于这个网格,我投影了一个具有 40x40 平铺尺寸的平面网格。
gridRows = 10;
gridCols = 10;
tileSize = 40;
gridWidth = gridCols * tileSize;
gridHeight = gridRows * tileSize;
canvasWidth = tileSize * (gridCols + gridRows) * Math.sqrt(3) / 2;
canvasHeight = tileSize * (gridRows + gridCols) / 2;
canvasOffset = tileSize * gridRows * Math.sqrt(3) / 2;
function carToIso(x, y) {
// Convert cartesian (x, y) to isometric coordinates
return [
Math.round((x - y) * Math.sqrt(3) / 2 + canvasOffset),
Math.round((x + y) / 2)
];
}
function drawGrid() {
let canvas = $("#canvas");
canvas.attr('width', canvasWidth);
canvas.attr('height', canvasHeight);
let ctx = canvas.get(0).getContext('2d');
// Background
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// Draw lines
ctx.beginPath();
ctx.lineWidth = 1;
// Rows
for(let i = 0; i <= gridRows; ++i) {
ctx.moveTo(...carToIso(0, i * tileSize));
ctx.lineTo(...carToIso(gridWidth, i * tileSize));
}
// Columns
for(let i = 0; i <= gridCols; ++i) {
ctx.moveTo(...carToIso(i * tileSize, 0));
ctx.lineTo(...carToIso(i * tileSize, gridHeight));
}
ctx.stroke();
}
drawGrid();
Run Code Online (Sandbox Code Playgroud)
这工作得很好,让我得到了我想要的网格。这里有一个关于这项工作的摆弄;https://jsfiddle.net/fgw10sev/2/
对于下一步,我需要弄清楚某人将鼠标悬停在哪个图块上。我最初有一个 2:1 网格,并且能够将画布内的鼠标坐标转换为原始未投影网格中的网格坐标,如下所示;
function mouseToIso(x, y) {
// Convert mouse (x, y in canvas) to grid coordinates
return [
Math.round((2 * y + x - canvasOffset) / 2),
Math.round((2 * y - x + canvasOffset) / 2)
];
}
Run Code Online (Sandbox Code Playgroud)
然而,随着 sqrt(3) 因子的添加,这不再起作用,而且我无法 - 对于我的一生 - 弄清楚如何解决这个问题。最初的 mouseToIso 函数已经是反复试验的黑客工作,我尝试在不同的地方注入 sqrt(3) 因子,但我就是无法让它工作。
有人可以帮我从这里出去吗?或者告诉我我需要使用完全不同的方法?
笔记; 由于我正在使用的图像,我需要其中的 sqrt(3) 因子。它们都是 30 度角,如果没有这个因素,网格就无法与图像正确对齐。
笔记2; 只是为了完整 - sqrt(3)/2 == cos(deg2rad(30)) 和 2 可以互换使用。
我自己不太精通代数,所以可能有一个更简单的解决方案,但无论如何......
您的函数需要做的是反转上一步中发生的转换,以便找到原始值x和y值。
a = Math.round((x - y) * Math.sqrt(3) / 2 + canvasOffset);
b = Math.round((x + y) / 2);
Run Code Online (Sandbox Code Playgroud)
由此我们可以检索值(x - y)并(x + y)作为
(x - y) = (a - canvasOffset) / Math.sqrt(3) * 2;
(x + y) = b * 2;
Run Code Online (Sandbox Code Playgroud)
现在我们已经有了这两个(x - y)值,(x + y)我们可以发现x,通过将这两个值相加并除以 2,该y值会自行抵消。
现在很容易找到y,因为它只是(x + y) - x。
const pre = document.querySelector("pre");
const log = (txt) => pre.textContent = JSON.stringify(txt);
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const gridRows = 10;
const gridCols = 10;
const tileSize = 40;
const gridWidth = gridCols * tileSize;
const gridHeight = gridRows * tileSize;
const canvasWidth = tileSize * (gridCols + gridRows) * Math.sqrt(3) / 2;
const canvasHeight = tileSize * (gridRows + gridCols) / 2;
const canvasOffset = tileSize * gridRows * Math.sqrt(3) / 2;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
function carToIso(x, y) {
// Convert cartesian (x, y) to isometric coordinates
// I moved the scaling part here, it makes lees noise in the rest of the code
// But feel free to change it back
x *= tileSize;
y *= tileSize;
return [
Math.round((x - y) * Math.sqrt(3) / 2 + canvasOffset),
Math.round((x + y) / 2)
];
}
function isoToCar(a, b) {
// Convert isometric (a, b) to cartesian coordinates
const xMinusY = (a - canvasOffset) / Math.sqrt(3) * 2;
const xPlusY = b * 2;
const x = (xMinusY + xPlusY) / 2;
const y = xPlusY - x;
return [
Math.floor(x / tileSize), // scaling is here too
Math.floor(y / tileSize)
];
}
function drawGrid() {
// Draw lines
ctx.beginPath();
ctx.lineWidth = 1;
ctx.fillStyle = "red";
// Rows
for (let i = 0; i <= gridRows; ++i) {
const [x1, y1] = carToIso(0, i);
const [x2, y2] = carToIso(gridCols, i);
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.fillText("r" + i, (x2 + x1) / 2, (y2 + y1) / 2);
}
// Columns
for (let i = 0; i <= gridCols; ++i) {
const [x1, y1] = carToIso(i, 0);
const [x2, y2] = carToIso(i, gridRows);
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.fillText("c" + i, (x2 + x1) / 2, (y2 + y1) / 2);
}
ctx.stroke();
}
function fillCell(x, y, color) {
ctx.beginPath();
ctx.moveTo(...carToIso(x, y));
ctx.lineTo(...carToIso((x + 1), y));
ctx.lineTo(...carToIso((x + 1), (y + 1)));
ctx.lineTo(...carToIso(x, (y + 1)));
ctx.fillStyle = "green";
ctx.fill();
}
onmousemove = (evt) => {
const {top, left} = canvas.getBoundingClientRect();
const mouseX = evt.clientX - left;
const mouseY = evt.clientY - top;
const [gridX, gridY] = isoToCar(mouseX, mouseY);
log({
mouseX,
mouseY,
gridX,
gridY
});
ctx.clearRect(0, 0, canvas.width, canvas.height);
fillCell(gridX, gridY, "green");
drawGrid();
};
drawGrid();Run Code Online (Sandbox Code Playgroud)
pre { position: absolute }Run Code Online (Sandbox Code Playgroud)
<pre></pre>
<canvas id="canvas"></canvas>Run Code Online (Sandbox Code Playgroud)