メディアアート~ランダムパーティクル~

# メディアアート用の言語・ライブラリ
メディアアートは展示会やテーマパークなどで触れていると思います。
実はメディアアートは<b>Processing</b>と言われる言語や<b>Pygame</b>と言われるライブラリで作ることができます。
本記事はメディアアート作品1作品目としてProcessingで描いたアートを載せます。

## Processingとは？
Processingはメディアアートやゲーム開発で活用されている言語です。
主にJavaをベースとしていて、その他同じ構文の言語としてArduinoがあります。
例えばProcessingでの開発例は、カメラを活用したインタラクティブなゲームやARマーカーを使ったエンタメコンテンツを作ることができます。
私自身も大学の講義で「カメラを使ったブロック崩し」や「HSVをベースとしたお絵描き」などを作りました。

## 作品名: ランダムパーティクル
早速、１作品目を上げていきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226429/b1d6ebb2-1b8c-4fc3-9d63-6e784c365ad4.png" width="60%"><br>

この作品は、画面をクリックするとパーティクルが出てきます。


## プログラム
まず、色とパーティクルを管理するリストを設定します。
```
int MaxColor;

float Hue = 0; // 色相
float Saturation = 500; // 彩度
float Value = 1000; // 明度

ArrayList<Particle> particles = new ArrayList<Particle>();  // パーティクルを管理するリスト

```

次、初期設定を行います。
backgroundを白にするため、MaxColor-1と設定し、スクリーンサイズは大きくします。

```
void setup() {
  size(1600, 1200);
  MaxColor = 800;
  colorMode(HSB, MaxColor, 255, 255); // HSB + 透明度対応
  background(MaxColor-1);
}
```

パーティクルを定義するため、Particleクラスを作ります。
アルゴリズムは以下の通りです。
<ol>
<li>初期のポジション(マウスクリックした場所)を設定し、ランダムでパーティクルを移動するようにsin,cosを活用
<li>パーティクル移動時、重力を活用する
<li>時間がたつにつれて透明度が増すようにする
<li>ウィンドウ外にたどり着いたかつ透明度がmaxになったらパーティクルを削除する

</ol>


```
// 粒子クラス
class Particle {
  float x, y;
  float speedX, speedY; // 速度
  float gravity = 0.1;  // 重力
  int startTime;
  float alpha = 255;  // 透明度（初期値 255）
  float particle_hue;

  Particle(float startX, float startY, int time, float hue) {
    x = startX;
    y = startY;
    startTime = time;
    
    // ランダムな角度と速度を設定（上方向に発射）
    float angle = random(-PI / 2 - PI / 6, -PI / 2 + PI / 6); // -90度±30度
    float speed = random(2, 5); // 速度をランダム化
    
    speedX = cos(angle) * speed;
    speedY = sin(angle) * speed;
    particle_hue = hue;
  }
  
  void update() {
    // 速度に基づいて移動
    x += speedX;
    y += speedY;
    
    // 重力を適用
    speedY += gravity;

    // 透明度を時間とともに減少（3秒で完全に消えるように調整）
    alpha = 255 - (millis() - startTime) / 18.0;
    if (alpha < 0) alpha = 0; // 負の値を防ぐ
  }
  
  void display() {
    noStroke();
    fill(particle_hue, Saturation, Value, alpha); // アルファ値を適用
    ellipse(x, y, 10, 10);
  }
  
  boolean isOutOfScreen() {
    return y > height || alpha <= 0; // 画面下に到達 or 透明度ゼロで削除
  }
}
```

最後、描画時の処理とマウス処理を行います。
マウスがクリックされたら、クリックした位置で30個同時にランダムな色で表示させます。
また、draw()と言われる継続的に行う関数でfor文を使ってパーティクルのアニメーションを行います。
```
void draw() {
  background(MaxColor-1); // 背景を描画してリフレッシュ
  
  // 全ての粒子を更新・描画
  for (int i = particles.size() - 1; i >= 0; i--) {
    Particle p = particles.get(i);
    p.update();
    p.display();
    
    // 透明度が0になったら削除
    if (p.isOutOfScreen()) {
      particles.remove(i);
    }
  }
}

void mousePressed() {
  Hue = random(0, 1000);     
  for (int i = 0; i < 30; i++) { // 一度のクリックで複数の粒子を生成
    particles.add(new Particle(mouseX, mouseY, millis(),Hue));
  }
}
```

コード全体は以下の通りです。
```
int MaxColor;

float Hue = 0; // 色相
float Saturation = 500; // 彩度
float Value = 1000; // 明度

ArrayList<Particle> particles = new ArrayList<Particle>();  // 粒子を管理するリスト

void setup() {
  size(1600, 1200);
  MaxColor = 800;
  colorMode(HSB, MaxColor, 255, 255); // HSB + 透明度対応
  background(MaxColor-1);
}

void draw() {
  background(MaxColor-1); // 背景を描画してリフレッシュ
  
  // 全ての粒子を更新・描画
  for (int i = particles.size() - 1; i >= 0; i--) {
    Particle p = particles.get(i);
    p.update();
    p.display();
    
    // 透明度が0になったら削除
    if (p.isOutOfScreen()) {
      particles.remove(i);
    }
  }
}

void mousePressed() {
  Hue = random(0, 1000);     
  for (int i = 0; i < 30; i++) { // 一度のクリックで複数の粒子を生成
    particles.add(new Particle(mouseX, mouseY, millis(),Hue));
  }
}

// 粒子クラス
class Particle {
  float x, y;
  float speedX, speedY; // 速度
  float gravity = 0.1;  // 重力
  int startTime;
  float alpha = 255;  // 透明度（初期値 255）
  float particle_hue;

  Particle(float startX, float startY, int time, float hue) {
    x = startX;
    y = startY;
    startTime = time;
    
    // ランダムな角度と速度を設定（上方向に発射）
    float angle = random(-PI / 2 - PI / 6, -PI / 2 + PI / 6); // -90度±30度
    float speed = random(2, 5); // 速度をランダム化
    
    speedX = cos(angle) * speed;
    speedY = sin(angle) * speed;
    particle_hue = hue;
  }
  
  void update() {
    // 速度に基づいて移動
    x += speedX;
    y += speedY;
    
    // 重力を適用
    speedY += gravity;

    // 透明度を時間とともに減少（3秒で完全に消えるように調整）
    alpha = 255 - (millis() - startTime) / 18.0;
    if (alpha < 0) alpha = 0; // 負の値を防ぐ
  }
  
  void display() {
    noStroke();
    fill(particle_hue, Saturation, Value, alpha); // アルファ値を適用
    ellipse(x, y, 10, 10);
  }
  
  boolean isOutOfScreen() {
    return y > height || alpha <= 0; // 画面下に到達 or 透明度ゼロで削除
  }
}
```

マウスでクリックするとparticleや図形表示することができ、インタラクティブアート作成ができます！

## まとめ
Processingでは図形の配置やマウス処理など安易に使うことができ、メディアアートに向いています。
今後、Pygameはもちろん、カメラ系のアートも上げていこうと考えています。