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

Processing中brightness(PImage.get())返回值异常的碰撞检测问题

问题分析与修复方案

核心问题

你遇到的亮度值始终为255的原因是原始碰撞图的尺寸与渲染到画布上的尺寸不匹配,导致你用屏幕坐标/错误计算的坐标去读取原始图像素时,对应的位置根本不是你视觉上看到的碰撞区域:

  • pallettowncollisionmap是加载的原始图片,它的width和height是图片本身的原始尺寸;
  • 但你通过image(pallettowncollisionmap, offsetX, offsetY, 2000, 1800)将其缩放到了2000x1800渲染到画布上,屏幕上的坐标和原始图的坐标完全不是1:1对应;
  • 你直接用mouseX/mouseY或错误计算的mapX/mapY去读原始图的像素,相当于拿缩放后的位置去查原图,自然读不到正确的碰撞区域像素;而get(mapX,mapY)是读取画布上已经渲染好的像素,所以能得到正确值,但这不是可靠的碰撞检测方式(画布可能被其他元素覆盖)。

另外,canMoveTo方法里的坐标计算逻辑混乱,进一步导致mapX/mapY对应到原始图的错误位置。


修复步骤

1. 统一坐标映射逻辑

需要将屏幕/角色位置按缩放比例转换为原始碰撞图的坐标,才能正确读取碰撞图的像素:
首先在setup中计算缩放比例并提前加载像素:

float collisionScaleX;
float collisionScaleY;

void setup() {
  size(1000, 1000);
  frameRate(999);

  // ... 其他图片加载代码
  pallettowncollisionmap = loadImage("pallettowncollisionmap.png");
  // 计算缩放比例:渲染尺寸 / 原始图尺寸
  collisionScaleX = 2000.0f / pallettowncollisionmap.width;
  collisionScaleY = 1800.0f / pallettowncollisionmap.height;
  // 提前加载像素,优化读取速度
  pallettowncollisionmap.loadPixels();
}

2. 修复鼠标点击的碰撞检测

修改mousePressed方法,将鼠标坐标转换为原始碰撞图的坐标:

void mousePressed() {
  // 将鼠标坐标转换为原始碰撞图的坐标
  int originalX = int((mouseX - offsetX) / collisionScaleX);
  int originalY = int((mouseY - offsetY) / collisionScaleY);
  
  // 边界检查
  if (originalX >=0 && originalX < pallettowncollisionmap.width && originalY >=0 && originalY < pallettowncollisionmap.height) {
    color pixel = pallettowncollisionmap.get(originalX, originalY);
    println("鼠标原始坐标:", originalX, originalY, "亮度:", brightness(pixel));
  } else {
    println("鼠标位置超出碰撞图范围");
  }
}

3. 修复canMoveTo的坐标计算

原来的mapX/mapY计算逻辑错误,需要基于角色在屏幕上的位置,转换为原始碰撞图的坐标:

boolean canMoveTo(float targetOffsetX, float targetOffsetY) {
  // 角色在屏幕上的中心位置(你设置的角色绘制位置是600,600,加上 sprite 半尺寸)
  float screenCharX = 600 + squareSize/2;
  float screenCharY = 600 + squareSize/2;
  
  // 根据目标偏移量,计算角色在碰撞图上的原始坐标
  int mapX = int((screenCharX - targetOffsetX) / collisionScaleX);
  int mapY = int((screenCharY - targetOffsetY) / collisionScaleY);

  // 边界检查
  if (mapX < 0 || mapX >= pallettowncollisionmap.width || mapY < 0 || mapY >= pallettowncollisionmap.height) {
    println("Out of bounds: mapX = " + mapX + ", mapY = " + mapY);
    return false;
  }

  color pixel = pallettowncollisionmap.pixels[mapY * pallettowncollisionmap.width + mapX];
  println("mapX: " + mapX + ", mapY: " + mapY + ", Brightness: " + brightness(pixel));
  
  fill(255,0,0);
  // 注意:这里绘制的矩形要对应屏幕位置,所以需要转换回屏幕坐标
  rect(offsetX + mapX * collisionScaleX, offsetY + mapY * collisionScaleY, 20, 20);

  return brightness(pixel) > 100;
}

4. 修正keyPressed中的参数传递

keyPressed里调用canMoveTo时,传递的参数应该是目标偏移量,原来的变量命名容易混淆,建议修改:

void keyPressed() {
  if (!isMoving) {
    float newTargetOffsetX = targetOffsetX;
    float newTargetOffsetY = targetOffsetY;

    if (key == 'w' || key == 'W') {
      newTargetOffsetY += 50;
      direction = "up";
    } else if (key == 's' || key == 'S') {
      newTargetOffsetY -= 50;
      direction = "down";
    } else if (key == 'a' || key == 'A') {
      newTargetOffsetX += 50;
      direction = "left";
    } else if (key == 'd' || key == 'D') {
      newTargetOffsetX -= 50;
      direction = "right";
    }

    // 传入目标偏移量,检查是否可以移动
    if (canMoveTo(newTargetOffsetX, newTargetOffsetY)) {
      targetOffsetX = newTargetOffsetX;
      targetOffsetY = newTargetOffsetY;
      isMoving = true;
    }
  }
}

关键说明

  • 碰撞检测必须基于原始碰撞图的像素,而不是画布上的渲染像素,这样才能避免其他元素的干扰,且逻辑更可靠;
  • 所有涉及碰撞图的坐标计算,都要通过缩放比例进行转换,确保原始图和渲染图的位置对应;
  • 提前调用loadPixels()可以大幅提升像素读取的性能,避免重复加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:50:55