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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 02:15:36