Being a total newbie to OF, I created a very simple particle system using attraction (http://www.shiffman.net/teaching/nature/forces/ is a great resource for this!).
Because I had a lot of start up troubles (pointers, creating a new project etc…) I wanted to write a tutorial on this for others. Please feel free to add information or to correct me!
step 1 (see readme.txt in OF package)
a) copy the folder inside of apps/exampleApps/ and paste in the same directory
ie: (copy “emptyExample” and paste “copy of emptyExample”)
b) rename the folder, and inside the folder, rename the .xcodeproj file - ie: myExperimentalApp.xcodeproj
c) open the project
d) in the sidebar scroll down to Targets and expand it to show the target. ie: emptyExample
e) with the target selected do Get Info ( either right click or Command-i )
f) in the General Tab rename the Name text field ie: from emptyExample to myExperimentalApp
e and f alternative ) you can also just do right click on the target -> rename in the sidebar directly
g) after you have renamed the target you should change the build from Debug to Release then back again. This refreshes the target app.
step 2 Adding external library
with XCode , go to Project --> add to project and select the lib you need (ofxVectorMath in the addons folder in this case)
step 3 Pointers
for (int i=0; i<3; i++){
particle[i] = new Particle();
}
We store the reference to each Particle into the pointer “particle”. If we want to access those particles we do it like this:
for (int i=0; i<3; i++){
particle[i]->update();
//we can also use this
//(*(particle[i])).update();
}
using -> still treats particle[i] as a pointer, while if we use *(particle[i])) we access the value of that pointer (which is the Particle Object)
step 4 Pointers as arguments
If we want to pass those particles into another function we will use the particle pointer again. attractor is also a pointer, so that why we use the ->
for (int i=0; i<3; i++){
ofxVec2f f = attractor[0]->calcGravForce(particle[i]);
}
the function of attractor[0] will accept a pointer and looks like this:
ofxVec2f Particle::calcGravForce(Particle *p){
cout << p->mass << endl;
return direction;
}
Now we can have access to the particle as a pointer (that’s why we use ->)!
**step 5 Constructors with arguments **
If we want constructors which allow arguments, we need to do 2 things.
edit the header file (.h)
public:
//default constructor
Particle();
//constructor which takes arguments
Particle(ofxVec2f location,ofxVec2f velocity,ofxVec2f accel, float m);
edit the code file (.cpp)
Particle::Particle(){
}
Particle::Particle(ofxVec2f location,ofxVec2f velocity,ofxVec2f accel, float m){
loc= location;
vel=velocity;
acc=accel;
mass=m;
}
All the code:
testApp.h
#ifndef _TEST_APP
#define _TEST_APP
#include "ofMain.h"
#include "Particle.h"
#define numParticles 2000
#define numAttractors 1
class testApp : public ofBaseApp{
private:
Particle *particle[numParticles];
Particle *attractor[numAttractors];
public:
void setup();
void update();
void draw();
void createAttractor();
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(int x, int y, int button);
void windowResized(int w, int h);
};
#endif
testApp.cpp
#include "testApp.h"
#include "ofxVec2f.h"
#include "Particle.h"
//--------------------------------------------------------------
void testApp::setup(){
createAttractor();
ofxVec2f l;
ofxVec2f v;
ofxVec2f a;
for (int i=0; i<numParticles; i++){
float m=ofRandom(1,2);
l.set(ofRandom(0,100), ofRandom(0,100));
v.set(ofRandom(1,2), ofRandom(1,2));
a.set(0, 0);
particle[i] = new Particle(l,v,a,m);
}
}
void testApp::createAttractor(){
ofxVec2f l;
ofxVec2f v;
ofxVec2f a;
float m=2.2;
l.set(400, 400);
v.set(0, 0);
a.set(0, 0);
for (int i=0; i<numAttractors; i++){
attractor[i] = new Particle(l,v,a,m);
}
}
//--------------------------------------------------------------
void testApp::update(){
for (int i=0; i<numParticles; i++){
ofxVec2f f = attractor[0]->calcGravForce(particle[i]);
particle[i]->applyForce(f);
particle[i]->update();
}
}
//--------------------------------------------------------------
void testApp::draw(){
attractor[0]->draw();
for (int i=0; i<numParticles; i++){
particle[i]->draw();
}
}
//--------------------------------------------------------------
void testApp::keyPressed(int key){
}
//--------------------------------------------------------------
void testApp::keyReleased(int key){
}
//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
}
//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){
}
//--------------------------------------------------------------
void testApp::windowResized(int w, int h){
}
Particel.h
#ifndef PARTICLE
#define PARTICLE
#include "ofMain.h"
#include "ofxVec2f.h"
#import "ofMain.h"
class Particle {
public:
Particle();
Particle(ofxVec2f location,ofxVec2f velocity,ofxVec2f accel, float m);
float x;
float y;
float mass;
float max_vel;
float bounce_force;
ofxVec2f loc;
ofxVec2f vel;
ofxVec2f acc;
void setup();
void update();
void draw();
void applyForce(ofxVec2f force);
ofxVec2f calcGravForce(Particle *p);
};
#endif
Particle.cpp
#include "Particle.h"
#include "ofxVec2f.h"
Particle::Particle(){
}
Particle::Particle(ofxVec2f location,ofxVec2f velocity,ofxVec2f accel, float m){
loc= location;
vel=velocity;
acc=accel;
mass=m;
}
void Particle::setup(){
}
ofxVec2f Particle::calcGravForce(Particle *p){
ofxVec2f direction = (loc-p->loc); // Calculate force direction
float distance = direction.length(); // Distance between objects
if(distance > 25){
distance=25;
}
if(distance<5){
distance=5;
}
direction.normalize();
float force = (1 * mass * p->mass) / (distance * distance);
direction=direction*force;
return direction;
}
void Particle::applyForce(ofxVec2f force){
force=force/mass;
acc=acc+force;
}
void Particle::update(){
vel=vel+acc;
vel=vel.limit(1.1);
loc=loc+vel;
acc=acc*(0);
}
void Particle::draw(){
ofSetColor(0xff0000);
ofCircle(loc.x, loc.y, 2);
}