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
相关产品推荐
相关产品推荐

