p5.js随机生成圆形偶尔超出画布问题求助
p5.js 目标圆形偶尔超出画布边界的问题解决
问题描述
开发时设置随机圆形的x坐标范围为0 + circle radius至width - circle radius,y坐标范围为0 + circle radius至height - circle radius,但偶尔目标圆形(circles[0])会超出画布边界。添加判断语句尝试重选合规坐标后,问题仍未解决。
相关代码
const circlesToMake = 50; let circleLayer, circles, r, g, b; let lives = 3; let round = -1; let dead = false; function setup() { createCanvas(600, 450); noStroke(); textFont('JetBrains Mono'); setupCircles(); fill(0); noLoop(); circleLayer = createGraphics(width, height); } function draw() { image(circleLayer, 0, 0); fill(0); drawCircles(circleLayer); dispInfo(); } function setupCircles() { circles = [] r = random(20, 235) g = random(20, 235) b = random(20, 235) round++; while (circles.length < circlesToMake) { const circle = { x: random(width), y: random(height), r: 20, }; let overlapping = false; for (let j = 0; j < circles.length; j++) { const other = circles[j]; const d = dist(circle.x, circle.y, other.x, other.y); if (d < circle.r + other.r) { overlapping = true; } if (circle.x < 0 + circle.r || circle.x > width - circle.r) { overlapping = true; } if (circle.y < 0 + circle.r || circle.y > height - circle.r) { overlapping = true; } } if (!overlapping) { circles.push(circle); } } } function drawCircles(circleLayer) { clear(); stroke(0); fill(255); rect(0, 0, width-1, height-1); noStroke(); circles.forEach(c => { fill(r, g, b, 200); ellipse(c.x, c.y, c.r * 2, c.r * 2); }); // fill(r, g, b, 220); // normal fill(32, 32, 32, 255); // dev mode const target = circles[0]; ellipse(target.x, target.y, target.r * 2, target.r * 2); } function dispInfo() { fill(0, 0, 0, 100); textAlign(LEFT, TOP); text(`Lives: ${lives}`, 10, 10); text(`Round: ${round + 1}`, 10, 25); } function youDied() { clear(); dead = true; textAlign(CENTER, CENTER); textSize(20); fill (0, 0, 0); text(`You survived ${round} rounds.`, width/2, height/2); fill(r, g, b, 255); ellipse(circles[0].x, circles[0].y, circles[0].r * 2, circles[0].r * 2); } function mousePressed() { if (!dead) { if (dist(mouseX, mouseY, circles[0].x, circles[0].y) < circles[0].r) { setupCircles(); drawCircles(); redraw(); } else { const wrongClick = circles.some(c => dist(mouseX, mouseY, c.x, c.y) < c.r); if (wrongClick) { lives--; redraw(); } if (lives <= 0) { youDied(); } } } }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.js"></script>
问题原因
setupCircles函数中,边界检查逻辑被嵌套在遍历已有圆形的for循环内部。当生成第一个圆形(即目标圆circles[0])时,circles.length为0,循环不会执行,导致第一个圆形直接跳过边界判断。如果此时随机生成的坐标刚好超出画布范围,就会出现目标圆出界的问题。
修复方案
方案1:抽离边界检查逻辑
将边界判断从循环中移出,确保每个生成的圆形(包括第一个)都先经过边界检查,再判断是否与已有圆形重叠:
function setupCircles() { circles = [] r = random(20, 235) g = random(20, 235) b = random(20, 235) round++; while (circles.length < circlesToMake) { const circle = { x: random(width), y: random(height), r: 20, }; let overlapping = false; // 先检查边界是否合规 if (circle.x < circle.r || circle.x > width - circle.r) { overlapping = true; } if (circle.y < circle.r || circle.y > height - circle.r) { overlapping = true; } // 再检查与已有圆形是否重叠 for (let j = 0; j < circles.length; j++) { const other = circles[j]; const d = dist(circle.x, circle.y, other.x, other.y); if (d < circle.r + other.r) { overlapping = true; } } if (!overlapping) { circles.push(circle); } } }
方案2:直接限定随机坐标范围(更高效)
在生成随机坐标时,直接将范围限定在合法区间内,从源头避免出界,再配合边界检查双重保险:
function setupCircles() { circles = [] r = random(20, 235) g = random(20, 235) b = random(20, 235) round++; while (circles.length < circlesToMake) { const circle = { // 直接生成合法范围内的坐标 x: random(circle.r, width - circle.r), y: random(circle.r, height - circle.r), r: 20, }; let overlapping = false; // 可选:保留边界检查作为双重保险 if (circle.x < circle.r || circle.x > width - circle.r) { overlapping = true; } if (circle.y < circle.r || circle.y > height - circle.r) { overlapping = true; } // 检查与已有圆形是否重叠 for (let j = 0; j < circles.length; j++) { const other = circles[j]; const d = dist(circle.x, circle.y, other.x, other.y); if (d < circle.r + other.r) { overlapping = true; } } if (!overlapping) { circles.push(circle); } } }
内容的提问来源于stack exchange,提问作者armput
相关产品推荐
相关产品推荐

