Java Arc2D旋转碰撞检测修正:NPC视觉锥位置异常问题
问题:NPC视觉锥碰撞检测失效(显示正常但实际位置固定)
我在做一个带视觉锥的NPC,它会来回旋转,能“看见”进入视觉范围的玩家。现在遇到的问题是:用Arc2D绘制的视觉锥在屏幕上显示正常,但它的实际位置固定不动,导致碰撞检测完全失效。
当前视觉锥更新代码
// Update the shapes used in the npc rect.setRect(x, y, w, h); ellipse.setFrame(rect); visionArc.setArcByCenter(cx, cy, visionDistance, visionAngle, visionAngle * 2, Arc2D.PIE);
其中cx、cy是NPC的中心坐标,visionDistance是视觉锥半径,visionAngle是约45度的常量,用来生成扇形视觉区域。
尝试过的无效调整方式
我试过用NPC当前角度的正弦、余弦值调整视觉锥的位置和角度,但都没成功:
visionArc.setArcByCenter(cx * (Math.cos(Math.toRadians(angle))), cy * (Math.sin(Math.toRadians(angle))), visionDistance, visionAngle, visionAngle * 2, Arc2D.PIE);visionArc.setArcByCenter(cx, cy, visionDistance, visionAngle - angle, (visionAngle + angle) * 2, Arc2D.PIE);visionArc.setArcByCenter(cx, cy, visionDistance, visionAngle * (Math.cos(Math.toRadians(angle))), visionAngle * 2, Arc2D.PIE);
调整角度会让视觉锥伸缩,调整位置会让视觉锥在屏幕上乱飞,都不符合需求。
NPC绘制函数
public void drawNPC(NPC npc, Graphics2D g2, AffineTransform old) { // translate to the position of the npc and rotate AffineTransform npcTransform = AffineTransform.getRotateInstance(Math.toRadians(npc.angle), npc.x, npc.y); // Translate back a few units to keep the npc rotating about its own center // point npcTransform.translate(-npc.halfWidth, -npc.halfHeight); g2.setTransform(npcTransform); // g2.draw(npc.rect); //<-- show bounding box if you want g2.setColor(npc.outlineColor); g2.draw(npc.visionArc); g2.setColor(Color.BLACK); g2.draw(npc.ellipse); g2.setTransform(old); }
碰撞检测代码
(NPC是Ninja的父类,Ninja的视觉范围短、视角广)
public void checkNinjas(Level level) { for (int i = 0; i < level.ninjas.size(); i++) { Ninja ninja = level.ninjas.get(i); playerRect = level.player.rect; // Check collision if (playerRect.getBounds2D().intersects(ninja.visionArc.getBounds2D())) { // Create an area of the object for greater precision Area area = new Area(playerRect); area.intersect(new Area(ninja.visionArc)); // After checking if the area intersects a second time make the NPC "See" the player if (!area.isEmpty()) { ninja.seesPlayer = true; } else { ninja.seesPlayer = false; } } } }
需要修正碰撞检测用的Arc2D实际位置,让它能跟着NPC旋转同步更新。
解决方案
问题核心:绘制视觉锥时用AffineTransform做了旋转平移,但碰撞检测直接用的是未经过变换的visionArc原始形状,导致检测的固定扇形和屏幕显示的旋转扇形不匹配。
步骤1:更新视觉锥时应用旋转变换
每次NPC角度变化后,直接修改visionArc的形状,让它的实际坐标和角度匹配NPC朝向:
// 在NPC的更新方法中,替换原有的visionArc设置代码 AffineTransform transform = AffineTransform.getRotateInstance(Math.toRadians(angle), cx, cy); // 创建以NPC中心为原点、朝向正右的基础扇形 Arc2D baseArc = new Arc2D.Double( cx - visionDistance, cy - visionDistance, visionDistance * 2, visionDistance * 2, -visionAngle, visionAngle * 2, Arc2D.PIE ); // 应用旋转变换,得到和NPC朝向一致的视觉锥 visionArc = (Arc2D) transform.createTransformedShape(baseArc);
步骤2:调整绘制逻辑避免重复变换
因为visionArc已经是旋转后的形状,绘制时不需要再通过npcTransform旋转它:
public void drawNPC(NPC npc, Graphics2D g2, AffineTransform old) { // 仅做平移,将NPC绘制到正确位置 AffineTransform npcTransform = AffineTransform.getTranslateInstance( npc.x - npc.halfWidth, npc.y - npc.halfHeight ); g2.setTransform(npcTransform); // 绘制NPC自身图形 g2.setColor(Color.BLACK); g2.draw(npc.ellipse); // 恢复原始变换,绘制已旋转好的视觉锥 g2.setTransform(old); g2.setColor(npc.outlineColor); g2.draw(npc.visionArc); g2.setTransform(old); }
这样修改后,visionArc的实际形状和屏幕显示完全一致,碰撞检测就能正常工作。
内容的提问来源于stack exchange,提问作者StormyFrolic
相关产品推荐
相关产品推荐

