You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中检测鼠标指针所在颜色以重置迷宫游戏?

光标迷宫游戏:鼠标触壁检测方案解析

核心问题结论

通过颜色识别检测鼠标是否触碰墙壁的方案不可行。浏览器没有原生API支持直接检测鼠标所在位置的画布像素颜色,onmouseover事件仅能作用于DOM元素,无法识别Canvas绘制的像素内容。

最优替代方案:利用迷宫数据结构检测

你已经通过maze.tiles维护了完整的迷宫墙信息,直接基于鼠标坐标和这些数据进行碰撞检测才是高效且可靠的方案,不需要额外的颜色识别逻辑。具体实现步骤如下:

  • 将鼠标坐标转换为迷宫的网格坐标(每个tile尺寸为res=50)
  • 根据网格坐标定位到对应的tile,判断鼠标是否处于墙壁区域
  • 若检测到触碰墙壁,触发游戏重置逻辑

修改后的完整代码

let maze = null;
let res = 50;
let mazeSizes = [25,50];
let gameActive = true; // 标记游戏是否在运行

function setup() {
  createCanvas(800, 450);
  noStroke();
  makeMaze(width/res + 2, height/res + 2);
  drawMaze();
}

let count = 0;
function draw() {
  if (!gameActive) return; // 游戏重置后暂停绘制
  
  fill("#39A7FF");
  ellipse(775, 425, 20, 20);
  
  // 生成迷宫的逻辑
  if(count % 10 == 0) { // 调整计数步长,避免过度刷新
    if(maze.stack.length != 0) {
      background("#68c7ff");
      mazeIterate();
      drawMaze();
    }
  }
  count++;
  
  // 检测鼠标是否触碰墙壁
  checkMouseCollision();
}

// 鼠标碰撞检测函数
function checkMouseCollision() {
  // 转换鼠标坐标为迷宫网格坐标(考虑translate的偏移)
  let gridX = floor((mouseX + res) / res);
  let gridY = floor((mouseY + res) / res);
  
  // 确保坐标在迷宫范围内
  if(gridX < 0 || gridX >= maze.w || gridY < 0 || gridY >= maze.h) {
    resetGame();
    return;
  }
  
  let tile = maze.tiles[gridX][gridY];
  // 计算鼠标在tile内的相对位置
  let relX = (mouseX + res) % res;
  let relY = (mouseY + res) % res;
  
  // 检测是否触碰当前tile的墙壁(匹配墙壁线宽2px)
  if(tile.up === "wall" && relY < 2) {
    resetGame();
  }
  if(tile.down === "wall" && relY > res - 2) {
    resetGame();
  }
  if(tile.left === "wall" && relX > res - 2) {
    resetGame();
  }
  if(tile.right === "wall" && relX < 2) {
    resetGame();
  }
}

// 游戏重置函数
function resetGame() {
  gameActive = false;
  setTimeout(() => {
    background("#68c7ff");
    makeMaze(width/res + 2, height/res + 2);
    gameActive = true;
    count = 0;
  }, 500); // 短暂延迟后重置
}

function makeMaze(w, h) {
  maze = 
  {
    "stack":[],
    "tiles":[],
    "w":w,
    "h":h
  };
  
  for(let i = 0; i < w; i++) {
    maze.tiles[i] = [];
    for(let j = 0; j < h; j++) {
      maze.tiles[i][j] = 
      {
        "up":"wall",
        "down":"wall",
        "left":"wall",
        "right":"wall",
        "isStart":false,
        "isCurrent":false,
        "x":i,
        "y":j,
        "seen":false
      }
      if(i == 0 || i == w-1 || j == 0 || j == h-1) {
        maze.tiles[i][j].seen = true;
      }
    }
  }
  
  maze.tiles[1][1].isCurrent = true;
  maze.tiles[1][1].isStart = true;
  maze.tiles[1][1].seen = true;
  maze.stack.push(maze.tiles[1][1]);
}

function mazeIterate() {
  let current = maze.stack.pop();
  
  let tileAndWall = pickNeighbor(current);
  if(tileAndWall) {
    maze.stack.push(current);
    tileAndWall.tile[tileAndWall.wall] = "open";
    current[opositeWall(
      tileAndWall.wall)] = "open";
    tileAndWall.tile.seen = true;
    maze.stack.push(tileAndWall.tile);
    
    current.isCurrent = false;
    tileAndWall.tile.isCurrent = true;
  }
  else if(maze.stack.length != 0) {
    current.isCurrent = false;
    maze.stack[
      maze.stack.length-1].isCurrent = true;
  }
}

function pickNeighbor(tile) {
  let unSeen = [];
  
  let upTile = maze.tiles[tile.x][tile.y+1];
  if(!upTile.seen) {
    unSeen.push({
      "tile":upTile,
      "wall":"up"
    });
  }

  let downTile = maze.tiles[tile.x][tile.y-1];
  if(!downTile.seen) {
    unSeen.push({
      "tile":downTile,
      "wall":"down"
    });
  }

  let rightTile = maze.tiles[tile.x+1][tile.y];
  if(!rightTile.seen) {
    unSeen.push({
      "tile":rightTile,
      "wall":"right"
    });
  }

  let leftTile = maze.tiles[tile.x-1][tile.y];
  if(!leftTile.seen) {
    unSeen.push({
      "tile":leftTile,
      "wall":"left"
    });
  }
  
  if(unSeen.length == 0) {
    return null;
  }
  
  return unSeen[Math.floor(
    Math.random()*unSeen.length
  )];
}

function opositeWall(wall) {
  if(wall == "up") {
    return "down"
  }
  else if(wall == "down") {
    return "up"
  }
  else if(wall == "right") {
    return "left"
  }
  else if(wall == "left") {
    return "right"
  }
  
  return -1;
}

function drawMaze() {
  push();
  translate(-res, -res);
  for(let i = 0; i < maze.tiles.length; i++) {
    for(let j = 0; j < maze.tiles[i].length; j++) {
      let tile = maze.tiles[i][j];
      drawTile(tile, i, j);
    }
  }
  pop();
}

function drawTile(tile, i, j) {
  strokeWeight(0);
  
  if(tile.seen == true) {
    fill("#24698e");
    square(i*res, j*res, res);
    
    strokeWeight(2);
    stroke("#c4ecff");
    if(tile.up == "wall") {
      line((i)*res, (j)*res, 
           (i+1)*res, (j)*res);
    }
    if(tile.down == "wall") {
      line((i)*res, (j+1)*res, 
           (i+1)*res, (j+1)*res);
    }
    if(tile.left == "wall") {
      line((i+1)*res, (j)*res, 
           (i+1)*res, (j+1)*res);
    }
    if(tile.right == "wall") {
      line((i)*res, (j)*res, 
           (i)*res, (j+1)*res);
    }
  }
  
  if(tile.isCurrent) {
    fill("#00faff")
    noStroke();
    circle(i*res + res/2, 
             j*res + res/2, res/3);
  }
}

代码说明

  • 添加gameActive变量控制游戏状态,重置时暂停绘制流程
  • checkMouseCollision函数将鼠标坐标转换为网格坐标,通过tile的wall属性精准判断是否触碰墙壁(匹配绘制时的2px线宽)
  • resetGame函数实现游戏重置逻辑,延迟0.5秒后重新生成迷宫,提升用户体验

内容的提问来源于stack exchange,提问作者Sdwhit17

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 00:02:03