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

Processing(本质为Java)粒子系统碰撞检测实现技术问询

嘿,我完全懂你刚接触Processing粒子系统时的迷茫——尤其是碰撞检测这块,不用急,咱们一步步来搞定这个「撞墙就反弹」的简单效果!

一、先搞定最基础的窗口边界碰撞(撞窗口边缘)

你之前尝试检测粒子坐标“刚好相同”没成功,核心问题在于:粒子是连续移动的,几乎不可能精准卡在边界坐标上。正确的思路是检测粒子是否超出边界范围,一旦超出就反转对应方向的速度。

先写一个极简的粒子类,包含碰撞逻辑:

class Particle {
  float x, y;
  float velX, velY;
  float size;

  Particle(float startX, float startY) {
    x = startX;
    y = startY;
    velX = random(-2, 2); // 随机X方向速度
    velY = random(-2, 2); // 随机Y方向速度
    size = 10; // 粒子大小
  }

  void update() {
    // 更新粒子位置
    x += velX;
    y += velY;

    // 检测左右边界:碰到就反转X方向速度
    if (x - size/2 < 0 || x + size/2 > width) {
      velX *= -1;
      // 小修正:防止粒子卡在边界里
      x = constrain(x, size/2, width - size/2);
    }

    // 检测上下边界:碰到就反转Y方向速度
    if (y - size/2 < 0 || y + size/2 > height) {
      velY *= -1;
      y = constrain(y, size/2, height - size/2);
    }
  }

  void display() {
    ellipse(x, y, size, size);
  }
}

再配合主程序调用:

ArrayList<Particle> particles = new ArrayList<Particle>();

void setup() {
  size(600, 400);
  // 创建10个随机位置的粒子
  for (int i = 0; i < 10; i++) {
    particles.add(new Particle(random(width), random(height)));
  }
}

void draw() {
  background(255);
  // 更新并渲染所有粒子
  for (Particle p : particles) {
    p.update();
    p.display();
  }
}
二、基于像素数组的自定义障碍碰撞检测

如果你说的「数组映射像素」是指碰撞到自定义的障碍区域(比如图像里的墙、手动绘制的障碍物),可以用Processing的pixels[]数组来实现——这个数组存储了图像每个像素的颜色值,我们可以通过检测粒子位置对应的像素是否为障碍,来触发反弹。

举个例子,比如我们用一个黑色矩形作为障碍:

ArrayList<Particle> particles = new ArrayList<Particle>();
PImage obstacle;

void setup() {
  size(600, 400);
  // 创建一个自定义障碍图像
  obstacle = createImage(width, height, RGB);
  obstacle.loadPixels();
  // 在图像中间画一个黑色矩形障碍
  for (int i = 0; i < obstacle.pixels.length; i++) {
    int x = i % width;
    int y = i / width;
    if (x > 200 && x < 400 && y > 100 && y < 300) {
      obstacle.pixels[i] = color(0); // 黑色障碍
    } else {
      obstacle.pixels[i] = color(255); // 白色背景
    }
  }
  obstacle.updatePixels();

  // 创建粒子
  for (int i = 0; i < 10; i++) {
    particles.add(new Particle(random(width), random(height)));
  }
}

void draw() {
  background(255);
  image(obstacle, 0, 0); // 显示障碍

  obstacle.loadPixels(); // 加载像素数组(如果障碍动态变化需要这一步)
  for (Particle p : particles) {
    p.checkObstacleCollision();
    p.update();
    p.display();
  }
}

class Particle {
  float x, y;
  float velX, velY;
  float size;

  Particle(float startX, float startY) {
    x = startX;
    y = startY;
    velX = random(-2, 2);
    velY = random(-2, 2);
    size = 10;
  }

  void update() {
    x += velX;
    y += velY;
    // 先保证粒子在窗口范围内
    x = constrain(x, size/2, width - size/2);
    y = constrain(y, size/2, height - size/2);
  }

  void checkObstacleCollision() {
    // 计算粒子中心对应的像素索引
    int pixelIndex = int(y) * width + int(x);
    // 确保索引在数组范围内(防止越界报错)
    if (pixelIndex >= 0 && pixelIndex < obstacle.pixels.length) {
      color pix = obstacle.pixels[pixelIndex];
      // 通过亮度判断是否是障碍(黑色亮度为0,白色为255)
      if (brightness(pix) < 50) {
        velX *= -1; // 反转X方向速度
        velY *= -1; // 反转Y方向速度
        // 修正位置,避免粒子卡在障碍里
        x -= velX * 2;
        y -= velY * 2;
      }
    }
  }

  void display() {
    fill(255, 0, 0);
    ellipse(x, y, size, size);
  }
}

核心逻辑说明:

  • pixels[]是一维数组,像素索引的计算公式是y * width + x
  • 用亮度判断障碍而非精确颜色值,能避免颜色细微差异导致的检测失败
  • 碰撞后修正位置是关键,不然粒子可能会卡在障碍里反复触发碰撞

刚上手粒子系统碰到这种问题太正常了,先从简单的边界碰撞练手,再过渡到自定义障碍,慢慢就能掌握啦!

内容的提问来源于stack exchange,提问作者Jake Winters

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:58:39