146
デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる 2013年10月5日 田所 淳

デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Embed Size (px)

Citation preview

Page 1: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

デジタルアートセミナー#2openFrameworksで学ぶ、クリエイティブ・コーディングSession 2: 構造をつくる

2013年10月5日田所 淳

Page 2: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

このセッションの内容‣ openFrameworksのプログラムの基礎

‣ 今後基礎体力をつけていきます!

‣ 乱数(ランダム)‣ 配列とくりかえし‣ 条件分岐‣ ベクトルを使用した運動の表現‣ 大量の物体を動かす

Page 3: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

このセッションの内容‣ ただ、プログラミングを書き写すだけではつまらない…‣ クイズ形式で進めてみます!

Page 4: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

準備‣ まずは、復習‣ 新規プロジェクトの生成 - ProjectGeneratorの使い方

Page 5: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q1: 乱数について

Page 6: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q1: 乱数について‣ ランダム(規則性のない)場所に、静止した円を描きなさい‣ プログラムを実行するたびに、違う場所に描かれるように

‣ ヒント:‣ 円を描く - ofCircle(x, y, radius);‣ ランダムな数を生成 - ofRandom(min, max);

Page 7: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "testApp.h"

void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32);}

void testApp::update(){}

void testApp::draw(){ // ランダムな場所に半径40pxの円を描く ofCircle(ofRandom(ofGetWidth()), ofRandom(ofGetHeight()), 40);}

... 後略

Q1: 乱数について‣ よくある間違い - testApp.cpp‣ どうなるか、実験してみる

Page 8: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q1: 解答

Page 9: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q1: 乱数について - 解答‣ setup() であらかじめランダムな座標を生成しておく‣ 生成した座標は、グローバルな変数に格納 (testApp.hに)‣ その変数の値を参照して、draw() で円を描く

Page 10: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once

#include "ofMain.h"

class testApp : public ofBaseApp{ public: void setup(); void update(); void draw();

... // 円の位置 float posX; float posY; };

Q1: 乱数について - 解答‣ testApp.h

Page 11: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "testApp.h"

void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所を指定 posX = ofRandom(ofGetWidth()); posY = ofRandom(ofGetHeight());}

...

void testApp::draw(){ // 設定した場所に円を描く ofSetHexColor(0x3399cc); ofCircle(posX, posY, 20);}

...

Q1: 乱数について - 解答‣ testApp.cpp

Page 12: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q1: 乱数について - 解答‣ 実行するたびに、ランダムな場所に円が描かれる

Page 13: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q2: たくさんの図形をランダムな場所に描く

Page 14: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q2: たくさんの図形をランダムな場所に描く‣ 100個の静止した円をランダムな場所に描く‣ 半径は40pxで統一

Page 15: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q2: たくさんの図形をランダムな場所に描く‣ ヒント 1: 配列 - たくさんの値を保存する‣ 例えば、100個のposXを保存するための「箱」は以下のようにしたら準備できる

‣ この箱には、[] で囲まれた部分に連番でナンバリングされる

‣ この仕組みで、100個の、posXとposYが確保できる

float posX[100];

posX[0] posX[1]posX[2]...posX[99]

← 0から開始する

← 0~99までで100個ぶん

Page 16: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q2: たくさんの図形をランダムな場所に描く‣ ヒント 2: くりかえし ‣ for文を使用する‣ 例えば、0~99の100回くりかえす構文

‣ カウンタ変数 i を賢く利用する

for (int i = 0; i < 100; i++) { 《処理の内容》}

for (int i = 0; i < 100; i++) { posX[i] = ????; posY[i] = ????;}

Page 17: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q2: 解答

Page 18: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once

#include "ofMain.h"

class testApp : public ofBaseApp{ public: void setup(); void update(); void draw(); ... // 位置の配列を生成 float posX[100]; float posY[100];};

Q2: 解答‣ testApp.h

Page 19: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "testApp.h"

void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所を円の数だけ指定 for (int i = 0; i < 100; i++) { posX[i] = ofRandom(ofGetWidth()); posY[i] = ofRandom(ofGetHeight()); }}

...

void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < 100; i++) { ofCircle(posX[i], posY[i], 20); }}

Q2: 解答‣ testApp.cpp

Page 20: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q2: 解答‣ 100個の円が、ランダムな場所に描かれる

Page 21: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q2: 解答‣ 参考: ‣ 数を変更したい場合、いろいろ修正箇所あり‣ 1箇所だけを変更すると、数がすぐに変更できるようにしたい!‣ testApp.hに、クラスの定数(const)として数を指定する‣ 正式には、静的メンバ変数による定数

‣ クラスの定数は、以下のような書式になる

‣ 例: 定数「CIRCLE_NUM」を100と定義

static const int 変数名 = 値;

static const int CIRCLE_NUM = 100;

Page 22: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once

#include "ofMain.h"

class testApp : public ofBaseApp{ public: void setup(); void update(); void draw();

...

// 描画する円の数を指定 static const int CIRCLE_NUM = 100; // 位置の配列を生成 float posX[CIRCLE_NUM]; float posY[CIRCLE_NUM];};

Q2: 解答‣ 定数で数を定義バージョン: testApp.h

Page 23: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "testApp.h"

void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { posX[i] = ofRandom(ofGetWidth()); posY[i] = ofRandom(ofGetHeight()); }}

...

void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(posX[i], posY[i], 20); }}

Q2: 解答‣ 定数で数を定義バージョン: testApp.cpp

Page 24: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q2: 解答‣ 例: 円の数を、100 → 400個に

Page 25: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q3: たくさんの図形をアニメーション

Page 26: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q3: たくさんの図形をアニメーション‣ 次に表示するプログラムを改造して、100個の円が同時に動きまわるアニメーションにする

‣ 開始位置と、円の移動速度と方向はランダムに

Page 27: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once

#include "ofMain.h"

class testApp : public ofBaseApp{ public: void setup(); void update(); void draw();... // 位置 float positionX; float positionY; // 速度 float velocityX; float velocityY;};

Q3: たくさんの図形をアニメーション‣ ヒントプログラム: testApp.h

Page 28: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "testApp.h"void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // ランダムな場所と速度を指定 positionX = ofRandom(ofGetWidth()); positionY = ofRandom(ofGetHeight()); velocityX = ofRandom(-10, 10); velocityY = ofRandom(-10, 10);}void testApp::update(){ // 円の座標を更新 positionX += velocityX; positionY += velocityY; // 画面からはみ出ないように if (positionX < 0 || positionX > ofGetWidth()) { velocityX *= -1; } if (positionY < 0 || positionY > ofGetHeight()) { velocityY *= -1; }}

Q3: たくさんの図形をアニメーション‣ ヒントプログラム: testApp.cpp

Page 29: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

void testApp::draw(){ ofSetHexColor(0x3399cc); // 円を描画 ofCircle(positionX, positionY, 20);}

Q3: たくさんの図形をアニメーション‣ ヒントプログラム: testApp.cpp

Page 30: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q3: たくさんの図形をアニメーション‣ ヒント: 位置と速度をそれぞれ配列にする‣ 定数を定義して、数はすぐに変更できるように

‣ static const int CIRCLE_NUM ‣ positionX[CIRCLE_NUM]‣ positionY[CIRCLE_NUM]‣ velocity X[CIRCLE_NUM]‣ velocityY[CIRCLE_NUM]

‣ 最初の位置と速度、座標の変更、描画、すべての処理をくりかえして100回行う → for文

Page 31: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q3: 解答

Page 32: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once

#include "ofMain.h"

class testApp : public ofBaseApp{ public:... // 描画する円の数を指定 static const int CIRCLE_NUM = 100; // 位置の配列を生成 float posX[CIRCLE_NUM]; float posY[CIRCLE_NUM]; // 速度の配列を生成 float speedX[CIRCLE_NUM]; float speedY[CIRCLE_NUM];};

Q3: 解答‣ testApp.h

Page 33: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "testApp.h"

void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所と速度を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { posX[i] = ofRandom(ofGetWidth()); posY[i] = ofRandom(ofGetHeight()); speedX[i] = ofRandom(-10, 10); speedY[i] = ofRandom(-10, 10); }}

void testApp::update(){ // 円の座標を全て更新 for (int i = 0; i < CIRCLE_NUM; i++) { posX[i] += speedX[i]; posY[i] += speedY[i];

Q3: 解答‣ testApp.cpp

Page 34: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

// 画面からはみ出たらバウンドさせる if (posX[i] < 0 || posX[i] > ofGetWidth()) { speedX[i] *= -1; } if (posY[i] < 0 || posY[i] > ofGetHeight()) { speedY[i] *= -1; } }}

//--------------------------------------------------------------void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(posX[i], posY[i], 20); }}

...

Q3: 解答‣ testApp.cpp

Page 35: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q3: 解答‣ 100個の円が、同時に動く(はず!)

Page 36: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

ベクトルによる運動の表現

Page 37: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

ベクトルによる運動の表現‣ ここまでの、(x, y)座標それぞれに変数を用意する方法‣ ビギナー的表現

‣ より運動を表現するための高度な書式をマスターしたい‣ 「ベクトル (Vector)」を理解する!

Page 38: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

ベクトルによる運動の表現‣ ベクトル = 幾何学的空間における、大きさと向きを持った量

Page 39: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

ベクトルによる運動の表現‣ 例: 原点(0,0)から(2,3)の座標までのベクトル

‣ このベクトルは、OA = (2,3) と記述される→

Page 40: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

ベクトルによる運動の表現‣ ベクトルは、足し算することができる‣ 例: a = (-2,3) と b = (4,2) の2つのベクトルを足す‣ a + b = (-2+4,3+2) = (2,5)

Page 41: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

ベクトルによる運動の表現‣ ベクトルは、引き算も可能‣ 例: a = (-2, 3) , b = (4, 2)‣ a - b = (-2-4,3-2) = (-6,1)

Page 42: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

ベクトルによる運動の表現‣ 位置ベクトル‣ いままで扱ってきた2次元平面の座標 (x, y) は、原点 (0, 0) を始点としたベクトルと捉えることができる → 位置ベクトル

Page 43: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

ベクトルによる運動の表現‣ 速度ベクトル‣ 「速度 (velocity)」とは、単位時間あたりの物体の移動の変位‣ 日常的な「速さ (speed)」と「速度 (velocity)」を区分する‣ 1フレームごとの座標の変化 = 向きと大きさをもった「速度ベクトル」

位置ベクトル a

位置ベクトル b速度ベクトル

Page 44: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

ベクトルによる運動の表現‣ openFrameworksで、ベクトルを表現‣ 2次元のベクトルは「ofVec2f」を使用する

‣ 例:位置ベクトルと速度ベクトルの宣言

‣ 「ベクトル名.x」「ベクトル名.y」: ベクトルの、x方向の成分と y方向の成分をとりだす

‣ 例:位置ベクトルの(x, y)座標を設定する‣

ofVec2f position; // 位置ベクトルpositionを宣言ofVec2f velocity; // 速度ベクトルvelocityを宣言

position.x = 100; // 位置ベクトルpositionのx成分を100にposition.y = 100; // 位置ベクトルpositionのx成分を50に

Page 45: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q4: ベクトルで運動を表現する

Page 46: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q4: ベクトルで運動を表現する‣ Q3 で作成した、たくさんの図形を動かすサンプルを、ベクトル(ofVec2f)で書き直してみる

‣ ヒント:100個ぶんの位置ベクトルと速度ベクトルは以下のように宣言される

// 描画する円の数を指定static const int CIRCLE_NUM = 100; // 位置ベクトルの配列ofVec2f position[CIRCLE_NUM]; // 速度ベクトルの配列ofVec2f velocity[CIRCLE_NUM];

Page 47: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q4: 解答

Page 48: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once

#include "ofMain.h"

class testApp : public ofBaseApp{ public:

... // 描画する円の数を指定 static const int CIRCLE_NUM = 100; // 位置ベクトルの配列 ofVec2f position[CIRCLE_NUM]; // 速度ベクトルの配列 ofVec2f velocity[CIRCLE_NUM];};

Q4: 解答‣ testApp.h

Page 49: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "testApp.h"void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所と速度を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { position[i].x = ofRandom(ofGetWidth()); position[i].y = ofRandom(ofGetHeight()); velocity[i].x = ofRandom(-10, 10); velocity[i].y = ofRandom(-10, 10); }}void testApp::update(){ // 円の座標を全て更新 for (int i = 0; i < CIRCLE_NUM; i++) { position[i] += velocity[i];

// 画面からはみ出たらバウンドさせる if (position[i].x < 0 || position[i].x > ofGetWidth()) { velocity[i].x *= -1; }

Q4: 解答‣ testApp.cpp

Page 50: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

if (position[i].y < 0 || position[i].y > ofGetHeight()) { velocity[i].y *= -1; } }}

void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(position[i], 20); }}

Q4: 解答‣ testApp.cpp

Page 51: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

Q4: 解答‣ おなじ運動が、とてもすっきりと記述できた!!

Page 52: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現摩擦力

Page 53: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ 摩擦力 (Friction) を表現してみる‣ 摩擦力 = その物体の進行方向逆向きに働く力

速度ベクトル

摩擦力

Page 54: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ 摩擦力を加えた運動の計算アルゴリズム

円の位置と初期速度を設定

力をリセット

摩擦力を加味した力を更新

力から速度を計算、座標を更新

画面からはみ出ていないかチェック

Page 55: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ プログラムの可読性を高める工夫‣ 処理のかたまりを「関数 (function) 」としてまとめる

Page 56: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ 関数 (function)‣ 引数 (ひきすう, argument) - 関数に渡す値 (入力)‣ 返り値 (return value) - 関数が返す値 (出力)

関数

引数1 引数2 引数3

戻り値

Page 57: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ C++での関数の書き方

‣ 例えば、int型の数の二乗を計算する関数

‣ もし戻り値がない関数の場合、戻り値の型は「void」にする

戻り値の型 名前空間::関数名(引数1, 引数2, 引数3...){ 関数の処理の内容}

int testApp::poweroftwo(int a){! return a * a;}

Page 58: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ 先程の処理の流れを以下の関数として定義

void setInit();

void resetForce();

void updateForce();

void updatePos();

void checkBounds();

Page 59: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once

#include "ofMain.h"

class testApp : public ofBaseApp{ public:

...

void setInit(); // 初期設定 void resetForce(); // 力をリセット void updateForce(); // 力を更新 void updatePos(); // 位置の更新 void checkBounds(); // 画面からはみ出たらバウンドさせる static const int CIRCLE_NUM = 100; // 描画する円の数を指定 ofVec2f position[CIRCLE_NUM]; // 位置ベクトルの配列 ofVec2f velocity[CIRCLE_NUM]; // 速度ベクトルの配列 ofVec2f force[CIRCLE_NUM]; // 力ベクトルの配列 float friction = 0.01; // 摩擦係数};

応用: さらにリアルな運動の表現‣ testApp.h

Page 60: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

...void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); setInit(); // 円を初期化}

void testApp::update(){ resetForce(); // 力をリセット updateForce(); // 力の更新 (摩擦) updatePos(); // 円の座標を全て更新 checkBounds(); // 画面からはみ出たらバウンドさせる}

void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(position[i], 20); }}

応用: さらにリアルな運動の表現‣ testApp.cpp

Page 61: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

void testApp::setInit(){ // 画面内のランダムな場所と速度を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { position[i].x = ofGetWidth()/2; position[i].y = ofGetHeight()/2; velocity[i].set(ofRandom(-30, 30), ofRandom(-30, 30)); force[i].set(0, 0); }}

void testApp::resetForce(){ // 力をリセット for (int i = 0; i < CIRCLE_NUM; i++) { force[i].set(0, 0); }}

void testApp::updateForce(){ // 力の更新 (摩擦) for (int i = 0; i < CIRCLE_NUM; i++) { force[i] = force[i] - velocity[i] * friction; }}

応用: さらにリアルな運動の表現‣ testApp.cpp

Page 62: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

void testApp::updatePos(){ // 円の座標を全て更新 for (int i = 0; i < CIRCLE_NUM; i++) { velocity[i] += force[i]; position[i] += velocity[i]; }}

void testApp::checkBounds(){ // 画面からはみ出たらバウンドさせる for (int i = 0; i < CIRCLE_NUM; i++) { if (position[i].x < 0 || position[i].x > ofGetWidth()) { velocity[i].x *= -1; } if (position[i].y < 0 || position[i].y > ofGetHeight()) { velocity[i].y *= -1; } }}

応用: さらにリアルな運動の表現‣ testApp.cpp

Page 63: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ 動きの勢いが、徐々に摩擦で減速していく

Page 64: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現重力

Page 65: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ 重力 (Gravity) を表現してみる‣ つねに下にむかって、一定の力をかけ続ける

摩擦力

重力

Page 66: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once

#include "ofMain.h"

class testApp : public ofBaseApp{ public:

... void setInit(); // 初期設定 void resetForce(); // 力をリセット void addForce(ofVec2f force); // 力を加える void updateForce(); // 力を更新 void updatePos(); // 位置の更新 // 画面からはみ出たらバウンドさせる void checkBounds(float xmin, float ymin, float xmax, float ymax); // 位置を枠内に収める void constrain(float xmin, float ymin, float xmax, float ymax); // 描画する円の数を指定 static const int CIRCLE_NUM = 100;

応用: さらにリアルな運動の表現‣ testApp.h

Page 67: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

// 位置ベクトルの配列 ofVec2f position[CIRCLE_NUM]; // 速度ベクトルの配列 ofVec2f velocity[CIRCLE_NUM]; // 力ベクトルの配列 ofVec2f force[CIRCLE_NUM]; // 摩擦係数 float friction = 0.01;}

応用: さらにリアルな運動の表現‣ testApp.h

Page 68: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "testApp.h"

void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); setInit(); // 円を初期化}

void testApp::update(){ resetForce(); // 力をリセット addForce(ofVec2f(0, 0.5)); // 重力を加える updateForce(); // 力の更新 (摩擦) updatePos(); // 円の座標を全て更新 // 画面からはみ出たらバウンドさせる checkBounds(0, 0, ofGetWidth(), ofGetHeight()); // 枠内に収める constrain(0, 0, ofGetWidth(), ofGetHeight());}

応用: さらにリアルな運動の表現‣ testApp.cpp

Page 69: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(position[i], 20); }}

void testApp::setInit(){ // 画面内のランダムな場所と速度を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { position[i].x = ofGetWidth()/2; position[i].y = ofGetHeight()/2; velocity[i].set(ofRandom(-30, 30), ofRandom(-30, 30)); force[i].set(0, 0); }}

void testApp::resetForce(){ // 力をリセット for (int i = 0; i < CIRCLE_NUM; i++) { force[i].set(0, 0); }}

応用: さらにリアルな運動の表現‣ testApp.cpp

Page 70: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

void testApp::addForce(ofVec2f _force){ // 力を加える for (int i = 0; i < CIRCLE_NUM; i++) { force[i] += _force; }}

void testApp::updateForce(){ // 力の更新 (摩擦) for (int i = 0; i < CIRCLE_NUM; i++) { force[i] = force[i] - velocity[i] * friction; }}

void testApp::updatePos(){ // 円の座標を全て更新 for (int i = 0; i < CIRCLE_NUM; i++) { velocity[i] += force[i]; position[i] += velocity[i]; }}

応用: さらにリアルな運動の表現‣ testApp.cpp

Page 71: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

void testApp::constrain(float xmin, float ymin, float xmax, float ymax){ // 枠内に収める for (int i = 0; i < CIRCLE_NUM; i++) { if (position[i].x < xmin) { position[i].x = xmin; } if (position[i].y < ymin) { position[i].y = ymin; } if (position[i].x > xmax) { position[i].x = xmax; } if (position[i].y > ymax) { position[i].y = ymax; } }}

void testApp::checkBounds(float xmin, float ymin, float xmax, float ymax){ // 画面からはみ出たらバウンドさせる for (int i = 0; i < CIRCLE_NUM; i++) { if (position[i].x < xmin || position[i].x > xmax) { velocity[i].x *= -1; }

応用: さらにリアルな運動の表現‣ testApp.cpp

Page 72: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

if (position[i].y < ymin || position[i].y > ymax) { velocity[i].y *= -1; } }}

応用: さらにリアルな運動の表現‣ testApp.cpp

Page 73: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ リアルな運動が再現される

Page 74: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

応用: さらにリアルな運動の表現‣ 数を大量に増やしてみる!

Page 75: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOoF = Object Oriented + openFrameworks

Page 76: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ オブジェクト指向プログラミング

‣ Object Oriented Programming (OOP)‣ オブジェクト指向でProcessingのプログラムを作る‣ そもそもオブジェクト指向とは?

‣ 簡単なプログラムを、オブジェクト指向で書いてみる‣ クラスの定義‣ クラスの呼びだし

オブジェクト指向プログラミングとは?

Page 77: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ オブジェクト指向プログラミング言語のイメージ

プログラミング・パラダイムの変遷

オブジェクト

オブジェクト

オブジェクト

オブジェクト

Page 78: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ OOPの特徴

‣ 相互にメッセージを送り合う「オブジェクト」の集まりとしてプログラムを構成

‣ オブジェクトは、プロパティとメソッドから構成される‣ カプセル化 - 必要のない情報は隠す‣ インヘリタンス(継承) - あるオブジェクトが他のオブジェクトの特性を引き継ぐ

‣ ポリモーフィズム(多態性・多様性) - プログラミング言語の各要素が複数の型に属することを許す

オブジェクト指向プログラミングの概念

Page 79: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ オブジェクト‣ プロパティとメソッド‣ カプセル化‣ 継承 (インヘリタンス)‣ 多態性、多相性 (ポリモーフィズム)

OOP、5つのポイント

Page 80: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ オブジェクト指向プログラムのポイント:その1‣ オブジェクトの集まりとしてプログラムを構成‣ オブジェクト同士がメッセージを送りあう

OOP:ポイントその1

Page 81: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ オブジェクト指向プログラムのポイント:その2‣ オブジェクトは、プロパティ(性質、状態)と、メソッド(動作、ふるまい) から構成される

状態1状態2状態3

オブジェクト

メソッド1 メソッド2

メソッド3メソッド4

OOP:ポイントその2

Page 82: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ 例:「りんご」をオブジェクトとして考える

赤5.0甘い

ふじ

実がなる

成長する

落ちる腐る

青4.0

すっぱい

青リンゴ実がなる

成長する

落ちる腐る

OOP:ポイントその2

Page 83: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ オブジェクト指向プログラムのポイント:その3‣ 必要のない情報は隠す (カプセル化)‣ プログラムの実装全てを知る必要はない‣ 必要なインターフェイス(接点)だけ見せて、あとは隠す

It’s this resemblance to real things that gives objects much of their power and appeal. They can notonly model components of real systems, but equally as well fulfill assigned roles as components insoftware systems.

Interface and Implementation

To invent programs, you need to be able to capture abstractions and express them in the programdesign. It’s the job of a programming language to help you do this. The language should facilitate theprocess of invention and design by letting you encode abstractions that reveal the way things work.It should let you make your ideas concrete in the code you write. Surface details shouldn’t obscurethe architecture of your program.

All programming languages provide devices that help express abstractions. In essence, these devicesare ways of grouping implementation details, hiding them, and giving them, at least to some extent,a common interface—much as a mechanical object separates its interface from its implementation, asillustrated in “Interface and Implementation” .

Figure 2-1 Inte rfa ce a nd Im ple m e nta tion

910

11

87 6

implementationinterface

Looking at such a unit from the inside, as the implementor, you’d be concerned with what it’scomposed of and how it works. Looking at it from the outside, as the user, you’re concerned onlywith what it is and what it does. You can look past the details and think solely in terms of the rolethat the unit plays at a higher level.

The principal units of abstraction in the C language are structures and functions . Both, in differentways, hide elements of the implementation:

� On the data side of the world, C structures group data elements into larger units which can thenbe handled as single entities. While some code must delve inside the structure and manipulatethe fields separately, much of the program can regard it as a single thing—not as a collection ofelements, but as what those elements taken together represent. One structure can include others,so a complex arrangement of information can be built from simpler layers.

14 Inte rfa ce a nd Im ple m e nta tion2007-12-11 | © 2007 Apple Inc. All Rights Reserved.

C H A P T E R 2

O bje ct-O rie nte d P rogra m m ing

インターフェイス 実装

OOP:ポイントその3

Page 84: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ オブジェクト指向プログラムのポイント:その4‣ インヘリタンス(継承)‣ オブジェクトから新たなオブジェクトを派生させる

植物

生物

動物

果物 穀物

りんご

ふじ 紅玉 デリシャス

バナナ マンゴー

OOP:ポイントその4

Page 85: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ オブジェクト指向プログラムのポイント:その5‣ ポリモーイズム(多態性、多様性)‣ オブジェクトはメッセージを受け取りそれに応じた処理を行う‣ メッセージの処理方法は、オブジェクト自身が知っていて、その処理はオブジェクトによって異なる

getName()

オブジェクトA:人間

「田所 淳」

getName()

オブジェクトB:車

「トヨタカローラ」

OOP:ポイントその5

Page 86: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ クラス‣ クラスとは:オブジェクトの「型紙」‣ クラスをインスタンス化 (実体化) することでインスタンス(オブジェクト)となる

色重さ(g)味

リンゴ(クラス)

実がなる

成長する

落ちる腐る

赤5.0甘い

ふじ(インスタンスオブジェクト)

実がなる

成長する

落ちる腐る

青4.0

すっぱい

青リンゴ(インスタンスオブジェクト)

実がなる

成長する

落ちる腐る

インスタンス化

クラス

Page 87: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ いままで扱ってきた、testApp も一つのクラス‣ メソッド - setup(), update(), draw() ...etc.‣ プロパティ - testApp全体で使用する変数

testAppもクラス

クラス変数

setup() update()

draw()exit()

testApp

Page 88: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ これまでのようにtestAppにどんどん機能を追加すると、様々な弊害が

‣ 可読性の低下、機能ごとに再利用できない、拡張が困難 ..etc.

testApp単体の限界

testApp testApp肥大化

Page 89: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

‣ 機能ごとにオブジェクトを分けてプロジェクトを構成する‣ オブジェクトが相互に連携

testApp単体の限界

testApp

Rectangle

Particle

ControlPanel

Page 90: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編クラスを作る

Page 91: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編 - クラスを作る‣ まずはシンプルなサンプルを発展させる

‣ 1つのパーティクル(粒)を描く‣ 同じプログラムをOOPで書き直してみる

Page 92: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編 - クラスを作る‣ ランダムな場所に、1つ静止したパーティクルを描く‣ https://gist.github.com/tado/6709701

Page 93: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "testApp.h"

void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所を指定 position.x = ofRandom(ofGetWidth()); position.y = ofRandom(ofGetHeight());}

...

void testApp::draw(){ // 設定した場所に円を描く ofSetHexColor(0x3399cc); ofCircle(position, 10);}

OOP実践編 - クラスを作る‣ testApp.cpp - コード抜粋

Page 94: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編 - クラスを作る‣ このプログラムをクラス化してみる

‣ クラス名:Particle

‣ プロパティ (状態、変数):‣ ofVec2f position : 初期位置

‣ メソッド (ふるまい、関数):‣ draw( ) : パーティクルを描く

Page 95: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編 - クラスを作る‣ こんな風に図示します (UMLクラス図)

Particle

+ position:ofVec2f

+ draw():void

←クラス名

←プロパティ

←メソッド

Page 96: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編 - クラスを作る‣ 次にXcodeを操作して、プロジェクトにクラスのためのファイルを追加します!

Page 97: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編 - クラスを作る‣ ファイルのリストの「src」フォルダを右クリック‣ リストから「New File (新規ファイル)」を選択

Page 98: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編 - クラスを作る‣ Mac OS X > C and C++ > C++ File を選択

Page 99: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編 - クラスを作る‣ 「Particle」という名前で「src」フォルダに保存

Page 100: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

OOP実践編 - クラスを作る‣ ファイルリストは以下のようになるはず‣ あとは、それぞれのファイルにコーディングしていく

Page 101: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの記述

Page 102: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの記述‣ まずはヘッダーファイル (Particle.h) から‣ レシピの材料と手順の一覧!

‣ 材料 → 状態、性質 → つまり、プロパティ(変数)‣ 手順 → ふるまい、動作 → つまり、メソッド(関数)

‣ そのクラスのプロパティとメソッドを記述‣ 外部から参照するものは、public: 以下に書く

Page 103: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once#include "ofMain.h"

class Particle {

public: void draw(); ofVec2f position;};

クラスの記述‣ Particle.h‣ https://gist.github.com/tado/6710045

Page 104: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once#include "ofMain.h"

class Particle {

public: void draw(); ofVec2f position;};

クラスの記述‣ Particle.h‣ https://gist.github.com/tado/6710045

インクルードガードBuildの際に複数回読みこまれないためのしくみ

Page 105: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once#include "ofMain.h"

class Particle {

public: void draw(); ofVec2f position;};

クラスの記述‣ Particle.h‣ https://gist.github.com/tado/6710045

oFの機能を使うためのライブラリを必ず読み込む

Page 106: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once#include "ofMain.h"

class Particle {

public: void draw(); ofVec2f position;};

クラスの記述‣ Particle.h‣ https://gist.github.com/tado/6710045

クラス名

Page 107: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once#include "ofMain.h"

class Particle {

public: void draw(); ofVec2f position;};

クラスの記述‣ Particle.h‣ https://gist.github.com/tado/6710045

public: 以下は外部に公開される

Page 108: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once#include "ofMain.h"

class Particle {

public: void draw(); ofVec2f position;};

クラスの記述‣ Particle.h‣ https://gist.github.com/tado/6710045

メソッド:draw() - 円を描く

Page 109: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once#include "ofMain.h"

class Particle {

public: void draw(); ofVec2f position;};

クラスの記述‣ Particle.h‣ https://gist.github.com/tado/6710045

プロパティ:position - 初期位置

Page 110: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#pragma once#include "ofMain.h"

class Particle {

public: void draw(); ofVec2f position;};

クラスの記述‣ Particle.h‣ https://gist.github.com/tado/6710045#file-oneparticleclass01-particle-h

最後に必ずセミコロンをつける

Page 111: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの記述‣ つぎに実装ファイル(Particle.cpp)を書く‣ 円を描くための全ての手続きを記述していく

‣ 現在は、draw() 関数のみ

Page 112: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "Particle.h"

void Particle::draw(){ ofSetHexColor(0x3399cc); ofCircle(position, 10);}

クラスの記述‣ Particle.cpp‣ https://gist.github.com/tado/6710045#file-oneparticleclass01-particle-cpp

Page 113: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "Particle.h"

void Particle::draw(){ ofSetHexColor(0x3399cc); ofCircle(position, 10);}

クラスの記述‣ Particle.cpp‣ https://gist.github.com/tado/6710045#file-oneparticleclass01-particle-cpp

必ずヘッダーファイルを読み込む

Page 114: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "Particle.h"

void Particle::draw(){ ofSetHexColor(0x3399cc); ofCircle(position, 10);}

クラスの記述‣ Particle.cpp‣ https://gist.github.com/tado/6710045#file-oneparticleclass01-particle-cpp

戻り値 クラス名::関数名(引数)クラス名を名前空間として使用している他のクラスのdraw()関数との混同を避けている

Page 115: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

#include "Particle.h"

void Particle::draw(){ ofSetHexColor(0x3399cc); ofCircle(position, 10);}

クラスの記述‣ Particle.cpp‣ https://gist.github.com/tado/6710045#file-oneparticleclass01-particle-cpp

円を描画

Page 116: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの記述‣ 最後に作成したクラスを、testAppから呼び出します‣ ヘッダーファイル testApp.h で MoveCircle を宣言

‣ これだけで、クラスが実体化(インスタンス化)される‣ クラス名:Particle‣ インスタンス:particle

‣ testApp.h‣ https://gist.github.com/tado/6710045#file-oneparticleclass01-testapp-h

Particle particle;

Page 117: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの記述‣ メインの実装ファイル、testApp.cpp で作成したインスタンスを使用して円を描かせる

‣ https://gist.github.com/tado/6710045#file-oneparticleclass01-testapp-cpp

‣ testApp::setup( ) で円の初期位置を指定

‣ testApp::draw( ) でParticleのdraw( )メソッドを呼びだし

particle.position.x = ofRandom(ofGetWidth());particle.position.y = ofRandom(ofGetHeight());

particle.draw();

Page 118: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの記述‣ 完成!!

Page 119: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの配列

Page 120: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの配列‣ 1つのクラスから、大量のオブジェクト(インスタンス)を生成することも可能

‣ クラスの配列を定義する‣ 「クラス = 工場」「オブジェクト = 車」というイメージ

‣ 例えば、100個のParticleクラスのオブジェクト‣static const int NUM = 100;Particle particle[NUM];

Page 121: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの配列‣ クラスの配列(Array)のイメージ

particle[0]

particle[1]

particle[2]...

Particle particle[NUM]

NUM個

particle[NUM]

Page 122: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの配列‣ あとは for文を使用して反復して処理していく

‣ testApp::setup() で初期化

‣ testApp::draw() で描画‣

for(int i = 0; i < NUM; i++){ float posX = ofRandom(ofGetWidth()); float posY = ofRandom(ofGetHeight()); particle[i].setup(ofVec2f(posX, posY));}

for(int i = 0; i < NUM; i++){ particle[i].draw();}

Page 123: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの配列‣ 先程のパーティクル1粒表示のプログラムを改造して、100粒のパーティクルを表示させてみる

‣ Particleクラスはそのまま

‣ testApp.h‣ https://gist.github.com/tado/6710857#file-particlearray-testapp-h

‣ testApp.cpp‣ https://gist.github.com/tado/6710857#file-particlearray-testapp-cpp

Page 124: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

クラスの配列‣ 完成 !!

Page 125: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクルシステムを作る - 1重力と摩擦力の表現

Page 126: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクルシステムを作る!‣ いよいよ、パーティクルを動かしてみましょう!‣ 先週のアルゴリズムを全て実装していく

void setInit();

void resetForce();

void updateForce();

void updatePos();

void checkBounds();

Page 127: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクルシステムを作る!‣ UMLクラス図で表現

Particle

+ position:ofVec2f+ velocity:ofVec2f+ force:ofVec2f+ friction:float+ radius:float

+ setup(ofVec2f position, ofVec2f velocity):void+ resetForce():void+ addForce(ofVec2f force):void+ updateForce():void+ updatePos():void+ checkBounds(float xmin, float ymin, float xmax, float ymax):void+ draw():void

Page 128: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクルシステムを作る!‣ 汎用的に使えるParticleクラス

‣ コードはGithub参照‣ https://gist.github.com/tado/6711018

Page 129: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクルシステムを作る!‣ 汎用Particleクラスの使用例:その1‣ 重力の影響を受けながら、摩擦抵抗のある空間を跳ねまわるパーティクル

‣ マウスクリックで、その場所で大量生成される‣ 先週最後に作成したサンプルのクラス版

摩擦力

重力

Page 131: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクルシステムを作る!‣ 完成!!

Page 132: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクルシステムを作る - 2vector (動的配列) の活用

Page 133: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

vector (動的配列) の活用‣ Particleクラス、さらに応用

‣ 次のようなインタラクションを実現したい:‣ マウスをドラッグしている間、パーティクルがマウスの場所から生成され続ける

‣ 生成されたパーティクルは、そのまま画面に残る‣ キーボードで「c」のキーを押すとクリア

‣ Particleの配列は、いくつ確保すれば良いのか?‣ 1000? 10000? 1000000?‣ 無限大のArrayを作成することはできない…

Page 134: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

vector (動的配列) の活用‣ Arrayの数が確定しない

particle[0]

particle[1]

particle[2]...

Particle particle[NUM]

NUM個

particle[NUM]

→ 不明

→ 不明

→ 不明

Page 135: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

vector (動的配列) の活用‣ 配列の上限の数がわからない場合‣ Array (静的配列) ではなく、要素数を自由に変更できる動的な配列を使用すると便利

‣ C++ では 「vector」 が比較的扱いやすい

‣ 「vector<型の種類> 配列名」となる‣ 例: Particleクラスの動的配列、particleを宣言

vector<Particle> particle;

Page 136: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

vector (動的配列) の活用‣ vector (動的配列) のイメージ

particle[0]

particle[1]

particle[2]...

vector<Particle> particle

数は可変

Page 137: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

vector (動的配列) の活用‣ Vectorの配列要素の操作

‣ 配列の末尾に要素を追加 → push_back()‣ 例:Particleのオブジェクトpを、particleに追加

‣ 配列の末尾に要素を削除 → pop_back()

‣ 配列の全ての要素をクリア → clear()

particle.push_back(p);

particle.clear();

particle.pop_back();

Page 139: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

vector (動的配列) の活用‣ 完成!!

Page 140: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクルシステムを作る - 3パーティクル表現の応用

Page 141: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクル表現の応用‣ さらに様々な表現の応用をしてみる‣ 例えば、それぞれのパーティクルを直接描画するのではなく、パーティクルの場所に画像を置いてみる

‣ こんな画像

Page 143: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクル表現の応用‣ 画像による美しいパーティクル!!

Page 144: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクル表現の応用‣ さらに、応用‣ それぞれのパーティクルを、曲線で結んでみる

‣ 曲線を描くには‣ ofBeginShape()‣ ofCurveVertex() ...頂点の数だけ繰り返し‣ ofEndShape()

Page 146: デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる

パーティクル表現の応用‣ 曲線で接続されたパーティクル!