p5.js中旋转线段与固定小圆的碰撞检测实现咨询
p5.js 旋转机械臂与圆形碰撞检测实现
实现思路
- 首先将所有待检测的小圆统一存储为对象数组,记录每个圆的坐标、半径、触发状态(避免重复触发)
- 计算每个小圆相对于原点的极角、到原点的距离,以及从原点观测该小圆的半张角(
asin(圆半径 / 到原点距离)) - 每帧计算当前机械臂的指向角度,与所有小圆的极角做差值判断,当角度差的绝对值小于半张角,且该圆未被触发过,就执行对应逻辑
- 角度差计算要处理周期特性,取最小的绝对值差值,同时对目标按距离从小到大排序,保证优先触发更近的目标
完整可运行代码
let angle; // 存储所有待检测的小圆参数:x坐标、y坐标、半径、是否已触发过碰撞 const targets = [ {x: 60, y: 0, r: 15, triggered: false}, {x: 160, y: 0, r: 15, triggered: false} ]; const ARM_LENGTH = 200; function setup() { createCanvas(400, 400); angleMode(RADIANS); angle = 0.00; } function draw() { background(220); translate(width / 2, height / 2); noFill(); ellipse(0, 0, 400); // 绘制小圆,已触发的换颜色标记 targets.forEach(t => { fill(t.triggered ? color(0,255,0,40) : color(255, 0, 0, 40)); ellipse(t.x, t.y, t.r*2); }); stroke(0, 200); strokeWeight(3); push(); rotate(angle); line(0, 0, 0, -ARM_LENGTH); pop(); // 碰撞检测 checkCollision(); angle += 0.015; // 旋转满一圈后重置所有触发状态,方便循环测试 if(angle > TWO_PI) { angle = 0; targets.forEach(t => t.triggered = false); } } function checkCollision() { // 计算当前机械臂的指向角度:原线指向负y(-PI/2),顺时针旋转angle后得到实际角度 const armAngle = angle - PI/2; // 按距离原点从小到大排序,保证先检测更近的目标 const sortedTargets = [...targets].sort((a,b) => dist(0,0,a.x,a.y) - dist(0,0,b.x,b.y)); sortedTargets.forEach(t => { if(t.triggered) return; const targetDist = dist(0,0, t.x, t.y); // 目标超出机械臂长度,跳过 if(targetDist > ARM_LENGTH) return; // 计算目标的极角 const targetAngle = atan2(t.y, t.x); // 计算两个角度的最小差值,处理2π周期 let angleDiff = armAngle - targetAngle; angleDiff = atan2(sin(angleDiff), cos(angleDiff)); // 计算目标的半张角:从原点看过去,小圆占据的角度范围的一半 const halfAngle = asin(t.r / targetDist); // 角度差在半张角范围内,判定为碰撞 if(abs(angleDiff) < halfAngle) { t.triggered = true; doSomething(t); } }) } function doSomething(target) { console.log('命中目标:', target); // 这里写你需要执行的逻辑 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
效果说明
机械臂顺时针旋转时会优先命中距离更近的小圆,命中后小圆会从半透明红色变为半透明绿色,控制台会打印命中的目标信息,旋转满一圈后自动重置状态,可循环测试。
内容的提问来源于stack exchange,提问作者Offt_madone
相关产品推荐
相关产品推荐

