多摩美 - “iTamabi” – iPhoneアプリ開発プロジェクト 2010
openFrameworks for iPhone:お絵描きアプリを作る
今日の内容
- ドロー(お絵描き)アプリをつくる
- 簡単なサンプルから徐々に複雑なサンプルへと進めていきます
ドロー系アプリのサンプル
- FatTag Deluxe Katsu Edition! http://fffff.at/fattag-deluxe-katsu-edition
- いろいろな写真を背景にタギング(落書き)することができる
- スプレーで描いた際のインクの垂れなどをリアルに再現
ドローアプリを作る
ステップ1:タッチした軌跡に円を描く
- touchDownとtouchMoveした際のX座標とY座標を取得
- 取得した座標の場所に円を描いていく
- 円の連なりで線を描いていく
testApp.h
[code language=”cpp”]
#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; //ドロー中かどうか
};
[/code]
testApp.mm
[code language=”cpp”]
#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){
}
[/code]
ステップ2:線で描く
- ひとつ前のタッチした座標を記録しておく
- ひとつ前のタッチした座標と現在の座標を線で結ぶ
testApp.h
[code language=”cpp”]
#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; //ドロー中かどうか
};
[/code]
testApp.mm
[code language=”cpp”]
#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){
}
[/code]
ステップ3:線の太さを変化させる
- 前のタッチした座標から、現在の座標までの移動した距離を測定
- 移動した距離に応じて線の太さを変化させる
- 移動距離が長いときは細い線で
- 移動距離が短いときには太い線で
- 筆で書いたような効果
testApp.h
[code language=”cpp”]
#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; //ドロー中かどうか
};
[/code]
testApp.mm
[code language=”cpp”]
#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){
}
[/code]
ステップ4:よりなめらかな線に
- 線が細くなった際に、線が切れぎれになってしまう問題に対処
- 座標を一気に移動するのではなく、補完していくことで、なめらかな線にしている
testApp.h
[code language=”cpp”]
#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; //補完の割合
};
[/code]
testApp.mm
[code language=”cpp”]
#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){
}
[/code]
ステップ5:文字で描く
- フォントを読みこんで、文字によって線を描く
testApp.h
[code language=”cpp”]
#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;
};
[/code]
testApp.mm
[code language=”cpp”]
#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){
}
[/code]
サンプルファイルのダウンロード
今回の授業で紹介したプログラムのソースコードは以下からダウンロードしてください。