多摩美 - “iTamabi” – iPhoneアプリ開発プロジェクト 2010
openFrameworks for iPhone:お絵描きアプリを作る
今日の内容
- ドロー(お絵描き)アプリをつくる
- 簡単なサンプルから徐々に複雑なサンプルへと進めていきます
ドロー系アプリのサンプル
- FatTag Deluxe Katsu Edition! http://fffff.at/fattag-deluxe-katsu-edition
- いろいろな写真を背景にタギング(落書き)することができる
- スプレーで描いた際のインクの垂れなどをリアルに再現
ドローアプリを作る
ステップ1:タッチした軌跡に円を描く
- touchDownとtouchMoveした際のX座標とY座標を取得
- 取得した座標の場所に円を描いていく
- 円の連なりで線を描いていく
testApp.h
#pragma once #include "ofMain.h" #include "ofxiPhone.h" #include "ofxiPhoneExtras.h" class testApp : public ofxiPhoneApp { public: void setup(); void update(); void draw(); void exit(); void touchDown(ofTouchEventArgs &touch); void touchMoved(ofTouchEventArgs &touch); void touchUp(ofTouchEventArgs &touch); void touchDoubleTap(ofTouchEventArgs &touch); void lostFocus(); void gotFocus(); void gotMemoryWarning(); void deviceOrientationChanged(int newOrientation); ofPoint touchLoc; //画面をタッチしている場所 bool drawing; //ドロー中かどうか };
testApp.mm
#include "testApp.h" //-------------------------------------------------------------- void testApp::setup(){ //iPhone基本設定 ofRegisterTouchEvents(this); ofxAccelerometer.setup(); ofxiPhoneAlerts.addListener(this); //横位置で起動 iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT); //画面の基本設定 ofBackground(255, 255, 255); ofSetBackgroundAuto(false); drawing = false; } //-------------------------------------------------------------- void testApp::update(){ } //-------------------------------------------------------------- void testApp::draw(){ //もし現在ドロー中だったら if (drawing) { //色を黒に ofSetColor(0, 0, 0); //タッチしている場所に円を描く ofCircle(touchLoc.x, touchLoc.y, 10); } } //-------------------------------------------------------------- void testApp::exit(){ } //-------------------------------------------------------------- void testApp::touchDown(ofTouchEventArgs &touch){ //ドロー中に drawing = true; //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; } //-------------------------------------------------------------- void testApp::touchMoved(ofTouchEventArgs &touch){ //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; } //-------------------------------------------------------------- void testApp::touchUp(ofTouchEventArgs &touch){ //ドローを終了 drawing = false; } //-------------------------------------------------------------- void testApp::touchDoubleTap(ofTouchEventArgs &touch){ } //-------------------------------------------------------------- void testApp::lostFocus(){ } //-------------------------------------------------------------- void testApp::gotFocus(){ } //-------------------------------------------------------------- void testApp::gotMemoryWarning(){ } //-------------------------------------------------------------- void testApp::deviceOrientationChanged(int newOrientation){ }
ステップ2:線で描く
- ひとつ前のタッチした座標を記録しておく
- ひとつ前のタッチした座標と現在の座標を線で結ぶ
testApp.h
#pragma once #include "ofMain.h" #include "ofxiPhone.h" #include "ofxiPhoneExtras.h" class testApp : public ofxiPhoneApp { public: void setup(); void update(); void draw(); void exit(); void touchDown(ofTouchEventArgs &touch); void touchMoved(ofTouchEventArgs &touch); void touchUp(ofTouchEventArgs &touch); void touchDoubleTap(ofTouchEventArgs &touch); void lostFocus(); void gotFocus(); void gotMemoryWarning(); void deviceOrientationChanged(int newOrientation); ofPoint touchLoc; //現在タッチしている場所 ofPoint lastTouchLoc; //ひとつ前のタッチしている場所 bool drawing; //ドロー中かどうか };
testApp.mm
#include "testApp.h" //-------------------------------------------------------------- void testApp::setup(){ //iPhone基本設定 ofRegisterTouchEvents(this); ofxAccelerometer.setup(); ofxiPhoneAlerts.addListener(this); //横位置で起動 iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT); //画面基本設定 ofSetBackgroundAuto(false); ofBackground(255, 255, 255); ofSetLineWidth(3); ofEnableSmoothing(); drawing = false; } //-------------------------------------------------------------- void testApp::update(){ } //-------------------------------------------------------------- void testApp::draw(){ //もしドロー中だったら if (drawing) { ofSetColor(0, 0, 0); //ひとつ前のタッチした座標から現在の座標まで線を描く ofLine(lastTouchLoc.x, lastTouchLoc.y, touchLoc.x, touchLoc.y); } } //-------------------------------------------------------------- void testApp::exit(){ } //-------------------------------------------------------------- void testApp::touchDown(ofTouchEventArgs &touch){ //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; } //-------------------------------------------------------------- void testApp::touchMoved(ofTouchEventArgs &touch){ //ドロー中に drawing = true; //ひとつ前の座標を記録 lastTouchLoc = touchLoc; //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; } //-------------------------------------------------------------- void testApp::touchUp(ofTouchEventArgs &touch){ //ドローを終了 drawing = false; } //-------------------------------------------------------------- void testApp::touchDoubleTap(ofTouchEventArgs &touch){ ofSetColor(255, 255, 255); ofRect(0, 0, ofGetWidth(), ofGetHeight()); } //-------------------------------------------------------------- void testApp::lostFocus(){ } //-------------------------------------------------------------- void testApp::gotFocus(){ } //-------------------------------------------------------------- void testApp::gotMemoryWarning(){ } //-------------------------------------------------------------- void testApp::deviceOrientationChanged(int newOrientation){ }
ステップ3:線の太さを変化させる
- 前のタッチした座標から、現在の座標までの移動した距離を測定
- 移動した距離に応じて線の太さを変化させる
- 移動距離が長いときは細い線で
- 移動距離が短いときには太い線で
- 筆で書いたような効果
testApp.h
#pragma once #include "ofMain.h" #include "ofxiPhone.h" #include "ofxiPhoneExtras.h" class testApp : public ofxiPhoneApp { public: void setup(); void update(); void draw(); void exit(); void touchDown(ofTouchEventArgs &touch); void touchMoved(ofTouchEventArgs &touch); void touchUp(ofTouchEventArgs &touch); void touchDoubleTap(ofTouchEventArgs &touch); void lostFocus(); void gotFocus(); void gotMemoryWarning(); void deviceOrientationChanged(int newOrientation); ofPoint touchLoc; //現在タッチしている場所 ofPoint lastTouchLoc; //ひとつ前のタッチしている場所 bool drawing; //ドロー中かどうか };
testApp.mm
#include "testApp.h" //-------------------------------------------------------------- void testApp::setup(){ //iPhone基本設定 ofRegisterTouchEvents(this); ofxAccelerometer.setup(); ofxiPhoneAlerts.addListener(this); //横位置で起動 iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT); //画面基本設定 ofSetBackgroundAuto(false); ofBackground(255, 255, 255); ofEnableSmoothing(); drawing = false; } //-------------------------------------------------------------- void testApp::update(){ } //-------------------------------------------------------------- void testApp::draw(){ //ドロー中だったら if (drawing) { //前のタッチした座標と現在の座標の距離を算出 float dist = ofDist(lastTouchLoc.x, lastTouchLoc.y, touchLoc.x, touchLoc.y); //線の太さを決定 float lineWidth = 14 - dist * 0.5; //4ピクセルよりは細くならないように if (lineWidth < 4) { lineWidth = 4; } ofSetColor(0, 0, 0); //算出した太さで円を描く ofCircle(touchLoc.x, touchLoc.y, lineWidth); } } //-------------------------------------------------------------- void testApp::exit(){ } //-------------------------------------------------------------- void testApp::touchDown(ofTouchEventArgs &touch){ //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; } //-------------------------------------------------------------- void testApp::touchMoved(ofTouchEventArgs &touch){ //ドロー中に drawing = true; //ひとつ前の座標を記録 lastTouchLoc = touchLoc; //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; } //-------------------------------------------------------------- void testApp::touchUp(ofTouchEventArgs &touch){ //ドローを終了 drawing = false; } //-------------------------------------------------------------- void testApp::touchDoubleTap(ofTouchEventArgs &touch){ //ダブルタップで画面をリセット drawing = false; ofSetColor(255, 255, 255); ofRect(0, 0, ofGetWidth(), ofGetHeight()); } //-------------------------------------------------------------- void testApp::lostFocus(){ } //-------------------------------------------------------------- void testApp::gotFocus(){ } //-------------------------------------------------------------- void testApp::gotMemoryWarning(){ } //-------------------------------------------------------------- void testApp::deviceOrientationChanged(int newOrientation){ }
ステップ4:よりなめらかな線に
- 線が細くなった際に、線が切れぎれになってしまう問題に対処
- 座標を一気に移動するのではなく、補完していくことで、なめらかな線にしている
testApp.h
#pragma once #include "ofMain.h" #include "ofxiPhone.h" #include "ofxiPhoneExtras.h" class testApp : public ofxiPhoneApp { public: void setup(); void update(); void draw(); void exit(); void touchDown(ofTouchEventArgs &touch); void touchMoved(ofTouchEventArgs &touch); void touchUp(ofTouchEventArgs &touch); void touchDoubleTap(ofTouchEventArgs &touch); void lostFocus(); void gotFocus(); void gotMemoryWarning(); void deviceOrientationChanged(int newOrientation); ofPoint touchLoc; //現在タッチしている場所 ofPoint lastTouchLoc; //ひとつ前のタッチしている場所 bool drawing; //ドロー中かどうか float interpolate; //補完の割合 };
testApp.mm
#include "testApp.h" //-------------------------------------------------------------- void testApp::setup(){ //iPhone基本設定 ofRegisterTouchEvents(this); ofxAccelerometer.setup(); ofxiPhoneAlerts.addListener(this); //横位置で起動 iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT); //画面基本設定 ofSetBackgroundAuto(false); ofBackground(255, 255, 255); ofEnableSmoothing(); drawing = false; //補完の割合を設定 interpolate = 0.2; } //-------------------------------------------------------------- void testApp::update(){ } //-------------------------------------------------------------- void testApp::draw(){ if (drawing) { //前のタッチした座標と現在の座標の距離を算出 float dist = ofDist(lastTouchLoc.x, lastTouchLoc.y, touchLoc.x, touchLoc.y); //線の太さを決定 float lineWidth = 16 - dist * 0.2; //6ピクセルよりは細くならないように if (lineWidth < 6) { lineWidth = 6; } ofSetColor(0, 0, 0); //座標を一定の割合で補完している lastTouchLoc += (touchLoc - lastTouchLoc) * interpolate; //円を描く ofFill(); ofCircle(lastTouchLoc.x, lastTouchLoc.y, lineWidth); ofNoFill(); ofCircle(lastTouchLoc.x, lastTouchLoc.y, lineWidth); } } //-------------------------------------------------------------- void testApp::exit(){ } //-------------------------------------------------------------- void testApp::touchDown(ofTouchEventArgs &touch){ //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; //ひとつ前の座標を記録 lastTouchLoc = touchLoc; } //-------------------------------------------------------------- void testApp::touchMoved(ofTouchEventArgs &touch){ //ドロー中に drawing = true; //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; } //-------------------------------------------------------------- void testApp::touchUp(ofTouchEventArgs &touch){ //ドローを終了 drawing = false; } //-------------------------------------------------------------- void testApp::touchDoubleTap(ofTouchEventArgs &touch){ //ダブルタップで画面をリセット drawing = false; ofSetColor(255, 255, 255); ofRect(0, 0, ofGetWidth(), ofGetHeight()); } //-------------------------------------------------------------- void testApp::lostFocus(){ } //-------------------------------------------------------------- void testApp::gotFocus(){ } //-------------------------------------------------------------- void testApp::gotMemoryWarning(){ } //-------------------------------------------------------------- void testApp::deviceOrientationChanged(int newOrientation){ }
ステップ5:文字で描く
- フォントを読みこんで、文字によって線を描く
testApp.h
#pragma once #include "ofMain.h" #include "ofxiPhone.h" #include "ofxiPhoneExtras.h" class testApp : public ofxiPhoneApp { public: void setup(); void update(); void draw(); void exit(); void touchDown(ofTouchEventArgs &touch); void touchMoved(ofTouchEventArgs &touch); void touchUp(ofTouchEventArgs &touch); void touchDoubleTap(ofTouchEventArgs &touch); void lostFocus(); void gotFocus(); void gotMemoryWarning(); void deviceOrientationChanged(int newOrientation); ofPoint touchLoc; ofPoint lastTouchLoc; float interpolate; bool drawing; ofTrueTypeFont myFont; string letters; float size; int counter; };
testApp.mm
#include "testApp.h" //-------------------------------------------------------------- void testApp::setup(){ //iPhone基本設定 ofRegisterTouchEvents(this); ofxAccelerometer.setup(); ofxiPhoneAlerts.addListener(this); //横位置で起動 iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT); //画面基本設定 ofSetBackgroundAuto(false); ofBackground(255, 255, 255); ofEnableSmoothing(); drawing = false; //表示する文字列を設定 letters = "hello iphone!!"; counter = 0; interpolate = 0.2; } //-------------------------------------------------------------- void testApp::update(){ } //-------------------------------------------------------------- void testApp::draw(){ //文字で線を描く float dist = ofDist(lastTouchLoc.x, lastTouchLoc.y, touchLoc.x, touchLoc.y); float fontSize = dist; if (fontSize < 12) { fontSize = 12; } myFont.loadFont("Georgia.ttf", dist); ofSetColor(0, 0, 0); string newLetter = letters.substr(counter, 1); size = myFont.stringWidth(newLetter); if (dist > size) { float angle = atan2(touchLoc.x - lastTouchLoc.x, lastTouchLoc.y - touchLoc.y); ofPushMatrix(); ofTranslate(touchLoc.x, touchLoc.y); ofRotateZ(angle * 180.0 / PI - 90); myFont.drawString(newLetter, 0, 0); ofPopMatrix(); counter++; if (counter > letters.size()) { counter = 0; } lastTouchLoc = touchLoc; } } //-------------------------------------------------------------- void testApp::exit(){ } //-------------------------------------------------------------- void testApp::touchDown(ofTouchEventArgs &touch){ //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; //ひとつ前の座標を記録 lastTouchLoc = touchLoc; } //-------------------------------------------------------------- void testApp::touchMoved(ofTouchEventArgs &touch){ //ドロー中に drawing = true; //タッチしている場所を記録 touchLoc.x = touch.x; touchLoc.y = touch.y; } //-------------------------------------------------------------- void testApp::touchUp(ofTouchEventArgs &touch){ //ドローを終了 drawing = false; } //-------------------------------------------------------------- void testApp::touchDoubleTap(ofTouchEventArgs &touch){ //ダブルタップで画面をリセット drawing = false; ofSetColor(255, 255, 255); ofRect(0, 0, ofGetWidth(), ofGetHeight()); } //-------------------------------------------------------------- void testApp::lostFocus(){ } //-------------------------------------------------------------- void testApp::gotFocus(){ } //-------------------------------------------------------------- void testApp::gotMemoryWarning(){ } //-------------------------------------------------------------- void testApp::deviceOrientationChanged(int newOrientation){ }
サンプルファイルのダウンロード
今回の授業で紹介したプログラムのソースコードは以下からダウンロードしてください。