Simple openFrameworks application on iPhone Sample 1 (2009)

This is a tutorial in getting a very simple openFrameworks application running on iPhone with basic graphics, multitouch and accelerometer support (and one might say a simple particle system too!).

  • 10 Balls are moving around on screen and bouncing off the edges.
  • You can touch the screen with multiple fingers and drag the balls around (multitouch support)
  • You can tilt the iphone and the balls fall in that direction (accelerometer support).

…and all of this without touching a line of Objective C. It is actually one of the samples included in the ofxiPhone download – iPhone Touch+Accel Example. You can find it in the examples folder of the download, so if you load and run that project you can see the finished result. The code below is straight from that sample, warts and all 😛

If you are already familiar with openFrameworks, then you should be able to fly through this sample, as it looks just like a normal openFrameworks application, pure C++. If you are not familiar with openFrameworks, hopefully this article will be a quick introduction to that as well, but please check out wiki.openframeworks.cc andwww.openframeworks.cc/documentation. (The info on those pages are a bit old but are being updated this very minute). Prior knowledge of some basic C++ would be useful to follow (or at least Java, ActionScript 3.0 etc.)

Setup

You can download the current openFrameworks 006 + ofxiPhone prerelease (+ some other addons) package fromwww.openframeworks.cc/download. If you would like more information on what’s going behind the scenes and how it all works you can find some at www.memo.tv/ofxiphone.

testApp.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "ofMain.h"
#include "ofxMultiTouch.h"
#include "ofxAccelerometer.h"

class testApp : public ofSimpleApp, public ofxMultiTouchListener {

public:
void setup();
void update();
void draw();
void exit();

void keyPressed(int key) {}
void keyReleased(int key) {}
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased();
void mouseReleased(int x, int y, int button );

void touchDown(float x, float y, int touchId, ofxMultiTouchCustomData *data = NULL);
void touchMoved(float x, float y, int touchId, ofxMultiTouchCustomData *data = NULL);
void touchUp(float x, float y, int touchId, ofxMultiTouchCustomData *data = NULL);
void touchDoubleTap(float x, float y, int touchId, ofxMultiTouchCustomData *data = NULL);
};

This is our standard openFrameworks testApp header file. It looks just like a normal openFrameworks testApp header file with the following differences:

  • class testApp extends ofxMultiTouchListener as well as ofSimpleApp.
  • There are 4 new methods, touchDowntouchMovedtouchUptouchDoubleTap.

Actually both these changes are related. ofxMultiTouchListener is an abstract base class (meaning it doesn’t have any implementation, it only declares a bunch of method names – a bit like a Java Interface), and it declares the touchXXXXmethods.

If you’re not sure what that means, and don’t really care, it doesn’t really matter. All you really need to know, is that each of the above methods are called automatically by the system when the relevat event occurs:

  • setup() is called when the app is launched. Your app initialization code goes here
  • update() is called every frame. Your update code goes here
  • draw() is called every frame just after update(). Your drawing code goes here
  • exit() is called just before the app exits. Your cleanup /goodbye code goes here
  • keyPressed() and keyReleased are currently not called (though there is an addon coming to support that)
  • mouseXXXX methods are called for the first finger touch events – this is here for compatibility with code ported from desktop. you can use these or use…
  • touchXXXX methods are called for each of the touch events. Information passed is touch position (x,y coordinates), which finger (touchId), and custom information about the touch (currently the total number of touches there are, this will probably expand in the future).

All of the above will be explained a bit more in the next section, the important thing to take away from this section is, thatmost of your iPhone openFrameworks apps will have the same or very similar testApp.h.

testApp.cpp

There is a lot going on in this file. As well as all of the testApp event callbacks, there is also the definition of a Thing class. Normally I would define that in a separate file Thing.h and Thing.cpp, but for some reason I kept it in testApp.cpp, can’t remember why, but let’s go with it for now.

Initialization and Setup

First let’s define some constants for some behavior. We’ll get to what they do later.

1
2
3
4
#define NUM_POINTS 10
#define BOUNCE_FACTOR 0.5
#define ACCELEROMETER_FORCE 0.2
#define RADIUS 30

Next up (if we follow the sample code) is the Thing class definition, I’m gonna skip that for now and go straight to the testApp event callbacks.

Our initialization method, called automatically when the app starts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void testApp::setup(){
printf("setup()\n");

ofBackground(0, 0, 0); // set background to black
ofSetBackgroundAuto(true); // set background to clear automatically every frame
ofSetFrameRate(60); // set desired framerate to 60fps

// initialize the accelerometer
ofxAccelerometer.setup();

// touch events will be sent to this object (this instance of testApp)
ofxMultiTouch.addListener(this);

// initialize all of the Thing particles
for(int i=0; i<NUM_POINTS; i++) things[i].init();
}

This looks like a normal openFrameworks setup function. The only new commands are the ofxAccelerometer setup and ofxMultiTouch listener. You will almost always keep these lines like that unless:

  • you don’t want to use the accelerometer, in which case you simply don’t call ofxAccelerometer.setup(), or
  • if you want another object to receive the multitouch events instead of your instance of testApp. In which case, you can pass a pointer to that object to ofxMultiTouch.addListener(myObject). More on this later.

Update and Draw

Next up is the update function. This gets called automatically every frame by the openframeworks core. it just loops through all of the things particles and updates them.

1
2
3
4
void testApp::update(){
// printf("update()\n");
for(int i=0; i<NUM_POINTS; i++) things[i].update();
}

Just like the testApp::update() method, the testApp::draw() method gets called every frame (just after testApp::update()). it loops through all things particles and draws them.

1
2
3
4
void testApp::draw(){
// printf("draw()\n");
for(int i=0; i<NUM_POINTS; i++) things[i].draw();
}

Then there is the exit method. In this example this does nothing other than dumping ‘exit()’ to the console. Here you can place any cleanup code.

1
2
3
void testApp::exit() {
printf("exit()\n");
}

Touch event callbacks – handling multitouch

First let’s look at the mouse callbacks. These are optional on iPhone, they are simply there for compatibility with desktop systems. If you are developing solely for iPhone you can skip the mouse callbacks and just use the touch callbacks (or use mouse callbacks if you don’t need multitouch, up to you – but you’ll rarely need to use both).

1
2
3
4
5
void testApp::mouseMoved(int x, int y ) // this one never gets called
void testApp::mouseDragged(int x, int y, int button) // called when you drag the first finger
void testApp::mousePressed(int x, int y, int button) // called when you touch screen for first time
void testApp::mouseReleased() // called when you release the screen with your first finger
void testApp::mouseReleased(int x, int y, int button) // called when you release the screen with your first finger

The touch callbacks are very similar to the mouse callbacks, except you also get the touchID of the finger which causes the touch event. While the mouseXXX callbacks are only called for the first finger that touches the screen, the touchXXX calbacks are called for multiple fingers, with the number (id) of the finger (example further below).

1
2
3
4
5
6
7
8
9
10
11
12
13
void testApp::touchDown(float x, float y, int touchId, ofxMultiTouchCustomData *data) {
printf("touchDown: %f, %f %i\n", x, y, touchId);
things[touchId].moveTo(x, y);
}

void testApp::touchMoved(float x, float y, int touchId, ofxMultiTouchCustomData *data) {
printf("touchMoved: %f, %f %i\n", x, y, touchId);
things[touchId].moveTo(x, y);
}

void testApp::touchUp(float x, float y, int touchId, ofxMultiTouchCustomData *data) {
printf("touchUp: %f, %f %i\n", x, y, touchId);
}

If you put one finger down, touchDown() will be called with the coordinates (x, y) and touchId == 0 (note that touchId begins at 0 instead of 1). If you drag that finger, touchMoved() will be called with the new coordinates and again touchId ==0. If you then put another finger down touchDown() will be called with the coordinates (x,y) for the new finger and touchId == 1 (2nd finger). Putting down another finger will trigger touchDown() with coordinates and touchId == 2 (3rd finger). If you then move your second finger, touchMoved() will be called with coordinates of the finger that just moved and touchId == 1 (2nd finger). etc. Best to just open the console, move your fingers around and see what happens.

In our case all we are doing is moving a ball (a things[touchId]) to the new position when a finger is moved. To keep the code as simple as possible, I’m simply moving the i’th ball when a touch occurs. I.e. when you put your first finger down, it moves the first ball, second finger moves second ball, third finger moves third ball etc. However the first ball may not be the closest ball to your finger when you put it down. (if you run the app you’ll see what I mean). If you want the effect that you can ‘touch any ball and move that’, in your touchDown you can loop through all of the balls, check the distance of each to the finger touch position, and if it is within a specified distance, then thats the ball you want to move.

The final touch event is a double tap. In this case we just toggle fullscreen when you double tap. (On iPhone fullscreen is interpreted as hiding the status bar).

1
2
3
4
void testApp::touchDoubleTap(float x, float y, int touchId, ofxMultiTouchCustomData *data) {
printf("touchDoubleTap: %f, %f %i\n", x, y, touchId);
ofToggleFullscreen();
}

The Thing class – drawing and using the accelerometer

It probably would have been better if I’d called this class ‘Ball’, but when I started writing it, I wasn’t sure what i was gonna do with it, so called it Thing. This is a class to handle each instance of the moving Things on screen. Each Thing has apositionvelocitycolor, a method to initialize itself, a method to update itself, a method to draw itself and finally a method to move itself to a new position.

1
2
3
4
5
class Thing {
public:
ofPoint pos; // contains x and y position (and z, but we ignore that for now)
ofPoint vel; // contains x and y components of velocity vector (and z, but we ignore that too)
ofColor col; // contains r,g,b and a( alpha) components for color

Our init function is just standard openFrameworks, sets the position of the ball to a random position, gives it a random velocity vector, and a random color:

1
2
3
4
5
6
7
8
9
void init() {
pos.set(ofRandomWidth(), ofRandomHeight(), 0);
vel.set(ofRandomf(), ofRandomf(), 0);

col.r = ofRandom(0, 255);
col.g = ofRandom(0, 255);
col.b = ofRandom(0, 255);
col.a = ofRandom(0, 255);
}

Next up is the update, this is where we read from the accelerometer, update the velocity, and add to the position. The latter part (update velocity, add to position), is the core of all simple animation systems. We also check its position against screen boundaries, and bounce it if it has gone outside.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void update() {
vel.x += ACCELEROMETER_FORCE * ofxAccelerometer.getForce().x * ofRandomuf();
vel.y += -ACCELEROMETER_FORCE * ofxAccelerometer.getForce().y * ofRandomuf(); // this one is subtracted cos world Y is opposite to opengl Y

// add vel to pos
pos += vel;

// check boundaries
if(pos.x < RADIUS) {
pos.x = RADIUS;
vel.x *= -BOUNCE_FACTOR;
} else if(pos.x >= ofGetWidth() - RADIUS) {
pos.x = ofGetWidth() - RADIUS;
vel.x *= -BOUNCE_FACTOR;
}

if(pos.y < RADIUS) {
pos.y = RADIUS;
vel.y *= -BOUNCE_FACTOR;
} else if(pos.y >= ofGetHeight() - RADIUS) {
pos.y = ofGetHeight() - RADIUS;
vel.y *= -BOUNCE_FACTOR;
}
}

Most of this should be straightforward (if you’re used to similar animation techniques in openFrameworks, processing, flash etc.). The interesting thing happens in the first two lines of the function. ofxAccelerometer is a global variable (defined in the ofxAccelerometer addon). You can see what methods it has by looking at ofxAccelerometer.h in the addon source. getForce() returns as you may have guessed, the current force exerted on the device (its actually acceleration, but that was too long to type twice, so I called it force :P). The return value is a number in units of ‘g’ (earth gravity at sea level). It is also smoothed (to remove noise), you can change the amount of smoothing using ofxAccelerometer.setForceSmoothing(float amountOfSmoothing e.g. 0.2);

So we read ofxAccelerometer.getForce(), get the x component, multiply it by a constant defined at the beginning ACCELEROMETER_FORCE and then multiply it by a random number 0…1 (ofRandomuf() returns a normalized unsigned random number). We then add this to the x component of the velocity. The random number is simply there to spice it up a bit. So not all balls move exactly the same.

We also do the same to the y component of the velocity (using the y component of the ofxAccelerometer.getForce()). One thing to note however, for the y component we have to negate the acceleration value. This is because the default openFrameworks viewport is setup with (0,0) in top left, with positive y axis going down, whereas the iPhone accelerometer assumes a positive y axis going up. So we need to flip it.

Geek alert (safe to skip this paragraph): You may be thinking, isn’t it a bit inefficient to call ofxAccelerometer.getForce() twice? once for the x component, and once for the y component? Would it not be better to just cache it first in a local variable and then use that? The answer is technically no, but probably better yes. ofxAccelerometer.getForce() doesn’t do any calculations, it simply returns an ofPoint stored in ofxAccelerometer. Actually it doesn’t even return the ofPoint, it returns the address of the ofPoint (it’s a reference). Actually it doesn’t even do that, it’s an inline method so the compiler won’t even call the function but replace your code with the variable directly. So its not really slower to call getForce() everytime you need to use it. But if you didn’t look at the ofxAccelerometer source code, you wouldn’t know that, and anyone else reading your code wouldn’t know that either. So it probably is better (for readability sake and to avoid such discussions) to first cache ofxAccelerometer.getForce() locally, and use that local variable.

Then we want to draw our Things. This is again standard openFrameworks, set a color and draw a circle. Behind the scenes openFrameworks 006+ now uses Vertex Arrays for all its drawing functions, so is fully openGL ES compliant (you don’t really need to care about vertex arrays etc., all you need to care about is that all openFrameworks 006+ drawing routines work on iPhone).

1
2
3
4
void draw() {
ofSetColor(col.r, col.g, col.b, col.a);
ofCircle(pos.x, pos.y, RADIUS);
}

Finally we have our moveTo method, which simply moves our Thing to a new position:

1
2
3
4
5
void moveTo(int x, int y) {
ofPoint oldPos = pos;
pos.set(x, y, 0);
vel.set(0, 0, 0);
}

You may be wondering what is that 

1
ofPoint oldPos = pos;

doing in there? I am wondering the same thing myself. Originally I wrote the app so that you could swipe the screen and send the balls off with the velocity of your swipe (so your fingers and balls had momentum), but I thought the code was a bit too complex for a 1st example so I removed that – but it seems remnants of it are left. You can safely remove this line.

So all thats left, is to declare an array of Things:

1
Thing things[NUM_POINTS];

It is more conventional to declare the Thing class in its own file(s) as I previously mentioned (in Thing.h and Thing.cpp), and then include the things variable as a property of the testApp class. For such a tiny example as this one it doesn’t really make a difference. I kept everything in one file so everything could be ‘seen’ together. But for larger projects it does make sense to break things up into separate files.

So thats it for the first example. Hope it all made sense. Next time, more drawing routines, and sending touch info as OSC and TUIO (yup MSA Remote).

Full source for testApp.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include "testApp.h"

#define NUM_POINTS 10
#define BOUNCE_FACTOR 0.5
#define ACCELEROMETER_FORCE 0.2
#define RADIUS 30

class Thing {
public:
ofPoint pos;
ofPoint vel;
ofColor col;

void init() {
pos.set(ofRandomWidth(), ofRandomHeight(), 0);
vel.set(ofRandomf(), ofRandomf(), 0);

col.r = ofRandom(0, 255);
col.g = ofRandom(0, 255);
col.b = ofRandom(0, 255);
col.a = ofRandom(0, 255);
}

void update() {
vel.x += ACCELEROMETER_FORCE * ofxAccelerometer.getForce().x * ofRandomuf();
vel.y += -ACCELEROMETER_FORCE * ofxAccelerometer.getForce().y * ofRandomuf(); // this one is subtracted cos world Y is opposite to opengl Y

// add vel to pos
pos += vel;

// check boundaries
if(pos.x < RADIUS) {
pos.x = RADIUS;
vel.x *= -BOUNCE_FACTOR;
} else if(pos.x >= ofGetWidth() - RADIUS) {
pos.x = ofGetWidth() - RADIUS;
vel.x *= -BOUNCE_FACTOR;
}

if(pos.y < RADIUS) {
pos.y = RADIUS;
vel.y *= -BOUNCE_FACTOR;
} else if(pos.y >= ofGetHeight() - RADIUS) {
pos.y = ofGetHeight() - RADIUS;
vel.y *= -BOUNCE_FACTOR;
}
}

void draw() {
ofSetColor(col.r, col.g, col.b, col.a);
ofCircle(pos.x, pos.y, 30);
}

void moveTo(int x, int y) {
pos.set(x, y, 0);
vel.set(0, 0, 0);
}
};

Thing things[NUM_POINTS];

//--------------------------------------------------------------
void testApp::setup(){
printf("setup()\n");

ofBackground(0, 0, 0); // set background to black
ofSetBackgroundAuto(true); // set background to clear automatically every frame
ofSetFrameRate(60); // set desired framerate to 60fps

// initialize the accelerometer
ofxAccelerometer.setup();

// touch events will be sent to this object (this instance of testApp)
ofxMultiTouch.addListener(this);

// initialize all of the Thing particles
for(int i=0; i<NUM_POINTS; i++) things[i].init();
}

//--------------------------------------------------------------
void testApp::update(){
// printf("update()\n");
for(int i=0; i<NUM_POINTS; i++) things[i].update();
}

//--------------------------------------------------------------
void testApp::draw(){
// printf("draw()\n");
for(int i=0; i<NUM_POINTS; i++) things[i].draw();
}

void testApp::exit() {
printf("exit()\n");
}

//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){
printf("mouseMoved: %i, %i\n", x, y); // this will never get called

}

// mouse functions are there for backwards compatibility
// they are simply the first finger to touch the screen
// you can omit the mouse functions and just use touch functions
// or omit touch functions and just use mouse functions if you don't need multitouch
//--------------------------------------------------------------

void testApp::mouseDragged(int x, int y, int button){
printf("mouseDragged: %i, %i %i\n", x, y, button);
// things[0].moveTo(x, y); // no need to do this here, doing it touchMoved()
}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
printf("mousePressed: %i, %i %i\n", x, y, button);
// things[0].moveTo(x, y); // no need to to this here, doing it in touchDown()
}

//--------------------------------------------------------------
void testApp::mouseReleased(){
// printf("mouseReleased\n");
printf("frameRate: %.3f, frameNum: %i\n", ofGetFrameRate(), ofGetFrameNum());
}

//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){
printf("mouseReleased: %i, %i %i\n", x, y, button);
}

//--------------------------------------------------------------
void testApp::touchDown(float x, float y, int touchId, ofxMultiTouchCustomData *data) {
printf("touchDown: %f, %f %i\n", x, y, touchId);
things[touchId].moveTo(x, y);
}

void testApp::touchMoved(float x, float y, int touchId, ofxMultiTouchCustomData *data) {
printf("touchMoved: %f, %f %i\n", x, y, touchId);
things[touchId].moveTo(x, y);
}

void testApp::touchUp(float x, float y, int touchId, ofxMultiTouchCustomData *data) {
printf("touchUp: %f, %f %i\n", x, y, touchId);
}

void testApp::touchDoubleTap(float x, float y, int touchId, ofxMultiTouchCustomData *data) {
printf("touchDoubleTap: %f, %f %i\n", x, y, touchId);
ofToggleFullscreen();
}

This is a tutorial in getting a very simple openFrameworks application running on iPhone with basic graphics, multitouch and accelerometer […]

Related keywords

iphone, open source, openframeworks, tutorial