Contenu connexe
Similaire à メディア・アートII 第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション
Similaire à メディア・アートII 第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション (20)
Plus de Atsushi Tadokoro (20)
メディア・アートII 第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション
- 7. #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
‣ どうなるか、実験してみる
- 9. Q1: 乱数について - 解答
‣ setup() であらかじめランダムな座標を生成しておく
‣ 生成した座標は、グローバルな変数に格納 (testApp.hに)
‣ その変数の値を参照して、draw() で円を描く
- 11. #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
- 15. Q2: たくさんの図形をランダムな場所に描く
‣ ヒント 1: 配列 - たくさんの値を保存する
‣ 例えば、100個のposXを保存するための「箱」は以下のように
したら準備できる
‣ この箱には、[] で囲まれた部分に連番でナンバリングされる
‣ この仕組みで、100個の、posXとposYが確保できる
float posX[100];
posX[0]
posX[1]
posX[2]
...
posX[99]
← 0から開始する
← 0∼99までで100個ぶん
- 16. 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] = ????;
}
- 18. #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
- 19. #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
- 21. Q2: 解答
‣ 参考:
‣ 数を変更したい場合、いろいろ修正箇所あり
‣ 1箇所だけを変更すると、数がすぐに変更できるようにしたい!
‣ testApp.hに、クラスの定数(const)として数を指定する
‣ 正式には、静的メンバ変数による定数
‣ クラスの定数は、以下のような書式になる
‣ 例: 定数「CIRCLE_NUM」を100と定義
static const int 変数名 = 値;
static const int CIRCLE_NUM = 100;
- 22. #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
- 23. #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
- 27. #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
- 28. #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
- 30. Q3: たくさんの図形をアニメーション
‣ ヒント: 位置と速度をそれぞれ配列にする
‣ 定数を定義して、数はすぐに変更できるように
‣ static const int CIRCLE_NUM
‣ positionX[CIRCLE_NUM]
‣ positionY[CIRCLE_NUM]
‣ velocity X[CIRCLE_NUM]
‣ velocityY[CIRCLE_NUM]
‣ 最初の位置と速度、座標の変更、描画、すべての処理をくりか
えして100回行う → for文
- 32. #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
- 33. #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
- 34. // 画面からはみ出たらバウンドさせる
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
- 43. ベクトルによる運動の表現
‣ 速度ベクトル
‣ 「速度 (velocity)」とは、単位時間あたりの物体の移動の変位
‣ 日常的な「速さ (speed)」と「速度 (velocity)」を区分する
‣ 1フレームごとの座標の変化 = 向きと大きさをもった「速度ベ
クトル」
位置ベクトル a
位置ベクトル b
速度ベクトル
- 44. ベクトルによる運動の表現
‣ 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に
- 46. Q4: ベクトルで運動を表現する
‣ Q3 で作成した、たくさんの図形を動かすサンプルを、ベクト
ル(ofVec2f)で書き直してみる
‣ ヒント:100個ぶんの位置ベクトルと速度ベクトルは以下のよ
うに宣言される
// 描画する円の数を指定
static const int CIRCLE_NUM = 100;
// 位置ベクトルの配列
ofVec2f position[CIRCLE_NUM];
// 速度ベクトルの配列
ofVec2f velocity[CIRCLE_NUM];
- 48. #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
- 49. #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
- 50. 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
- 56. 応用: さらにリアルな運動の表現
‣ 関数 (function)
‣ 引数 (ひきすう, argument) - 関数に渡す値 (入力)
‣ 返り値 (return value) - 関数が返す値 (出力)
関数
引数1 引数2 引数3
戻り値
- 57. 応用: さらにリアルな運動の表現
‣ C++での関数の書き方
‣ 例えば、int型の数の二乗を計算する関数
‣ もし戻り値がない関数の場合、戻り値の型は「void」にする
戻り値の型 名前空間::関数名(引数1, 引数2, 引数3...){
関数の処理の内容
}
int testApp::poweroftwo(int a){
! return a * a;
}
- 59. #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
- 61. 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
- 62. 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
- 66. #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
- 68. #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
- 69. 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
- 70. 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
- 71. 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
- 72. if (position[i].y < ymin || position[i].y > ymax) {
velocity[i].y *= -1;
}
}
}
応用: さらにリアルな運動の表現
‣ testApp.cpp