Частицы, движущиеся вокруг поля шума Перлина


Я сделал этот эскиз в обработке (в основном Java), который состоит из множества частиц, движущихся вокруг поля шума Перлина. Каждая частица осознает положение одной другой частицы, и это создает веревку, как эффект. Эскиз предназначен для эстетики, как заставку, и я в это может быть трудно судить о работоспособности кода.

Тем не менее, я надеялся, что есть что-то, что я делаю неправильно стилистически, что может быть указано.

    int emergenceInterval = int(random(75, 100));
    float a, freq = 0.05;
    float alphDelta, alphAccel, alphSpringing = 0.0009, alphDamping = 0.98, alphX, maxAlph;
    int pAmt = int(random(2000, 4000));
    Particle p[] = new Particle[pAmt]; 

    void setup() {
      background(0);
      size(1000, 500); 
      for (int i = 0; i < pAmt; i++) {
        p[i] = new Particle(random(width), random(height), i);
      }
    }

    void draw() {
      if(frameCount % emergenceInterval == 0) {
       if(maxAlph == .05) maxAlph = 1;
       else maxAlph = .05; 
      }
      a += freq;
      fill(50, findAlpha() * 255);
      rect(0, 0, width, height);
      runParticles();
    }

    void runParticles() {
      for (Particle _p : p) {
        Particle lastP = _p;
        if (_p.index != 0) lastP = p[_p.index - 1];
        _p.update(450, lastP.pos, abs(pow(sin(radians(a)), 3)));
        point(_p.pos.x, _p.pos.y);
        _p.vel.x = 1;
      }
    }

    float findAlpha() {
      if (!(alphAccel < 0)) alphDelta = width - alphX;
      else alphDelta = 0 - alphX;
      alphDelta *= alphSpringing;
      alphAccel += alphDelta;
      alphAccel *= alphDamping;
      alphX += alphAccel;
      float alph = (alphX * (maxAlph * abs(pow(sin(radians(a)), 2))))/width;

      if(alphX > width) alphAccel *= -1;
      else if(alphX < 0) alphAccel *= -1;
      return alph;
    }


  class Particle {

  int index;
  float theta;
  float stride;
  float maxSpeed = 5;
  float maxChaos = 10;
  PVector accel, vel, pos;


  Particle(float startX, float startY, int index) {
    this.index = index;
    accel = new PVector(0, 0);
    vel = new PVector(0, 0);
    pos = new PVector(startX, startY);
  } 

  void update(float stride, PVector target, float chaos) {
    this.stride = stride;
    stroke(50*(noise(pos.x)),0,50*(noise(pos.x)), noise(pos.x, pos.y) * 255);
    accel = noiseDir(chaos);
    accel.add(followDir(target));
    if (pos.x > width) pos.x = 0;
    if (pos.y > height) pos.y = 0;
    if (pos.y < 0) pos.y = height;
    vel.add(accel);
    float speed = noise(pos.x, pos.y) * maxSpeed;
    vel.limit(speed);
    pos.add(vel);
  }

  PVector noiseDir(float chaos) {
    theta = abs(noise(pos.x, pos.y)) * 180;
    float x = pos.x + stride * cos(theta);
    float y = pos.y + stride * sin(theta);
    PVector dir = new PVector(x - pos.x, y - pos.y);
    dir.normalize();
    dir.mult(chaos * maxChaos);
    return dir;
  }

  PVector followDir(PVector target) {
    PVector dir = new PVector(target.x - pos.x, target.y - pos.y);
    dir.normalize();
    dir.mult(5);
    return dir;
  }
}


501
6
задан 21 августа 2011 в 05:08 Источник Поделиться
Комментарии
2 ответа

(1). С точки зрения стиля я рекомендую вам не смешивать уровень детали в функции. Например.

Вместо того, чтобы писать что-то вроде этого:

void setup() {
background(0);
size(1000, 500);
for (int i = 0; i < pAmt; i++) { // this is bad
p[i] = new Particle(random(width), random(height), i);
}
}

Вы должны написать что-то вроде этого. То же касается и других функций.

void setup() {
background(0);
size(1000, 500);
fillArray(); // there goes the loop and it's load easier to read.
}

(2). Что касается именования, я бы рекомендовал вам использовать глагол как часть имени функции. Как этот код выглядит необычно.

background(0);
size(1000, 500);

(3). Вы должны соответствовать имена для ваших переменных. Например, в ваши обновить() функция, вы можете увидеть полные и короткие имена, такие как Страйд, цель, хаос против разгона, Вэл, поз. Это действительно заставляет меня думать о нем гораздо больше имен, чем я должен.

(4).Если у вас есть, чтобы назвать это "нормализовать()" метод, много после строительства объекта, я бы рекомендовал подумать о добавлении этого метода consturctor например с флагом под названием "shouldNormalize".

PVector dir = new PVector(x - pos.x, y - pos.y);
dir.normalize();

против

PVector dir = new PVector(x - pos.x, y - pos.y, true); 
//or make it to normalize the vector by default and pass false when you don't need it
//but I guess that you should normalize it quite often after creation

(5). Я бы настоятельно рекомендовал сделать класс частиц неизменным. Это спасет вас от многих писак, как это и делают ваш код чище:

 void update(float stride, PVector target, float chaos) {
this.stride = stride;
... }

3
ответ дан 22 августа 2011 в 08:08 Источник Поделиться

Некоторые мелкие замечания:

//maybe it works here, but generally you should use Math.abs(a-b) < epsilon 
//with a very small epsilon instead a == b for double comparision
if(maxAlph == .05) maxAlph = 1;
else maxAlph = .05;
-->
maxAlph = (maxAlph == .05) ? 1 : 0.05;

if(alphX > width) alphAccel *= -1;
else if(alphX < 0) alphAccel *= -1;
-->
if(alphX > width || alphX < 0) alphAccel *= -1;

if (!(alphAccel < 0)) alphDelta = width - alphX;
else alphDelta = 0 - alphX;
-->
alphDelta = (alphAccel >= 0) ? width - alphX : -alphX;

И почему тета переменной-члена?

1
ответ дан 21 августа 2011 в 10:08 Источник Поделиться