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

p5.js中旋转平移图形的碰撞检测及坐标变换问题咨询

Duet游戏复刻:平移旋转后的碰撞检测解决方案

一、平移/旋转对图形坐标的具体影响

p5.js的translate()和rotate()是修改绘图上下文的坐标系,而非直接改变图形的原始坐标值:

  • translate(width/2, height/2)会把绘图原点从屏幕左上角(0,0)移到屏幕中心,之后你绘制的所有图形,代码里写的坐标都是相对于这个新原点的。
  • rotate(angle)会让整个坐标系绕当前原点(也就是屏幕中心)旋转指定角度,此时图形在代码里的相对坐标会跟着坐标系旋转,但它们在**屏幕绝对坐标系(左上角为原点)**中的实际位置需要通过数学计算推导。

以你代码中的红蓝球为例,假设它们相对于中心的初始偏移是(0, -d)和(0, d)(d是球心到中心的距离),旋转角度为angle,那么每个球的屏幕绝对坐标计算公式为:

const centerX = width / 2;
const centerY = height / 2;
const d = 60; // 假设你的球到中心的距离是60

// 蓝球绝对坐标
blueAbsX = centerX + (0 * cos(angle) - (-d) * sin(angle));
blueAbsY = centerY + (0 * sin(angle) + (-d) * cos(angle));

// 红球绝对坐标
redAbsX = centerX + (0 * cos(angle) - d * sin(angle));
redAbsY = centerY + (0 * sin(angle) + d * cos(angle));

本质是用旋转矩阵将相对坐标转换为绝对坐标,通用公式为:

绝对X = 中心X + (相对X * cos(angle) - 相对Y * sin(angle))
绝对Y = 中心Y + (相对X * sin(angle) + 相对Y * cos(angle))

二、球体与障碍物的碰撞检测实现

核心思路是:先算出红蓝球的屏幕绝对坐标,再用这个坐标和障碍物(白色矩形)做碰撞判断。

1. 矩形与圆形的碰撞检测逻辑

如果你的障碍物是矩形(比如垂直长条),可以用以下步骤检测:

  • 对于每个障碍物矩形,找到矩形边界上离球心最近的点(closestX, closestY):
    // rect是障碍物对象,包含x, y, width, height
    const closestX = constrain(ballAbsX, rect.x, rect.x + rect.width);
    const closestY = constrain(ballAbsY, rect.y, rect.y + rect.height);
    
  • 计算球心到这个最近点的距离,若距离小于等于球的半径,则判定为碰撞:
    const distance = dist(ballAbsX, ballAbsY, closestX, closestY);
    if (distance <= ballRadius) {
      // 触发碰撞逻辑,比如游戏结束
      gameOver = true;
    }
    

2. 整合到你的代码中

  • 首先在draw()函数里,每次旋转后,先计算两个球的绝对坐标,不要直接用绘图时的相对坐标。
  • 遍历所有障碍物,对每个球执行上述碰撞检测逻辑。

简化的代码示例:

let angle = 0;
const ballRadius = 20;
const d = 60;
const obstacles = [
  {x: 100, y: 0, width: 20, height: height} // 示例障碍物
];
let gameOver = false;

function draw() {
  background(0);
  translate(width/2, height/2);
  rotate(angle);
  
  // 计算红蓝球绝对坐标
  const centerX = width/2;
  const centerY = height/2;
  const blueX = centerX + (0 * cos(angle) - (-d) * sin(angle));
  const blueY = centerY + (0 * sin(angle) + (-d) * cos(angle));
  const redX = centerX + (0 * cos(angle) - d * sin(angle));
  const redY = centerY + (0 * sin(angle) + d * cos(angle));
  
  // 绘制球
  fill(0,0,255);
  ellipse(0, -d, ballRadius*2, ballRadius*2);
  fill(255,0,0);
  ellipse(0, d, ballRadius*2, ballRadius*2);
  
  // 绘制障碍物(需转成相对坐标系)
  fill(255);
  for (let rect of obstacles) {
    rect(rect.x - centerX, rect.y - centerY, rect.width, rect.height);
  }
  
  // 碰撞检测
  if (!gameOver) {
    for (let rect of obstacles) {
      // 检测蓝球
      let closestX = constrain(blueX, rect.x, rect.x + rect.width);
      let closestY = constrain(blueY, rect.y, rect.y + rect.height);
      if (dist(blueX, blueY, closestX, closestY) <= ballRadius) {
        gameOver = true;
      }
      // 检测红球
      closestX = constrain(redX, rect.x, rect.x + rect.width);
      closestY = constrain(redY, rect.y, rect.y + rect.height);
      if (dist(redX, redY, closestX, closestY) <= ballRadius) {
        gameOver = true;
      }
    }
  }
  
  angle += 0.01;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 11:40:39