2020プログラミング講座1: Processingについて

本講座ではプログラミングを学習するための環境としてProcessing[図1]を使用します。

図1 Processingのウェブサイト

Processingはグラフィックスをプログラムで生成するうえで困難な各種設定などを必要とせず、コーディングに専念できるという特長があります。
また、Processingはグラフィックスだけでなく、音声や動画なども扱うことができ、それらを組み合わせてインタラクティブ(双方向性のある)な表現を可能にしてくれます。

それでは最初にProcessingがどういう経緯で制作されたプログラミング環境なのかを解説します。

Processingは当時マサチューセッツ工科大学メディアラボに在籍していたCasey ReasとBen Fryによって2001年に誕生しました。
その後2002年から2008年まで開発が続き、2008年秋からバージョン1.0がリリースされ、2013年にはバージョン2.0が、つづく2015にはバージョン3.0がリリースされ現在に至っています。
ProcessingはJava(Java日本語サイト)というプログラミング言語の環境を活用してグラフィック機能などに特化したものだと言えます。

Processingの作者であるCasey ReasとBen Fryは著書「Processingをはじめよう」の中で影響を受けた先行するプログラミング環境をあげています。
ひとつはLOGO(LOGOファウンデーション)で、教育のために開発されたプログラミング環境でした。この言語は児童の発達心理学の成果などが活かされており子どもが思考するための道具としての工夫がなされていました。
ふたつめはDesign By Numbers(公式サイト)で、この言語はマサチューセッツ工科大学メディアラボのJohn Maedaによって開発されました。Design By Numbersはデザイナーやアーティストといったプログラミングを専門としていない人でもプログラミングが可能となる環境を目指して作られており、数値によるグラフィックデザインの研究や教育に使われました。

上のような先行するプログラミング環境の思想や特徴の影響を色濃く受けたProcessingは、初心者にもわかりやすく、特にアーティストやデザイナーなどが創造や表現のためにプログラミングを使うことを学ぶ最初の一歩を踏み出すのに最適な言語です。

課題1
Processingを活用して制作された下記の作品アーカイヴサイトを閲覧し,どのような作品が制作できるのか調べてみましょう。
https://processing.org/exhibition/
作品を1つ選んで、その作品についての感想を200字程度で記載してCampusSquareに提出してください。
A4サイズ・縦位置・横書き PDF形式のファイルをアップロードしてください。

締切:10月8日(木)17:00まで

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プログラミング講座14:サウンドのビジュアライズ

サウンドの再生

はじめに、サウンドの再生を実行します。サウンドを扱うためにminimというサウンドライブラリを用います。(ライブラリとは、processingなどプログラミング言語の開発環境に様々な機能を追加するプログラムの集まりのようなものだと理解するとよいでしょう。)また、今回はminimを使うためにprocessing バージョン2を使用しますので注意してください。

まず、processingを起動しておきます。次にフリーの音源データをインターネット上から探してデスクトップにダウンロードします。ダウンロードする音源データは必ずmp3形式を選んでください。ダウンロードした音源データの名称をtest.mp3と変更します。

次に、デスクトップにダウンロードした音源データをprocessingで扱えるように追加します。processingのメニューからSketchを選択し、Add File…を選びます。デスクトップから先ほどダウンロードした音源データを選択しopenボタンを押して追加します。

以下のコードを記述して実行ボタンを押すと音源データが再生されます。

import ddf.minim.*; //サウンドライブラリminimの読み込み
 
Minim sound; //minim型変数の宣言
AudioPlayer player;//サウンドデータ格納用変数の用意
 
void setup(){
  size(100, 100);
  sound = new Minim(this); //minim型変数の初期化
  player = sound.loadFile("test.mp3"); //サウンドデータの読み込み
  player.play(); //サウンドデータの再生
}
 
void draw(){
  background(0);
}
 
void stop(){ 
  player.close(); //サウンドデータの終了
  sound.stop(); //minimプログラムの停止
  super.stop(); //プログラムの停止
}

マウスクリックでサウンドを再生する

次にマウスをクリックすることでサウンドが再生されるプログラムを作成してみましょう。(新規でプログラムを作成する場合は、先ほどと同じようにあらかじめ音源データを追加しておきます。)

import ddf.minim.*;
 
Minim sound;
AudioPlayer player;
 
void setup(){
  size(100, 100);
  sound = new Minim(this);
  player = sound.loadFile("test.mp3");
}
 
void draw(){
  background(0);
}
 
void stop(){
  player.close();
  sound.stop();
  super.stop();
}
 
void mousePressed() { //マウスを押下したときに動作する関数
    player.play();
    player.rewind(); //サウンドデータの巻き戻し
}

音量の視覚化

サウンドの音量(ボリューム)とグラフィックスを関連づけてみましょう。

import ddf.minim.*;
 
Minim sound;
AudioPlayer player;
 
void setup(){
  size(400, 400);
  sound = new Minim(this);
  player = sound.loadFile("test.mp3");
}
 
void draw(){
  background(0);
  float d = player.mix.level() * 2000; //サウンドデータの音量を数値化して変数dに代入
  ellipse(width/2, height/2, d, d);
}
 
void stop(){
  player.close();
  sound.stop();
  super.stop();
}
 
void mousePressed() {
    player.play();
    player.rewind();
}

複数のサウンドを再生する

複数のサウンドをマウスクリックで再生するプログラムを作成します。2種類の音源(mp3データ)を用意して、それぞれ、test1.mp3、test2.mp3と名称変更します。2種類の音源データをprocessingに追加します。
準備ができたら、以下のコードを記述しましょう。

import ddf.minim.*;
 
Minim sound;
AudioPlayer player1, player2; //サウンドデータ格納用変数を2種類用意する
 
void setup(){
  size(800, 800);
  sound = new Minim(this);
 //下記で2種類のサウンドデータを読み込む
  player1 = sound.loadFile("test1.mp3"); 
  player2 = sound.loadFile("test2.mp3");
  fill(255); //オブジェクトの塗りの初期設定
}
 
void draw(){
  background(0);
  rect(50, 50, 100, 100);
  rect(200, 50, 100, 100);
  rect(350, 50, 100, 100);
  rect(500, 50, 100, 100);
  float d1 = player1.mix.level() * 2000;
  float d2 = player2.mix.level() * 2000;
  ellipse(width/2, height/2, d1, d1);
  ellipse(width/2, height/2, d2, d2);
}
 
void stop(){
  player1.close();
  player2.close();
  sound.stop();
  super.stop();
}

void mousePressed() {
 if (mouseX > 50 && mouseX < 150 && mouseY > 50 && mouseY < 150) { 
    player1.play(); 
    player1.rewind(); 
}
 if (mouseX > 200 && mouseX < 300 && mouseY > 50 && mouseY < 150) { 
    player1.pause(); 
    player1.rewind(); 
}
 if (mouseX > 350 && mouseX < 450 && mouseY > 50 && mouseY < 150) { 
    player2.play(); 
    player2.rewind(); 
}
 if (mouseX > 500 && mouseX < 600 && mouseY > 50 && mouseY < 150) {
    player2.pause();
    player2.rewind();
  }
}
 
void mouseReleased() {
  fill(255);
}
総合課題2:
上記のサウンド再生ソフトを改良し独自のデザインにする。
ただし以下の機能は全て必ず実装すること。
画面のサイズやボタンの配置は自由とする。
・サウンドデータを3種類以上用意し再生と停止ができるようにする。
・サウンドの音量で独自に用意した画像を変形させる。
・背景画像を用意し配置する。
・ボタンを画像に変更する。

2019プログラミング講座13:インターフェースデザイン

インターフェース(interface)とは英語で境界や界面を表す言葉です。この講座では、ユーザーインターフェースと呼ばれる、人間と機械の境界を取り扱います。お絵かきソフトのインターフェースデザインを通して、プログラミングの過程を学んでいきましょう。

まず、はじめに作成するお絵かきソフトの画面サイズを決めます。ここでは800ピクセルx800ピクセルの画面で作成することにします。また背景色を白に設定します。

void setup(){
  size(800,800);//画面サイズ
 background(255);//背景色を白に設定
}

void draw(){
  
}

次に、幅20ピクセル・高さ20ピクセルの黒色の円がマウスの動きに付いてくるようにします。

int penX = 0;//円のX座標
int penY = 0;//円のY座標
int penSize = 20;//円の直径

void setup(){
  size(800,800);
  background(255);
}

void draw(){
  penX = mouseX;//円のX座標にマウスのX座標を代入
  penY = mouseY;//円のY座標にマウスのY座標を代入
  fill(0);//円の塗りを黒色にする
  noStroke();//円の輪郭線の描画を無効にする
  ellipse(penX,penY,penSize,penSize);//円の描画
}

円のサイズを変えるためのアイコンを配置します。アイコンが描線で隠れてしまわないようにアイコンの背景として長方形を配置します。

int penX = 0;
int penY = 0;
int penSize = 20;

void setup(){
  size(800,800);
  background(255);
}

void draw(){
  penX = mouseX;
  penY = mouseY;
  fill(0);
  noStroke();
  ellipse(penX,penY,penSize,penSize);
  fill(255);
  rect(0,700,800,100);//アイコンの背景
  fill(0);
  ellipse(50,750,20,20);//細い描線のアイコン
  ellipse(150,750,40,40);//太い描線のアイコン 
}

アイコンの上にマウスが重なると描線の太さが変わるように設定します。

int penX = 0;
int penY = 0;
int penSize = 20;

void setup(){
  size(800,800);
  background(255);
}

void draw(){
  penX = mouseX;
  penY = mouseY;
  fill(0);
  noStroke();
  ellipse(penX,penY,penSize,penSize);
  fill(255);
  rect(0,700,800,100);
  fill(0);
  ellipse(50,750,20,20);
  ellipse(150,750,40,40); 
  if(penX<60 && penY>740){ //小さい円のアイコンの座標にマウスが重なった場合
    penSize=20;
  }
  if(penX>60 && penX<170 && penY>740){ //太い円のアイコンの座標にマウスが重なった場合
    penSize=40;
  }
}

同じ手法を使って描線の色を変えてみましょう。

int penX = 0;
int penY = 0;
int penSize = 20;
int penR = 0;//描線の色・赤
int penG = 0;//描線の色・緑
int penB = 0;//描線の色・青


void setup(){
  size(800,800);
  background(255);
}

void draw(){
  penX = mouseX;
  penY = mouseY;
  fill(penR,penG,penB);
  noStroke();
  ellipse(penX,penY,penSize,penSize);
  fill(255);
  rect(0,700,800,100);
  fill(0);
  ellipse(50,750,20,20);
  ellipse(150,750,40,40);
  fill(255,0,0);
  ellipse(250,750,40,40);
  fill(0,255,0);
  ellipse(350,750,40,40);
  fill(0,0,255);
  ellipse(450,750,40,40);
  if(penX<60 && penY>740){
    penSize=20;
  }
  if(penX>60 && penX<170 && penY>740){
    penSize=40;
  }
  if(penX>230 && penX<270 && penY>740){ //アイコンに描線が重なったら描線の色を赤色に変更する
    penR = 255;
    penG = 0;
    penB = 0;
  }
  if(penX>330 && penX<370 && penY>740){ //アイコンに描線が重なったら描線の色を緑色に変更する
    penR = 0;
    penG = 255;
    penB = 0;
  }
  if(penX>430 && penX<470 && penY>740){ //アイコンに描線が重なったら描線の色を青色に変更する
    penR = 0;
    penG = 0;
    penB = 255;
  }
}

更に描線をline()関数を使用してスムーズにつなげてみましょう。1フレーム前のX座標、Y座標を格納するpmouseX、pmouseYという変数を使用します。

int penX = 0;
int penY = 0;
int penPX = 0;//pmouseXの値を格納する変数
int penPY = 0;//pmouseYの値を格納する変数
int penSize = 20;
int penR = 0;
int penG = 0;
int penB = 0;


void setup(){
  size(800,800);
  background(255);
}

void draw(){
  penX = mouseX;
  penY = mouseY;
  penPX = pmouseX; //1フレーム前のX座標を代入
  penPY = pmouseY; //1フレーム前のY座標を代入
  stroke(penR,penG,penB); //線の色を設定
  strokeWeight(penSize); //線の太さを設定
  line(penX,penY,penPX,penPY); //線を描画
  noStroke(); //以下のオブジェには線を描画しないよう設定
  fill(255);
  rect(0,700,800,100);
  fill(0);
  ellipse(50,750,20,20);
  ellipse(150,750,40,40);
  fill(255,0,0);
  ellipse(250,750,40,40);
  fill(0,255,0);
  ellipse(350,750,40,40);
  fill(0,0,255);
  ellipse(450,750,40,40);
  if(penX<60 && penY>740){
    penSize=20;
  }
  if(penX>60 && penX<170 && penY>740){
    penSize=40;
  }
  if(penX>230 && penX<270 && penY>740){
    penR = 255;
    penG = 0;
    penB = 0;
  }
  if(penX>330 && penX<370 && penY>740){
    penR = 0;
    penG = 255;
    penB = 0;
  }
  if(penX>430 && penX<470 && penY>740){
    penR = 0;
    penG = 0;
    penB = 255;
  }
}

次にマウスボタンが押されているときだけ、描線が描画されるように改良しましょう。

int penX = 0;
int penY = 0;
int penPX = 0;
int penPY = 0;
int penSize = 20;
int penR = 0;
int penG = 0;
int penB = 0;


void setup(){
  size(800,800);
  background(255);
}

void draw(){
  penX = mouseX;
  penY = mouseY;
  penPX = pmouseX;
  penPY = pmouseY;
  stroke(penR,penG,penB);
  strokeWeight(penSize);
  if(mousePressed){ //マウスボタンが押されている間だけコードが実行される
    line(penX,penY,penPX,penPY);
  }
  noStroke();
  fill(255);
  rect(0,700,800,100);
  fill(0);
  ellipse(50,750,20,20);
  ellipse(150,750,40,40);
  fill(255,0,0);
  ellipse(250,750,40,40);
  fill(0,255,0);
  ellipse(350,750,40,40);
  fill(0,0,255);
  ellipse(450,750,40,40);
  if(penX<60 && penY>740){
    penSize=20;
  }
  if(penX>60 && penX<170 && penY>740){
    penSize=40;
  }
  if(penX>230 && penX<270 && penY>740){
    penR = 255;
    penG = 0;
    penB = 0;
  }
  if(penX>330 && penX<370 && penY>740){
    penR = 0;
    penG = 255;
    penB = 0;
  }
  if(penX>430 && penX<470 && penY>740){
    penR = 0;
    penG = 0;
    penB = 255;
  }
}

最後に、キーボードの特定のボタンを押すと描線がリセットされるようにしましょう。keyPressedおよびkeyという関数を用いることで、キーボードが押されているかどうか、また、どのキーが押されているかをif文で判定するコードを書き加えます。

int penX = 0;
int penY = 0;
int penPX = 0;
int penPY = 0;
int penSize = 20;
int penR = 0;
int penG = 0;
int penB = 0;

void setup(){
  size(800,800);
  background(255);
}

void draw(){
  penX = mouseX;
  penY = mouseY;
  penPX = pmouseX;
  penPY = pmouseY;
  stroke(penR,penG,penB);
  strokeWeight(penSize);
  if(mousePressed){
    line(penX,penY,penPX,penPY);
  }
  noStroke();
  fill(255);
  rect(0,700,800,100);
  fill(0);
  ellipse(50,750,20,20);
  ellipse(150,750,40,40);
  fill(255,0,0);
  ellipse(250,750,40,40);
  fill(0,255,0);
  ellipse(350,750,40,40);
  fill(0,0,255);
  ellipse(450,750,40,40);
  if(penX<60 && penY>740){
    penSize=20;
  }
  if(penX>60 && penX<170 && penY>740){
    penSize=40;
  }
  if(penX>230 && penX<270 && penY>740){
    penR = 255;
    penG = 0;
    penB = 0;
  }
  if(penX>330 && penX<370 && penY>740){
    penR = 0;
    penG = 255;
    penB = 0;
  }
  if(penX>430 && penX<470 && penY>740){
    penR = 0;
    penG = 0;
    penB = 255;
  }
  if ((keyPressed == true) && ((key == 'd') ||  (key == 'D'))) {
    fill(255);
    noStroke();
    rect(0,0,800,700);
  }
}
総合課題1:
上記のお絵かきソフトを改良し独自のインターフェースデザインにリデザインする。
ただし以下の機能は全て必ず実装すること。
画面のサイズやアイコンの配置は自由とする。
・描画色を黒色に戻せるようにする。
・3段階以上の太さの描線で描画できるようにする。
・4色以上の色で描画できるようにする。
・消しゴム機能を追加する。

2019プログラミング講座12:画像

Processingでは他のソフトウェアなどで作成した画像を扱うことができます。

画像ファイルの読み込み
まず始めにProcessingで使用したい画像ファイルを用意します。次にProcessingを開き、新しいスケッチ(sketch_)を表示します。Processingの「スケッチ(Sketch)」メニューから「ファイルを追加…(Add File…)」を選び実行します。使用したい画像ファイルを選択し「開く(Open)」ボタンを押して読み込みます。
追加した画像ファイルは「スケッチ(Sketch)」メニューの「スケッチフォルダーを開く(Show Sketch Folder)」を実行し、dataフォルダの内容を確認すると見つかります。このdataフォルダに格納された画像ファイルをProcessingのプログラムで使用します。Processingでは、ひとつのdataフォルダに複数の画像ファイルを格納して使用します。

画像ファイルの表示
画像ファイルをProcessingのプログラムで使用してみましょう。画像ファイルは、ここでは仮に XXXX.jpg という名称のJPEGデータとします。

PImage img;

void setup(){
  size(800,800);
  img = loadImage("XXXX.jpg");
}

void draw(){
  image(img,0,0);
}

上記のプログラムでは、始めにPImage変数を作成し、img と名付けます。変数 img にloadImage()関数を使って画像ファイル XXXX.jpg(XXXXは任意の名称を各自で入力してください)を格納します。画像ファイル XXXX.jpg を格納した変数 img をimage()関数を使って表示します。image(img,0,0) 内の数値は画像ファイルの座標を表します。

複数の画像ファイルを表示する
複数の画像ファイルを表示する際のプログラム例を以下に記述します。画像ファイルは、ここでは仮に XXXX_1.jpg, XXXX_2.jpg という名称の2種類のJPEGデータとします。

PImage img1;
PImage img2;

void setup(){
  size(800,800);
  img1 = loadImage("XXXX_1.jpg");
  img2 = loadImage("XXXX_2.jpg");
}

void draw(){
  image(img1,0,0,800,800);
  image(img2,mouseX,mouseY,40,40);
}

上記のプログラムでは、image(img1,0,0,800,800) のように記述することで画像ファイルの表示サイズをプログラムで変更しています。image()関数の各パラメータは以下のようになります。

image(画像を格納した変数, x座標, y座標, 幅, 高さ)

扱える画像フォーマット
Processingで扱うことのできるラスタ画像のファイルフォーマットは、JPEG、PNG、GIF になります。
ラスタ画像とは色のついた点(ドット)の集合として画像を表現するデータ形式のことです。もとの画像サイズより拡大するとジャギー(ギザギザ)が目立つようになるなど、拡大、縮小、変形には適さない形式ですが、写真などの複雑な画像の表現に適しています。

練習課題12-1:
PNGデータを使用し背景を透明化した画像データを作成する。
作成した画像データを使用して、画像データがマウスカーソルの動きに追従する作品を作成してください。

画像を活用したプログラム
画像を活用したプログラムを作成してみましょう。マウスと画像の距離に応じてeasingを施すプログラムを作成します。
easingとは動きを緩める効果のことで、Robert Pennerが数種類のeasing効果を考案しています。
等速度(動き始めから終わりまで同じ速度)で動くのではなく、動きに変化をつけることが可能になります。
今回はマウスに画像が近づくにつれてゆっくりと動くeasing効果を試してみましょう。
画像作成ソフト(Photoshopなど)で背景を透明化したPNG画像を用意し任意の名前をつけてProcessingのファイルに追加しておきます。

PImage img;
float x;
float y;
float easing = 0.08;
float dx;
float dy;

void setup() {
  size(400, 400);
  img = loadImage("map.png");
}

void draw() {
  background(255);
  
  dx = mouseX - x;
  if(abs(dx) > 1) {
    x += dx * easing;
  }

  dy = mouseY - y;
  if(abs(dy) > 1) {
    y += dy * easing;
  }
  
  imageMode(CENTER);
  image(img,x,y,50,50);
}

画像の現在位置を変数(今回はx,y)で指定し、目標位置であるマウスの位置との距離を求め、その距離にeasingを発生させるための数値をかけています。
dx = mouseX – x; あるいは dy = mouseY – y;の部分でマウスの位置と画像の位置の距離を変数(dx,dy)に格納します。
abs( )関数を使って距離の絶対値(正数)を求め、距離の値が1より大きい場合に画像の現在地をeasingの値を使って緩めています。

練習課題12-2:
背景を透明化したPNG形式の画像データを5つ作成する。
作成した5つの画像データを使用して、5つの画像データがそれぞれ異なる
easing値でマウスカーソルの動きに追従する作品を作成してください。

2019プログラミング講座11:乱数とジェネラティブなグラフィック表現

生成される予測できない数列の要素を乱数と呼びます。Processingではrandom()関数を使って乱数を擬似的に生成することができます。

ランダムな線の描画
random()関数は呼び出すたびに異なる数値を返します。パラメータで値の上限あるいは値の範囲を指定することができます。たとえばrandom(10)とすると、0以上、10未満の乱数が生成されます。生成される数値は浮動小数点になるため、変数は float型を使います。
それでは、乱数を使って線を描画してみましょう。線の配色も乱数で生成しています。

void setup(){
   size(400, 400);
   background(255);
}

void draw(){
  for(int i = 0; i < 100; i++){
    stroke(random(255), random(255), random(255));
    line(random(width), random(height), random(width), random(height));
  }
}

ランダムな円の描画
次に円を乱数を使って描画してみましょう。

float speed = 5;
float x = 200;
float y = 200;

void setup(){
   size(400, 400);
   background(255);
}

void draw(){
    x += random(-speed, speed);
    y += random(-speed, speed);
    noStroke();
    fill(random(255), random(255), random(255));
    ellipse(x, y, 100, 100);
}

これらのグラフィックは、コードが実行されるたびに、その実行結果が異なることに気がついたでしょうか。
コードに規則を与えることで、予測は可能だが確定的ではないグラフィックスなどを生成することができます。

ジェネラティブなグラフィック表現
ここからは、参考書籍「ジェネラティブ・アート Processingによる実践ガイド マット・ピアソン著」を参考にジェネラティブ(生成的)なグラフィック表現に挑戦してみましょう。

円の描画
まずは、これまでどうりの方法で円を描いてみましょう。

float radius = 200;
int centerx = 400;
int centery = 400;

void setup(){
  size(800,800);
  background(255);
  strokeWeight(2);
  smooth();
}

void draw(){
  stroke(200, 200, 200);
  noFill();
  ellipse(centerx, centery, radius*2, radius*2);
}

円を描画する別の方法
次に三角関数を用いて点で円を描いてみましょう。

float radius = 200;
int centerx = 400;
int centery = 400;
float x, y;
float lastx = -999;
float lasty = -999;
float ang;
float rad; 

void setup(){
  size(800,800);
  background(255);
  strokeWeight(2);
  smooth();
}

void draw(){
  stroke(0, 0, 0);
  for(ang = 0; ang <= 360; ang += 2){
    rad = radians(ang);
    x = centerx + (radius * cos(rad));
    y = centery + (radius * sin(rad));
    point(x,y);
  }
}

円かららせんを描画する
円のコードをもとにして、らせんを描いてみましょう。

float radius = 10;
int centerx = 400;
int centery = 400;
float x, y;
float lastx = -999;
float lasty = -999;
float ang;
float rad; 

void setup(){
  size(800,800);
  background(255);
  strokeWeight(2);
  smooth();
}

void draw(){
  stroke(0, 0, 0);
  for(ang = 0; ang <= 1440; ang += 2){
    radius += 0.5;
    rad = radians(ang);
    x = centerx + (radius * cos(rad));
    y = centery + (radius * sin(rad));
    point(x,y);
  }
}

らせんを線で描画する
らせんを点ではなく線で描きましょう。

float radius = 10;
int centerx = 400;
int centery = 400;
float x, y;
float lastx = -999;
float lasty = -999;
float ang;
float rad; 

void setup(){
  size(800,800);
  background(255);
  strokeWeight(0.5);
  smooth();
}

void draw(){
  stroke(0, 0, 0);
  for(ang = 0; ang <= 1440; ang += 2){ 
      radius += 0.5; rad = radians(ang); 
      x = centerx + (radius * cos(rad)); 
      y = centery + (radius * sin(rad)); 
  if(lastx > -999){
      line(x, y, lastx, lasty);
    }
    lastx = x;
    lasty = y;
    lasty = y;
  }
}

らせんの線にノイズを加える
線にノイズを加えることで手書きの描線のようなゆらぎが現れます。

float radius = 10;
int centerx = 400;
int centery = 400;
float x, y;
float lastx = -999;
float lasty = -999;
float ang;
float rad; 
float radiusNoise;
float thisRadius;

void setup(){
  size(800,800);
  background(255);
  strokeWeight(0.5);
  smooth();
}

void draw(){
  stroke(0, 0, 0);
  radiusNoise = random(10);
  for(ang = 0; ang <= 1440; ang += 5){
    radiusNoise += 0.05;
    radius += 0.5;
    thisRadius = radius + (noise(radiusNoise) * 200)-100;
    rad = radians(ang);
    x = centerx + (thisRadius * cos(rad));
    y = centery + (thisRadius * sin(rad)); 
    if(lastx > -999){
      line(x, y, lastx, lasty);
    }
    lastx = x;
    lasty = y;
  }
}

らせんに乱数を加え複数重ねて描画する
らせんの描線に乱数を加えながら複数のらせんを重ねて描いてみましょう。

float radius;
int centerx = 400;
int centery = 400;
float x, y;
float lastx;
float lasty;
float ang;
float rad; 
float radiusNoise;
float thisRadius;
int startangle;
int endangle;
int anglestep;

void setup(){
  size(800,800);
  background(255);
  strokeWeight(0.5);
  smooth();
}

void draw(){
  for(int i = 0; i < 100; i++){
    lastx=-999;
    lasty=-999;
    radius = 10;
    stroke(random(255), random(255), random(255),50);
    startangle = int(random(360));
    endangle = 1440 + int(random(1440));
    anglestep = 5 + int(random(3));
    radiusNoise = random(10);
    for(ang = startangle; ang <= endangle; ang += anglestep){ 
      radiusNoise += 0.05; 
      radius += 0.5; 
      thisRadius = radius + (noise(radiusNoise) * 200)-100; 
      rad = radians(ang); 
      x = centerx + (thisRadius * cos(rad)); y = centery + (thisRadius * sin(rad)); 
      if(lastx > -999){
        line(x, y, lastx, lasty);
      }
      lastx = x;
      lasty = y;
    }
  }
}
課題11:
乱数を用いたグラフィック作品を5点作成する。

2019プログラミング講座10:繰り返し構造

繰り返し構造について
プログラムでは繰り返しの構造を使うことで、ひとまとまりのコードを繰り返し実行することができます。繰り返しの構造を使うことで複雑な構造のプログラムを短いコードにできたり、プログラムにパターンを生み出すことなどができます。

forループ文
繰り返し構造を記述するコードとしてforループ文を使ったプログラムを作成してみましょう。
forループ文は以下のように記述します。

for(初期値; 条件式; 更新){

繰り返し実行されるコード

}

例)
for(i = 0; i < 100; i+=10){

ellipse(i,100,20,20);

}

・「初期値」で最初の値を設定します。  forループ文では慣例的に変数 i が使われることが多いです。
この例では変数iが宣言され、初期値は0に設定されています。
・「条件式」で変数 i を評価します。  変数 i の値を比べて条件にあわなくなるまで「繰り返し実行されるコード」を実行します。
この例では変数iの値が100以下の値である限り「繰り返し実行されるコード」が実行され続けます。
・「更新」で変数の値を変化させていきます。
この例では変数iの値は10ずつ加算されていきます。0,10,20,30,40〜のように変化します。

条件式の例)
i > A Aより大きい
i < A Aより小さい  i >= A A以上
i <= A A以下
i == A Aと等しい
i != A Aと等しくない
「更新」で変数 i の値をどのように変化させるかの例)
i+=10ならコードが実行されるごとに変数 i に10加算
i-=10なら10減算
i++は1加算
i–は1減算。

それでは、forループ文を使った繰り返し構造のプログラムを記述してみましょう。

void setup(){
  size(400,200);
}

void draw(){
  for(int i = 20; i < 400; i += 20){
    ellipse(i,100,20,20);
  }
}

 

二重の繰り返し構造
forループ文のなかにforループ文を記述することができます。
それでは、二重の繰り返し構造のプログラムを記述してみましょう。

void setup(){
  size(400,400);
  background(0);
  noStroke();
}

void draw(){
  for(int i = 0; i <= 400; i += 20){
    for(int j = 0; j <= 400; j += 20){
      fill(255,48,203);
      ellipse(i,j,15,15);
   }
  }
}

 

二重の繰り返し構造を使った別のプログラムを記述してみましょう。

void setup(){
  size(400,400);
}

void draw(){
  background(0);
  fill(252,145,3);
  stroke(250,240,48);
  for(int i = 0; i <= 400; i += 20){
    for(int j = 0; j <= 400; j += 20){
      ellipse(i,j,10,10);
      line(i,j,mouseX,mouseY);
   }
  }
}

 

練習課題10:これまでに学んだ、点、線、面および色のコードと繰り返しの構造を組み合わせて
          グラフィック作品を作成してください。

2019プログラミング講座9:条件分岐

条件分岐とは
プログラミングは通常は最初の1行から終わりの1行まで順番に処理されます。しかし、それでは複雑な処理をコンピューターに実行させることができません。複雑な処理をさせるための方法のひとつとして条件分岐という考え方が存在します。

単純な処理:
公園に行く。

複雑な処理:
晴れたら公園に行く。
そうでなければ、家で読書する。

上の例のように、条件によって行動(=処理)が変化する(=分岐する)ことを条件分岐といいます。上の複雑な処理の例は以下のように条件分岐命令の書式で記述することができます。

if( 晴れ ){ 公園に行く; }else{ 家で読書する; }

練習課題09-01:if( 晴れ ){ 公園に行く; }else{ 家で読書する; }のように、あなたの行動を
        条件分岐命令の書式で記述してみましょう。

コードであらわす場合は以下のように記述します。

if( 条件式 ){ 条件式が真の場合に実行する内容; }else{ 条件式が真ではない場合に実行する内容; }

プログラミングでは、真であることをtrueと記述します。また真ではない場合は偽とあらわしfalseと記述します。

次に実際にProcessingのコードとして条件分岐命令を記述してみましょう。

if文
if( 条件式 ){ 条件がtrueの場合に実行される内容; }

条件が真(true)の場合:

int i=1;
if( i>0 ){
 background(0,0,0);
}

条件が偽(false)の場合:

int i=0;
if( i>0 ){
 background(0,0,0);
}

if〜else文
if( 条件式 ){ 条件がtrueの場合に実行される内容; }else{ 条件がfalseの場合に実行される内容; }

int i=1;
if( i>0 ){
 background(255,0,0);
}else{
 background(0,0,255);
}

条件分岐命令を使用してProcessingのストラクチャーを利用したコードを記述してみましょう。

int x=0;

void setup(){
  size(400,400);
}

void draw(){
   x = mouseX;
   if( x<200 ){
      background(255,0,0);
   }else{
      background(0,0,255); 
   }
}

上のコードではウィンドウを幅400ピクセル、高さ400ピクセルに設定しマウスのX座標がウィンドウの中心(200ピクセルの位置)より「小さい(=true)か否(=false)か」を条件式として判定し、背景色を切り替えています。

練習課題09-02:if〜else文を活用してマウスの座標に応じて変化するグラフィック作品を
        制作しなさい。

条件式
真偽を判定するために使用できる条件式を以下に記載します。

< 左辺が右辺より小さい

i<100

> 左辺が右辺より大きい

i>100

<= 左辺が右辺以下

i<=100

>= 左辺が右辺以上

i>=100

>== 左辺が右辺に等しい

i>==100

!= 左辺が右辺に等しくない

i>!=100

&& かつ (「かつ」はandとも表現する)

i>0 && i<100

|| または (「または」はorとも表現する)

i<0 || i>100

さまざまな条件式を利用したコードを記述してみましょう。

int x=0;
int y=0;

void setup(){
  size(400,400);
}

void draw(){
 x = mouseX;
 y = mouseY;
 if( x<200 ){ background(255,0,0); } if( x>200 ){
  background(0,0,255); 
 } 
 if( x==200){
  fill(0,0,0);
  ellipse(width/2,height/2,300,300); 
 } 
 if( y>0 && y<100){
  fill(255,255,255);
  ellipse(width/2,height/2,200,200); 
 }
 if( x<100 || x>300){
  fill(0,255,0);
  ellipse(width/2,height/2,100,100); 
 }
 line(width/2,0,width/2,height);
 line(0,height/2,width,height/2);
}

上のコードの例ではマウスの座標に応じて背景色や円の表示が切り替わります。

練習課題09-03:さまざまな条件式を活用してマウスの座標に応じて変化するグラフィック作品を
        制作しなさい。

2019プログラミング講座8:変数

変数について
変数とは、ある値をコンピュータのメモリに保存しておき、プログラムのなかで再利用できるようにするための仕組みです。

変数の作成
変数を作成するには、データ型、変数の名前、変数の値を考えて設定します。
変数を使う前には必ず変数の宣言をします。宣言とは、コンピュータのメモリにデータの値を格納する領域を確保することです。
変数の宣言をするためには格納する値にあったデータ型を定義し、名前を決めて値を設定します。

変数の宣言は以下のように記述します。

データ型 変数の名前 = 値;

例)
int x = 10;

上の例は以下のように記述することができます。

int x;
x = 10;

ある変数に格納できる値や種類はデータ型で指定します。データ型には以下のようなものがあります。
・整数(小数点以下のない数値を扱うデータ型 マイナスの値をとることができる) int など
・浮動小数点(小数点を扱えるデータ型) float など
・文字 char
・単語 String
・画像 PImage
・フォント PFont
など

変数には任意の名前を付けて設定をします。データの内容がわかりやすい名前を選んで設定しましょう。

変数を使った描画
それでは、変数を使って基本図形を描画してみましょう。

int d = 100; //変数の宣言
size(400,400);
ellipse(100,200,d,d);
ellipse(200,200,d,d);
ellipse(300,200,d,d);

上の例では1行目の int d = 100; にて変数の宣言が行われています。
int で整数のデータ型を定義し、変数の名前を d とし、変数 d に 100 という整数の値を代入しています。
変数を使うことで3つの円が同じ値を受け取ることができます。

練習課題08-01:変数を2つ作成し、x座標とy座標に変数を使用した4つの方形を描いてみましょう。

コンソールへの表示
Processingではプログラミングによる各種の値をコンソールに表示できます。コンソールとはスケッチを記述しているエディタの下の部分です。
コンソールへの値の表示には以下の関数を使用して記述します。

println(値);

例1)
int x = 1;
println(x);

コンソールにはxの値である1が表示されます。

それでは、コンソールを活用したスケッチを描いてみましょう。

int x = 0;//変数の宣言
int y = 0;//変数の宣言

void setup(){
  size(400,400);
}

void draw(){
  x=mouseX;
  y=mouseY;
  println(x);//コンソールへの値の表示
  println(y);//コンソールへの値の表示
}

上のプログラミングでは2種類の変化する値がコンソールに表示されますが、何の値かわかりにくいので、少し改良してみましょう。
以下のように記述することで何の値を表示するのかを明示することができます。

println(“値の説明” + 値);

例)
println(“x:” + x);

それでは、先ほどのスケッチを改良してみましょう。座標の変化がわかりやすいようにラインの表示も加えてみましょう。

int x = 0;//変数の宣言
int y = 0;//変数の宣言

void setup(){
  size(400,400);
}

void draw(){
  background(255);
  x=mouseX;
  y=mouseY;
  println("x:"+x);//コンソールへの値の表示
  println("y:"+y);//コンソールへの値の表示
  line(x,0,x,height);
  line(0,y,width,y);
}

上のスケッチではwidthheightというシステム変数を使用しています。システム変数とはProcessingによってあらかじめ設定されている変数です。

width size関数で設定されたウィンドウの幅
height size関数で設定されたウィンドウの高さ

練習課題08-02:変数を2つ作成し、マウスのx座標とy座標を中心にした円が描画されるスケッチを描く。
その際、円は画面に同時に1個だけ表示されていること。またx座標とy座標の値をコンソールに出力すること。

演算子
演算子とは各種の演算を表わす記号のことです。以下のような演算子があります。

=  代入する 例)x = 0;
+  足す 例)x = x + 1;
  引く 例)x = x – 1;
*  かける 例)x = x * 2;
/  割る 例)x = x / 2;

また演算子を組み合わせた記述もよく使われます。

+= 例)x += 1; x=x+1と同じ計算結果となる
-=  例)x -= 1; x=x-1と同じ計算結果となる
++ 例)x++; x+=1あるいは、x=x+1と同じ計算結果となる
例)x–; x-=1あるいは、x=x-1と同じ計算結果となる

それでは、これまで学んだことを組み合わせたスケッチを描いてみましょう。

int x = 0;//変数の宣言
int y = 0;//変数の宣言
int d = 40;//変数の宣言

void setup(){
  size(128,128);
}

void draw(){
  background(0);
  x=mouseX;
  y=mouseY;
  println("x:"+x);
  println("y:"+y);
  noStroke(); // 線を消す
  fill(x+y,0,0);//塗りの色
  ellipse(width/4,height/4,d,d);
  fill(0,x+y,0);
  ellipse(width/2,height/2,d,d);
  fill(0,0,x+y);
  ellipse(width*0.75,height*0.75,d,d);
}

上の例ではカラーモードがRGBの場合、各色が256色であるのを利用してウィンドウサイズを256の半分の128ピクセルとし、マウスのx座標とy座標の値の変化が円の色の変化に反映されるようにしています。

練習課題08-03:変数を使い、x座標とy座標の変化を利用したグラフィックス表現をスケッチで描く。