ProcessingでSnowParticleの作成

この記事は[Processing Advent Calendar 2021](https://adventar.org/calendars/6163)の24日目の記事です。

## はじめに

blenderで作成している雪だるまくんに最適な雪を見つけたくて作成しました。

実装したソースコードはいかにあります。
[GitHub](https://github.com/HosodaMath/ArtOFCode/tree/main/Particle/SnowParticle/baseParticle)

## データの管理

データはJavaのCollectionである`ArrayList`を使い管理しています。
`ArrayList`は可変長配列を扱うことが可能なデータ構造で動的に値を追加したり削除が可能なため使おうと思いました。

## SnowParticle

早速SnowParticleを制作します。

SnowParticleは大きく分けて2つのクラスによって実装されています。

### SnowParticle

SnowParticle自体に関わるクラスでParticleの位置や速度、加わっている力、質量、マテリアルなどの要素を定義しています。そのため1つ1つのParticleに速度や大きさなどに異なるパラメーターを割り当てが行えます。

#### コンストラクター

SnowParticleのコンストラクターを見ていきます。

```java
SnowParticle(PVector initPosition, float initMass, float particleMax){
    position = initPosition.copy();
    velocity = new PVector(0.0, 0.0, 0.0);
    acceleration = new PVector(0.0, 0.0, 0.0);
    mass = initMass;
    particleCounter = particleMax;
  }
```

`particleCounter`変数は生成Particleの最大個数を動的に変化させることができます。大きければ大きいほどParticleの生成個数は増えます（その分重くなります）。
位置ベクトルが`copy`で呼び出されているのは名前空間汚染を避けるためです。

#### addForce

力を加えるメソッドで加速度ベクトルを求めます。
力は重力や風力などで加え方によってParticleの動きを大きく変化させます。

```java
void addForce(PVector force){
  PVector calcForce = PVector.div(force, mass);
  acceleration.add(calcForce);
}
```

#### update

値の更新を行います。
`particleCounter`は1ずつ減らしていきParticleの削除を行うかどうかの判定を行うための準備しています。

```java
void update(){
  // 速度ベクトルに加速度ベクトルを加算
  velocity.add(acceleration);
  // 位置ベクトルに速度ベクトルを加算
  position.add(velocity);
  // 加速度ベクトルを0にリセットする。
  acceleration.mult(0.0);
  // Particleの個数をカウントする。
  particleCounter -= 1.0;
}
```

#### render

Particle自体の描画を行うためのメソッドです。
ここでParticleの大きさや色を決定します。

```java
void render(){
  float size = mass;
  // stroke(200, 200, 200);
  fill(240, 240, 250);
  pushMatrix();
  translate(position.x, position.y, position.z);
  ellipse(0, 0, size, size);
  popMatrix();
}
```

#### isCheckEdge

このメソッドはできる限りParticleが画面外に出ないようするためです。
x軸のみ定義されています。できる限り画面表示したいので特定の領域に達すると跳ね返り反対方向に飛んでいきます。

```java
void isCheckEdge(){
  float positionMaxX = 100;
  if(position.x < 0.0){
    position.x = 0.0;
    velocity.x *= -1.0;
  } else if(position.x > width) {
    position.x = width + positionMaxX;
    velocity.x *= -1.0;
  }
}
```

#### isRemove

Particleの削除を行うかどうかの**結果のみ**返します。
削除自体はもう1つのクラスである`SnowParticleSystem`で制御します。

```java
boolean isRemove(){
  if(particleCounter < 0.0){
    return true;
  } else {
    return false;
  }
}
```
### SnowParticleSystem

`SnowParticle`クラス自体を追加や配列からの削除、メソッドの呼び出しなど重要な制御をします。

#### コンストラクター

`SnowParticle`クラスを`ArrayList`で定義しています。
`wind`は風力の定義で今後外部からコントロールできるようコンストラクターで初期化をしています。

```java
ArrayList<SnowParticle> particles;
PVector wind;
boolean flag;
SnowParticleSystem(){
  particles = new ArrayList<SnowParticle>();
  wind = new PVector(0.01, 0.0);
  // 今は気にしなくて良いです。
  flag = false;
}
```

#### addParticleSystem

`ArrayList`に`SnowParticle`クラスを追加します。この際Particleの位置ベクトルや質量などの値も生成しています。

```java
void addParticleSystem(){
  // particleMaxは適切でないので移動する予定です
  float particleMax = 500;
  PVector position = new PVector(random(-width * 0.5, width), -height * 0.1);
  float mass = random(1.0, 5.0);
  particles.add(new SnowParticle(position, mass, particleMax));
  }
```

#### updateParticleSystem

`ArrayList`にある`SnowParticle`クラス自体と定義メソッドの制御をしています。

```java
void updateParticleSystem(){
  for(int count = particles.size() - 1; count >= 0; count--){
    SnowParticle particle = particles.get(count);
    float mass = particle.mass;
    // 重力の定義 Particleの質量をかける。
    PVector gravity = new PVector(0.0, 0.01 * mass);
    // 風力を追加
    particle.addForce(wind);
    // 重力を追加
    particle.addForce(gravity);
    // 値の更新
    particle.update();
    // Particleの描画
    particle.render();
    // Particleが画面外かどうかの判定
    particle.isCheckEdge();

    // 削除するかどうかの判定
    // trueならば削除
    if(particle.isRemove()){
      // ArrayListのremoveメソッド
      particles.remove(count);
    }
  }
}
```

## つまずいたところ

2Dで実装したあと3D実装する予定でしたがカクカクしてしまい、問題を解消中です。

## 今後の予定

- [ ] コンストラクターで制御できるパラメーターを増やす。
- [ ] blenderやGLSLと組み合わせる。
- [ ] 吹雪感を出す。
- [ ] データ構造やアルゴリズムの深い知識
- [ ] 3Dで実装すると同時にフレームレートが落ちてしまう問題を解消する。

## 参考文献

- The Nature of Code: Simulating Natural Systems with Processing
- プログラミングコンテスト攻略のためのアルゴリズムとデータ構造
- 世界で闘うプログラミング力を鍛える本～コーディング面接189問とその解法～