yoppa.org


多摩美 - “iTamabi” – iPhoneアプリ開発プロジェクト 2010

openFrameworks for iPhone:時計をつくる

今日の内容

  • iPhoneで時計をつくってみる
  • openFrameworksで、現在の時刻の取得は簡単に実現可能
  • あとは、その数値を使って、いろいろな表現を試す

時刻の取得

  • openFrameworksでは、現在の時間、分、秒を取得する関数が用意されている
  • だたし、この時間はiPhone (シミュレータの場合はMac) の時計を参照しているので、常に正確とは限らない
  • 時刻を取得する関数
    • ofGetHours(); – 「時」を取得 (0〜24)
    • ofGetMinutes(); – 「分」を取得 (0〜60)
    • ofGetSeconds(); – 「秒」を取得 (0〜60)

サンプル1:時刻を表示する

  • まずは簡単に、取得した時刻を文字で表示してみる

testApp.mm

#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){	
	ofRegisterTouchEvents(this);
	ofxAccelerometer.setup();
	ofxiPhoneAlerts.addListener(this);
	ofBackground(0,0,0);
}

//--------------------------------------------------------------
void testApp::update(){
    
}

//--------------------------------------------------------------
void testApp::draw(){
    //秒の取得
    int s = ofGetSeconds();
    //分の取得
    int m = ofGetMinutes();
    //時の取得
    int h = ofGetHours();
    
    //文字で表示する
    ofSetColor(255, 255, 255);
    string time = ofToString(h, 0) + ":" + ofToString(m, 0) + ":" + ofToString(s, 0);
    ofDrawBitmapString(time, 10, 20);
}

//--------------------------------------------------------------
void testApp::exit(){

}

//--------------------------------------------------------------
void testApp::touchDown(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchUp(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchDoubleTap(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::lostFocus(){

}

//--------------------------------------------------------------
void testApp::gotFocus(){

}

//--------------------------------------------------------------
void testApp::gotMemoryWarning(){

}

//--------------------------------------------------------------
void testApp::deviceOrientationChanged(int newOrientation){

}

サンプル2:デジタル時計

  • フォントを読み込んで、きれいな文字で表示
  • 時、分、秒ともに、値が10以下の時は、左に0を追加して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);
  ofTrueTypeFont verdana;

};

testApp.mm

#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){	
	ofRegisterTouchEvents(this);
	ofxAccelerometer.setup();
	ofxiPhoneAlerts.addListener(this);
	ofBackground(0,0,0);
    //フォントを読み込み
    verdana.loadFont("verdana.ttf",36, true, true);
}

//--------------------------------------------------------------
void testApp::update(){
    
}

//--------------------------------------------------------------
void testApp::draw(){
    string s, m, h;
    ofSetColor(255, 255, 255);
    
    //秒を読み込み、10以下の場合には左に0づめで2桁に
    if (ofGetSeconds()<10) {
        s = "0"+ofToString(ofGetSeconds(), 0);
    } else {
        s = ofToString(ofGetSeconds(), 0);
    }
    //分を読み込み、10以下の場合には左に0づめで2桁に
    if (ofGetMinutes()<10) {
        m = "0"+ofToString(ofGetMinutes(), 0);
    } else {
        m = ofToString(ofGetMinutes(), 0);
    }
    //時を読み込み、10以下の場合には左に0づめで2桁に
    if (ofGetHours()<10) {
        h = "0"+ofToString(ofGetHours(), 0);
    } else {
        h = ofToString(ofGetHours(), 0);
    }
    
    //読み込んだフォントで、時刻を表示
    string time = h + ":" + m + ":" + s;
    verdana.drawString(time, 50, ofGetHeight()/2);
}

//--------------------------------------------------------------
void testApp::exit(){

}

//--------------------------------------------------------------
void testApp::touchDown(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchUp(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchDoubleTap(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::lostFocus(){

}

//--------------------------------------------------------------
void testApp::gotFocus(){

}

//--------------------------------------------------------------
void testApp::gotMemoryWarning(){

}

//--------------------------------------------------------------
void testApp::deviceOrientationChanged(int newOrientation){

}

サンプル3:アナログ時計(簡易版)

  • 取得した時刻から、アナログ時計を作成する
  • 時針、分針、秒針のそれぞれの角度を求める
  • 時針:12時間で360°変化する。1時間あたりの変化は、360 / 12 = 30°
    • 時刻から時針の角度を求める
    • 現在の時刻(時) x 30
  • 分針:60分で360°変化する。1時間あたりの変化は、360 / 60 = 6°
    • 時刻から分針の角度を求める
    • 現在の時刻(分) x 6
  • 秒針:60秒で360°変化する。1時間あたりの変化は、360 / 60 = 6°
    • 時刻から秒針の角度を求める
    • 現在の時刻(秒) x 6

testApp.mm

#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){	
	ofRegisterTouchEvents(this);
	ofxAccelerometer.setup();
	ofxiPhoneAlerts.addListener(this);
	ofBackground(0, 0, 0);
    ofEnableSmoothing();
}

//--------------------------------------------------------------
void testApp::update(){
    
}

//--------------------------------------------------------------
void testApp::draw(){
    //時刻を取得
    int s = ofGetSeconds();
    int m = ofGetMinutes();
    int h = ofGetHours()%12;
    
    //時計の大きさを設定
    float clockSize = ofGetWidth()/2 - 20;
    
    //背景に円を描く
    ofSetColor(255, 255, 255);
    ofNoFill();
    ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
    ofSetLineWidth(3);
    ofSetCircleResolution(64);
    ofCircle(0, 0, clockSize);
   
    //秒針
    ofPushMatrix();
    ofRotateZ(s*6.0);
    ofSetLineWidth(1);
    ofLine(0, 0, 0, -clockSize);
    ofPopMatrix();
    
    //分
    ofPushMatrix();
    ofRotateZ(m*6.0);
    ofSetLineWidth(2);
    ofLine(0, 0, 0, -clockSize);
    ofPopMatrix();
    
    //時針
    ofPushMatrix();
    ofRotateZ(h*30.0);
    ofSetLineWidth(4);
    ofLine(0, 0, 0, -clockSize*0.75);
    ofPopMatrix();
}


//--------------------------------------------------------------
void testApp::exit(){

}

//--------------------------------------------------------------
void testApp::touchDown(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchUp(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchDoubleTap(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::lostFocus(){

}

//--------------------------------------------------------------
void testApp::gotFocus(){

}

//--------------------------------------------------------------
void testApp::gotMemoryWarning(){

}

//--------------------------------------------------------------
void testApp::deviceOrientationChanged(int newOrientation){

}

サンプル4:アナログ時計(完成版)

  • 作成したプログラムの表示と実際のアナログ時計と比べてみる
  • なにか違いはないだろうか?
    • 分が切り替わった瞬間の動き
    • 時間が切り替わった瞬間の動き
  • 実際の時計
    • 時針、分針も常にゆっくりと動いている
    • 時刻が変化した瞬間に動くのではなく、ゆっくりと移動して、気がつくと角度が変化している
  • 実際の分針
    • 秒の影響を受けている
    • 毎秒あたり、1/60の影響 (1分 = 60秒なので)
    • m = m + (s/60);
  • 実際の時針
    • 分の影響を受けている
    • 毎分あたり、1/60の影響 (1時間 = 60分なので)
    • h = h + (m/60);
  • 分針と時針の補正をしたアナログ時計に修正する
  • 文字盤を追加
    • 角度を変更しながら、一定間隔に目盛を刻んでいく
    • 小さな目盛:6度づつ
    • 大きな目盛:30度づつ

testApp.mm

#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){	
	ofRegisterTouchEvents(this);
	ofxAccelerometer.setup();
	ofxiPhoneAlerts.addListener(this);
	ofBackground(0, 0, 0);
    ofEnableSmoothing();
}

//--------------------------------------------------------------
void testApp::update(){
    
}

//--------------------------------------------------------------
void testApp::draw(){
    //時刻を取得
    //秒を取得
    float s = ofGetSeconds();
    //秒の影響を加えた、分の算出
    float m = ofGetMinutes() + (s/60.0);
    //分の影響を加えた、時の算出
    float h = ofGetHours()%12 + (m/60);
    
    //時計の大きさ
    float clockSize = ofGetWidth()/2 - 20;
    
    //座標全体を中心に移動
    ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
    
    //時計の背景
    ofSetColor(127,127,127);
    ofFill();
    
    //分の目盛を描く
    for (int i=0; i<60; i++) {
        ofRotateZ(6);
        ofCircle(clockSize, 0, 2);
    }
    
    //時の目盛を描く
    for (int i=0; i<12; i++) {
        ofRotateZ(30);
        ofCircle(clockSize, 0, 4);
    }
    
    ofSetColor(255, 255, 255);
    ofNoFill();
    
    //秒針
    ofPushMatrix();
    ofRotateZ(s*6.0);
    ofSetLineWidth(1);
    ofLine(0, 0, 0, -clockSize);
    ofPopMatrix();
    
    //分
    ofPushMatrix();
    ofRotateZ(m*6.0);
    ofSetLineWidth(2);
    ofLine(0, 0, 0, -clockSize);
    ofPopMatrix();
    
    //時針
    ofPushMatrix();
    ofRotateZ(h*30.0);
    ofSetLineWidth(4);
    ofLine(0, 0, 0, -clockSize*0.75);
    ofPopMatrix();
}


//--------------------------------------------------------------
void testApp::exit(){

}

//--------------------------------------------------------------
void testApp::touchDown(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchUp(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchDoubleTap(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::lostFocus(){

}

//--------------------------------------------------------------
void testApp::gotFocus(){

}

//--------------------------------------------------------------
void testApp::gotMemoryWarning(){

}

//--------------------------------------------------------------
void testApp::deviceOrientationChanged(int newOrientation){

}

サンプル5:大きさによる時間の表現

  • 時刻の数値をより自由な発想で使用してみる
  • 時、分、秒、ミリ秒の値で半径を変化させながら、円を描いてみる
  • 大きさによる時計

testApp.mm

#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){	
	ofRegisterTouchEvents(this);
	ofxAccelerometer.setup();
	ofxiPhoneAlerts.addListener(this);
	ofBackground(0, 0, 0);
    ofEnableSmoothing();
}

//--------------------------------------------------------------
void testApp::update(){
    
}

//--------------------------------------------------------------
void testApp::draw(){
    //時刻を取得
    int ms = ofGetElapsedTimeMillis() % 1000;
    int s = ofGetSeconds();
    int m = ofGetMinutes();
    int h = ofGetHours();
    
    //円の最大の大きさを設定
    float circleSize = ofGetHeight()/8;
    
    ofSetColor(127, 127, 127);    
    //ミリ秒
    ofCircle(ofGetWidth()/2, ofGetHeight()/8*7, ms/1000.0*circleSize);
    //秒
    ofCircle(ofGetWidth()/2, ofGetHeight()/8*5, s/60.0*circleSize);
    //分
    ofCircle(ofGetWidth()/2, ofGetHeight()/8*3, m/60.0*circleSize);
    //時
    ofCircle(ofGetWidth()/2, ofGetHeight()/8, h/24.0*circleSize);}


//--------------------------------------------------------------
void testApp::exit(){
    
}

//--------------------------------------------------------------
void testApp::touchDown(ofTouchEventArgs &touch){
    
}

//--------------------------------------------------------------
void testApp::touchMoved(ofTouchEventArgs &touch){
    
}

//--------------------------------------------------------------
void testApp::touchUp(ofTouchEventArgs &touch){
    
}

//--------------------------------------------------------------
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
    
}

//--------------------------------------------------------------
void testApp::lostFocus(){
    
}

//--------------------------------------------------------------
void testApp::gotFocus(){
    
}

//--------------------------------------------------------------
void testApp::gotMemoryWarning(){
    
}

//--------------------------------------------------------------
void testApp::deviceOrientationChanged(int newOrientation){
    
}

サンプル6:位置による時間の表現

  • 時、分、秒、ミリ秒の値で位置を変化させながら、直線を引いてみる

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);
    
  ofTrueTypeFont	verdana;
};

testApp.mm

#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){	
  ofRegisterTouchEvents(this);
  ofxAccelerometer.setup();
  ofxiPhoneAlerts.addListener(this);
  ofBackground(0, 0, 0);
  ofEnableSmoothing();
  ofSetBackgroundAuto(false);
  ofEnableAlphaBlending();
    
  verdana.loadFont("verdana.ttf",12, false, true);
}

//--------------------------------------------------------------
void testApp::update(){
    
}

//--------------------------------------------------------------
void testApp::draw(){
  //背景
  ofSetColor(0, 0, 0, 15);
  ofRect(0, 0, ofGetWidth(), ofGetHeight());
    
  //時刻を取得
  int ms = ofGetElapsedTimeMillis() % 1000;
  int s = ofGetSeconds();
  int m = ofGetMinutes();
  int h = ofGetHours();
    
  //枠
  ofSetColor(63, 63, 63);
  ofSetLineWidth(1);
  ofLine(0, ofGetHeight()/4, ofGetWidth(), ofGetHeight()/4);
  ofLine(0, ofGetHeight()/2, ofGetWidth(), ofGetHeight()/2);
  ofLine(0, ofGetHeight()/4*3, ofGetWidth(), ofGetHeight()/4*3);
    
  //線の位置で時間を表現
  ofSetColor(255, 255, 255);
  ofSetLineWidth(3);
  //ミリ秒
  verdana.drawString(ofToString(ms, 0), ms/1000.0*ofGetWidth()+4, ofGetHeight()/8+6);
  ofLine(ms/1000.0*ofGetWidth(), 0, ms/1000.0*ofGetWidth(), ofGetHeight()/4);
  //秒
  verdana.drawString(ofToString(s, 0), s/60.0*ofGetWidth()+4, ofGetHeight()/8*3+6);
  ofLine(s/60.0*ofGetWidth(), ofGetHeight()/4, s/60.0*ofGetWidth(), ofGetHeight()/2);
  //分
  verdana.drawString(ofToString(m, 0), m/60.0*ofGetWidth()+4, ofGetHeight()/8*5+6);
  ofLine(m/60.0*ofGetWidth(), ofGetHeight()/2, m/60.0*ofGetWidth(), ofGetHeight()/4*3);
  //時
  verdana.drawString(ofToString(h, 0), h/24.0*ofGetWidth()+4, ofGetHeight()/8*7+6);
  ofLine(h/24.0*ofGetWidth(), ofGetHeight()/4*3, h/24.0*ofGetWidth(), ofGetHeight());
}

//--------------------------------------------------------------
void testApp::exit(){

}

//--------------------------------------------------------------
void testApp::touchDown(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchUp(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::touchDoubleTap(ofTouchEventArgs &touch){

}

//--------------------------------------------------------------
void testApp::lostFocus(){

}

//--------------------------------------------------------------
void testApp::gotFocus(){

}

//--------------------------------------------------------------
void testApp::gotMemoryWarning(){

}

//--------------------------------------------------------------
void testApp::deviceOrientationChanged(int newOrientation){

}

サンプルファイルのダウンロード

今日とりあげた全てのサンプルは、下記よりダウンロードすることができます。