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
[code language=”cpp”]
#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){

}
[/code]

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

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

};
[/code]

testApp.mm
[code language=”cpp”]
#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){

}
[/code]

サンプル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
[code language=”cpp”]
#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){

}
[/code]

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

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

testApp.mm
[code language=”cpp”]
#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){

}
[/code]

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

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

testApp.mm
[code language=”cpp”]
#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){

}
[/code]

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

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

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);

ofTrueTypeFont verdana;
};
[/code]

testApp.mm
[code language=”cpp”]
#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){

}
[/code]

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

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