鼠标移动时更新画布

问题描述 投票:0回答:2

基本思想来自于游戏地图。根据我的代码审查,该地图是整页画布。我在画布上绘制图像没有问题。我的问题是如何检测地图房屋并更新画布,甚至为其添加点击功能。 我附上了原始游戏中的 GIF 和 HTML 代码,以便更好地理解我的请求。

enter image description here

<div id="canvasBorder"><canvas id="canvasMap"></canvas></div>

好的,这是我的代码。这很简单。我根据画布上很大的主图像绘制了地图上的房屋。

function onClick2() {
  const imagePath = '/lobby/map.png';

  //Image Positions and Width/Height
  const array = [
    { x: 1764, y: 1104, w: 126, h: 84 },
    { x: 0, y: 1188, w: 126, h: 84 },
    { x: 126, y: 1188, w: 126, h: 84 },
    { x: 2090, y: 340, w: 126, h: 68 },
    { x: 126, y: 1188, w: 126, h: 84 },
  ];

  if (canvasRef?.current) {
    let x = canvasRef?.current.getContext('2d');

    let img = new Image();
    img.src = path;

    //Draw Map Blocks
    //Here I deleted the extra codes, I just wanted to show that it was done this way.
    if (x) {
      x.drawImage(
        img,
        array[3].x,
        array[3].y,
        array[3].w,
        array[3].h,
        0,
        0,
        array[3].w,
        array[3].h
      );
    }
  }
}

这是我的结果: enter image description here

在这里我需要您的指导来理解实现技巧。在这里,我们需要识别图像上的鼠标移动,或者我们需要一些旋转的正方形并具有图像并与 isPointInPath 函数一起使用。 如果我们继续我提到的第二种方法,要绘制正方形,我们需要

rotate(-0.25 * Math.PI);

javascript html canvas html5-canvas
2个回答
0
投票

我建议查看 JavaScript 事件

HTML 画布没有任何花哨的输入处理程序,它只是用于绘图。但我们可以相对轻松地监听 mousemove 和 click 事件来与画布交互。

const canvasMap = document.getElementById("canvasMap");

// First method
canvasMap.onmousemove = function(event) {
    console.log(event);
}

// Second method
canvasMap.addEventListener("mousemove", function(event) {
    console.log(event);
    // If collision with tile, draw white border around it.
});

// For click events
canvasMap.addEventListener("click", function(event) {
    console.log(event);
});

然后您可以获取

clientX
clientY
属性并使用它们来计算鼠标与画布上的哪个图块相交。

如果画布不是位于左上角,我们可以获取边界客户端矩形,并从鼠标坐标中减去画布的

clientLeft
clientTop
属性,以获得鼠标相对于画布的位置。

如果我们有相对于画布的坐标,它应该像碰撞检测一样简单,然后在画布中执行视觉变化。

对于碰撞检测,您可以参考 this stackoverflow post 并做一些研究。


0
投票

您只需要做一个简单的基础更改:

  • 光标的

    v_C = (x, y)
    位于规范基础上,
    C

  • 您有替代基础

    B
    (您的2.5D网格/投影)。

  • 替代基向量是

    columnVector_C = (cellHalfSizeLong, cellHalfSizeShort)
    rowsVector_C = (-cellHalfSizeLong, cellHalfSizeShort)

  • 您将它们放在矩阵的列中

    M_BC
    。该矩阵可帮助您将向量从基础
    B
    转换为规范基础。

  • 将该矩阵求逆并得到

    M_CB
    。该矩阵可帮助您将向量从规范基础转换为基础
    B

  • v_B = M_CB * v_C
    。然后将坐标设置为底,这会告诉您在 2.5D 网格中选择/突出显示哪个网格。

仍然:

这是一个工作示例:

// Some basic utils to work with matrices and vectors:

function matrixVectorMultiply(matrix, vector) {
  let result = [];

  for (let i = 0; i < matrix.length; i++) {
    let sum = 0;

    for (let j = 0; j < vector.length; j++) {
      sum += matrix[i][j] * vector[j];
    }

    result.push(sum);
  }

  return result;
}

function invertMatrix(matrix) {
  const n = matrix.length;

  let identity = [];

  for (let i = 0; i < n; i++) {
    identity.push([]);

    for (let j = 0; j < n; j++) {
      identity[i].push(i === j ? 1 : 0);
    }
  }

  // Apply Gauss-Jordan elimination:

  for (let i = 0; i < n; i++) {
    let pivot = matrix[i][i];

    for (let j = 0; j < n; j++) {
      matrix[i][j] /= pivot;
      identity[i][j] /= pivot;
    }

    for (let k = 0; k < n; k++) {
      if (k !== i) {
        let factor = matrix[k][i];

        for (let j = 0; j < n; j++) {
          matrix[k][j] -= factor * matrix[i][j];
          identity[k][j] -= factor * identity[i][j];
        }
      }
    }
  }

  return identity;
}

// Define the grid data (colors of each cell):

const gridData = [
  ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF'],
  ['#FFFF00', '#00FFFF', '#FF00FF', '#FF0000', '#00FF00', '#0000FF'],
  ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF'],
  ['#FFFF00', '#00FFFF', '#FF00FF', '#FF0000', '#00FF00', '#0000FF'],
  ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF'],
  ['#FFFF00', '#00FFFF', '#FF00FF', '#FF0000', '#00FF00', '#0000FF'],
];

const selectedCellBolor = '#000000';

// Get the UI elements:

const positionLabelElement = document.getElementById('positionLabel');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

positionLabelElement.textContent = ' ';

// Adjust the canvas to the window:

const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;

// Grid sizing params:

const cellSizeLong = 100;
const cellHalfSizeLong = cellSizeLong / 2;
const cellSizeShort = cellSizeLong / 3;
const cellHalfSizeShort = cellSizeShort / 2;

// Keep track of the selected/highlighted cell:

let currentRow = 0;
let currentCol = 0;

// Drawing functions:

function drawCell(ctx, color, row, col) {
  ctx.fillStyle = color;

  // Calculate the position of the cell
  const x = (col - row) * cellHalfSizeLong + width / 2;
  const y = (col + row) * cellHalfSizeShort;

  // Fill:
  
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.lineTo(x + cellHalfSizeLong, y + cellHalfSizeShort);
  ctx.lineTo(x, y + cellSizeShort);
  ctx.lineTo(x - cellHalfSizeLong, y + cellHalfSizeShort);
  ctx.closePath();
  ctx.fill();

  // Border:
  ctx.strokeStyle = '#000000';
  ctx.stroke();
}

function drawBoard() {
  ctx.clearRect(0, 0, width, height);
      
  const numRows = gridData.length;
  const numCols = gridData[0].length;

  // Draw all the cells in their respective color:
  
  for (let row = 0; row < numRows; ++row) {
    for (let col = 0; col < numCols; ++col) {      
      drawCell(ctx, gridData[row][col], row, col);
    }
  }
  
  // And re-draw the selected one on top (you might want to do this differently):
  drawCell(ctx, selectedCellBolor, currentRow, currentCol);
}

canvas.addEventListener('mousemove', () => {
    const x_C = width / 2 - event.clientX;
    const y_C = event.clientY;
    
    // First column is the columns vector in the 2.5D grid.
    // Second column is the rows vector in the 2.5 grid.
    const M_BC = [
      [cellHalfSizeLong, -cellHalfSizeLong],
      [cellHalfSizeShort, cellHalfSizeShort],
    ];
    
    // We need the inverse of that matrix to translate canonical basis
    // coordinates to coordinates in the 2.5D space's base:
    const M_CB = invertMatrix(M_BC);
    
    const [x_B, y_B] = matrixVectorMultiply(M_CB, [x_C, y_C]);
    const int_x_B = Math.floor(x_B);
    const int_y_B = Math.floor(y_B);
    
    currentRow = int_x_B;
    currentCol = int_y_B;
    
    positionLabelElement.textContent = `(${
      (x_C | 0).toFixed().padStart(4, ' ')
    }, ${
      (y_C | 0).toFixed().padStart(4, ' ')
    }) => (${
      x_B.toFixed(2).padStart(5, ' ')
    }, ${
      y_B.toFixed(2).padStart(5, ' ')
    }) => (${
      int_x_B.toFixed().padStart(2, ' ')
    }, ${
      int_y_B.toFixed().padStart(2, ' ')
    })`;    
    
    requestAnimationFrame(() => {
      drawBoard();
    });
});

drawBoard();
body {
  background: #777;
}

#canvas {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}

#positionLabel {
  position: fixed;
  bottom: 0;
  left: 0;
  background: rgba(255, 255, 255, .5); 
  padding: 8px;
  border-radius: 0 4px 0 0;
  font-family: monospace;
  font-weight: bold;
  white-space: pre;
  backdrop-filter: blur(8px);
}
<canvas id="canvas"></canvas>

<div id="positionLabel"> <div>

© www.soinside.com 2019 - 2024. All rights reserved.