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

enter image description here

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

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

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
      );
    }
  }
}

This is my result: enter image description here

在这里我需要您的指导来理解实施技巧.在这里,我们需要识别图像上的鼠标移动,或者我们需要一些旋转的正方形并具有图像并使用isPointInPath函数. 如果我们继续我提到的第二种方法,绘制正方形,我们需要rotate(-0.25 * Math.PI);

推荐答案

您需要用mousemove跟踪鼠标位置,然后进行简单的基础更改,将屏幕坐标转换为游戏网格坐标:

  • 指针的位置v_C = (x, y)位于规范基础C.

  • 您有一个备用基B(您的2.5D网格),其在基C中的备用基载体是:

    columnVector_C = (cellHalfSizeLong, cellHalfSizeShort)
    rowsVector_C = (-cellHalfSizeLong, cellHalfSizeShort)
    
  • 将它们放在矩阵M_BC上的列中:

    const M_BC = [
      [cellHalfSizeLong, -cellHalfSizeLong],
      [cellHalfSizeShort, cellHalfSizeShort],
    ];
    

    该矩阵可帮助您将B基的载体转换为C

  • 反转该矩阵以得到M_CB.该矩阵可以帮助您将基C转换为B的载体.

  • v_B = M_CB * v_C

  • 最后,计算坐标.这告诉您在2.5D网格中 Select /突出显示哪个单元格.

仍然:

这是一个工作示例:

// 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 = [
  ['#008800', '#00FF00', '#008800', '#00FF00', '#008800', '#00FF00'],
  ['#00FF00', '#008800', '#00FF00', '#008800', '#00FF00', '#008800'],
  ['#008800', '#00FF00', '#000088', '#00FF00', '#008800', '#00FF00'],
  ['#00FF00', '#008800', '#00FF00', '#008800', '#00FF00', '#000088'],
  ['#008800', '#00FF00', '#008800', '#00FF00', '#000088', '#0000FF'],
  ['#00FF00', '#008800', '#00FF00', '#000088', '#0000FF', '#000088'],
];

// This is just for the demo. In a real application, the grid data matrix would
// probably contain all the information on each cell objects (array items):

const gridColorToType = {
  '#008800': 'Grass',
  '#00FF00': 'Grass',
  '#000088': 'Water',
  '#0000FF': 'Water',
};

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;
    
    const cellType = gridColorToType[gridData[currentRow]?.[currentCol]] || 'Void';
    
    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, ' ')
    }) => ${ cellType }`;    
    
    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);
  pointer-events: none;
}
<canvas id="canvas"></canvas>

<div id="positionLabel"> <div>

如果您不关心像素完美的准确性(例如,您不关心一个单元格是否有一棵溢出一点的树,覆盖后面的树,鼠标无法识别位于树顶部),那么您不需要isPointInPath,并且您还获得了很多性能.

Javascript相关问答推荐

假设我有2个对象,根据它们,我想要新对象

CSS背景过滤器忽略转换持续时间(ReactJS)

为什么这个自定义组件会被放置在TR之外?

功能和普通对象之间的原型污染

如何在不使用类型化数组的情况下将32位浮点数按位转换为整值?

使用typeof运算符获取对象值类型-接收字符串而不是数组

如何在JavaScript中在文本内容中添加新行

ReactJS中的material UI自动完成类别

react 路由加载程序行为

当promise 在拒绝处理程序被锁定之前被拒绝时,为什么我们会得到未捕获的错误?

微软Edge Select 间隙鼠标退出问题

Bootstrap动态选项卡在切换选项卡后保持活动状态,导致元素堆叠

为什么我的includes声明需要整个字符串?

InDesign—创建一个独立的窗口,在文档中进行更正时保持打开状态

当点击注册页面上的注册按钮时,邮箱重复

如何在Java脚本中对数据进行签名,并在PHP中验证签名?

将Auth0用户对象存储在nextjs类型脚本的Reaction上下文中

构建器模式与参数对象输入

如何通过Axios在GraphQL查询中发送数组

有没有办法通过使用不同数组中的值进行排序