2019プログラミング講座16:クラスとパーティクル

パーティクル(particle)とは運動する粒子で表現される事象のことで、コンピューターグラフィックスでは、光、炎、水などの現象を表現するのに用いられています。今回はprocessingを用いたパーティクルの表現を学びます。またオブジェクト指向プログラミングのための、クラス構文(以下、クラス)についても学んでいきましょう。

クラスの定義
クラスとは型のようなもので、そこで定義された内容をもとに複数の実体=インスタンスを作成することができます。クラスは以下のように記述します。クラス名は慣例的に大文字で始めます。

class Mediaproduce {
  //初期化用メソッド(コンストラクタ) 
  Mediaproduce ( ) {
    
  }

  //更新用メソッド
 void update() {

 }

  //表示用メソッド
  void display() {

 }
 
}

クラスを用いた描画
次に、クラスを実際に使って描画を実行するスケッチを作成してみましょう。

//クラスのインスタンスを宣言
Mediaproduce c1, c2, c3, c4, c5;
 
void setup() {
  size(600, 600);
 
  //インスタンスを作成
  c1 = new Mediaproduce(100,100, 10, 1.0);
  c2 = new Mediaproduce(150,150, 20, 1.5);
  c3 = new Mediaproduce(200,200, 30, 2.0);
  c4 = new Mediaproduce(250,250, 40, 2.5);
  c5 = new Mediaproduce(300,300, 50, 3.0);
}
 
void draw() {
  background(0);
 
  noStroke();
  fill(255,0,0);
  c1.update(); 
  c1.display();
 
  fill(0,255,0);
  c2.update(); 
  c2.display();
  
  fill(0,0,255);
  c3.update(); 
  c3.display();
  
  fill(255,255,0);
  c4.update(); 
  c4.display();
  
  fill(0,255,255);
  c5.update(); 
  c5.display();
}
 
//クラスの宣言
class Mediaproduce {
  float x, y, speed;
  int d;
 
  //初期化用メソッド(コンストラクタ) 
  Mediaproduce (float _x, float _y, int _d, float _speed) {
    x = _x;
    y = _y;
    d = _d;
    speed = _speed;
  }
 
  //円の位置を更新するメソッド
  void update() {
    x += speed;
    if (x > width) {
      x = 0;
    }
    
    y += speed;
    if (y > height) {
      y = 0;
    }
  }
 
  void display() {
    ellipse(x, y, d, d);
  }
}

パーティクルを表示するコード
ひとつの型から複数の実体を生成するというクラスの特徴を活用して、パーティクルを生成するオブジェクト指向プログラムを作成してみましょう。

ArrayList<ParticleSystem> systems;

void setup() {
  size(800, 800);
  systems = new ArrayList<ParticleSystem>();
}

void draw() {
  background(0);
  for (ParticleSystem ps: systems) {
    ps.run();
    ps.addParticle();
  }
}

void mousePressed() {
  systems.add(new ParticleSystem(1, new PVector(mouseX, mouseY)));
}

class CrazyParticle extends Particle {
  float theta;
  CrazyParticle(PVector l) {
    super(l);
    theta = 0.0;
  }

  void update() {
    super.update();
    float theta_vel = (velocity.x * velocity.mag()) / 10.0f;
    theta += theta_vel;
  }

}

class Particle {
  PVector location;
  PVector velocity;
  PVector acceleration;
  float lifespan;

  Particle(PVector l) {
    acceleration = new PVector(0.00,-0.05); //パーティクル生成の方向
    velocity = new PVector(random(-1,1),random(-2,0));
    location = l.get();
    lifespan = 300.0; //パーティクル生成の上限
  }

  void run() {
    update();
    display();
  }

  void update() {
    velocity.add(acceleration);
    location.add(velocity);
    lifespan -= 2.0;
  }

  void display() {
    stroke(255,0,0,lifespan); //パーティクルの線の色
    fill(255,0,0,lifespan); //パーティクルの塗り色
    ellipse(location.x,location.y,2,2); //パーティクルで生成される図形
  }

  boolean isDead() {
    return (lifespan < 0.0);
  }

}

class ParticleSystem {

  ArrayList<Particle> particles;
  PVector origin;
  
  ParticleSystem(int num, PVector v) {
    particles = new ArrayList<Particle>();
    origin = v.get();
    for (int i = 0; i < num; i++) { particles.add(new Particle(origin)); } } void run() { for (int i = particles.size()-1; i >= 0; i--) {
      Particle p = particles.get(i);
      p.run();
      if (p.isDead()) {
        particles.remove(i);
      }
    }
  }

  void addParticle() {
    Particle p;
    if (int(random(0, 2)) == 0) {
      p = new Particle(origin);
    } 
    else {
      p = new CrazyParticle(origin);
    }
    particles.add(p);
  }

  void addParticle(Particle p) {
    particles.add(p);
  }

  boolean dead() {
    return particles.isEmpty();
  }
}
総合課題4:
パーティクルを用いたグラフィックスを作成する。
画面のサイズは自由とする。
以下の項目を用いて独自の作品を制作する。
・背景に画像を使用する(写真やイラストなど)。
・パーティクルの粒子のサイズを変更する。
・パーティクルの生成方向を変更する。
・パーティクルの配色を変更する。

2019プログラミング講座15:ビデオのコントロール

Processingでは外部データとして、画像や音声に加えて映像を扱うことが可能です。今回は映像を扱う手法を学びます。Processingで映像を扱うためには、videoライブラリを使用します。
では、最初に映像データを用意しましょう。今回はmp4形式の映像データを用意します。Processingの「スケッチメニュー」から、「ファイルを追加」へと進み、用意した映像データを選択し「開く」ボタンを押してスケッチフォルダー内のdataフォルダーに格納します。準備ができたら、以下のコードを記述しましょう。

映像のループ再生

import processing.video.*; //videoライブラリの読み込み

Movie mov; //Movie変数を宣言しmovと名付ける

void setup() {
  size(800, 600); //映像の縦横比に合わせたウィンドウサイズが望ましい
  background(0);
  mov = new Movie(this, "XXXX.mov"); //変数movに映像データを格納する XXXXは映像データの名称に合わせる
  mov.loop(); //映像をループさせる
}

void movieEvent(Movie m) { 
  m.read(); //映像を読み取る
}

void draw() {    
  image(mov, 0, 0, width, height); //映像を画面に表示する
}

映像の再生速度のコントロール
次に読み込んだ映像の再生速度をコントロールするコードを記述します。

import processing.video.*; //videoライブラリの読み込み

Movie mov; //Movie変数を宣言しmovと名付ける

void setup() {
  size(800, 600);
  background(0);
  mov = new Movie(this, "octopus.mov"); //変数movに映像データを格納する XXXXは映像データの名称に合わせる
  mov.loop(); //映像をループさせる
}

void movieEvent(Movie m) { 
  m.read(); //映像を読み取る
}

void draw() {    
  image(mov, 0, 0, width, height); //映像を画面に表示する
  
  //map関数を使ってmouseのx座標の値0〜widthを0.1〜2までの値に変換する
  float newSpeed = map(mouseX, 0, width, 0.1, 2); 
  mov.speed(newSpeed); //変換された0.1〜2までの値を映像の再生速度に置き換える
}

映像のフレームをコントロール
映像のフレームの進行をマウスのX座標に関連づけるコードを記述してみましょう。

import processing.video.*;

Movie mov;

void setup() {
  size(800, 600);
  background(0);

  mov = new Movie(this, "octopus.mov");

  // 初期値として映像をポーズ(停止)させておきます。 
  mov.play();
  mov.jump(0);
  mov.pause();
}

void draw() {

  if (mov.available()) {
    mov.read();
    float f = map(mouseX, 0, width, 0, 1); //マウスのx座標を0〜1の値に置き換え変数fに代入
    float t = mov.duration() * f; //変数tにムービーの長さ(秒単位の位置)に0~1までの数値をかけて代入
    mov.play();
    mov.jump(t); //ムービーの再生箇所をtの位置にジャンプ
    mov.pause();
  }  

  image(mov, 0, 0, width, height);
}

2つの映像データを表示する
2つの映像データを実行ウィンドウに配置して再生します。

import processing.video.*;

Movie mov1,mov2; //変数を2つ用意する

void setup() {
  size(800, 400);
  background(0);

  mov1 = new Movie(this, "XXXX.mov");
  mov2 = new Movie(this, "YYYY.mov");

  mov1.play();
  mov1.pause();
  
  mov2.play();
  mov2.pause();
}

void draw() {

  if (mov1.available()) {
    mov1.read();    
    mov1.play();
    mov1.loop();
  }  
  
  if (mov2.available()) {
    mov2.read();    
    mov2.play();
    mov2.loop();
  }  

  image(mov1, 0, 100, 400, 200);
  image(mov2, 400, 100, 400, 200);
}

2つの映像データの再生をマウスでコントロール
2つの映像データを実行ウィンドウに配置してマウスのx座標で再生と停止を制御します。

import processing.video.*;

Movie mov1,mov2;

void setup() {
  size(800, 400);
  background(0);

  mov1 = new Movie(this, "octopus.mov");
  mov2 = new Movie(this, "tuna.mov");

  mov1.play();
  mov1.pause();
  
  mov2.play();
  mov2.pause();
}

void draw() {

  if (mov1.available()) {
    mov1.read();
    
    mov1.play();
    mov1.loop();
  }  
  
  if (mov2.available()) {
    mov2.read();
    
    mov2.play();
    mov2.loop();
  }  
  //マウスのx座標をウィンドウの中心から右か左かを判定して映像を再生
  if(mouseX<width/2){
    image(mov1, 0, 100, 400, 200);
  }else{
    image(mov2, 400, 100, 400, 200);
  }
  
}
総合課題3:
上記の映像のコントロール方法を応用して作品を制作すること。
自分で撮影した映像素材を使うこと。

2019プログラミング講座スケジュール

本講座のスケジュールを記載します。

まず、各回に記載している練習課題の制作をすすめてください。第7回では練習課題の講評を実施します。

第7回以降は総合課題として、より複雑な制作に挑んでもらいます。練習課題で取り上げた技術がベースになりますので、第7回までの内容について理解を深めておくようにしてください。第15回では総合課題の講評を実施します。

01: processingの基本
02: 描画(基本図形、色、座標)
03: 変数
04: 条件分岐
05: 繰り返し
06: 外部データの使用(画像、サウンド、動画)
07: 練習課題講評
08: 総合課題1 お絵かきソフトのインターフェイスデザイン
09: 総合課題2 サウンドのビジュアライズ
10: 総合課題3 ビデオコントロールのインターフェイスデザイン
11: 総合課題4 ARを活用した作品制作
12: 制作
13: 制作
14: 制作
15: 総合課題講評

課題提出:2020年1月29日(水)まで

提出方法:共有フォルダに提出(詳細は授業内で告知します)

評価:
1 技術修得回での小課題の制作(25%)練習課題
2 課題を制作する(40%)総合課題
3 講評を受ける(20%)練習課題講評+総合課題講評
4 授業内での積極的制作活動:特に企画報告や進捗状況報告を評価します。(15%)
*注意:課題提出だけを実施し講評会に出席しない場合は講評点(20点)が減点になります。