[work 9] Liquid

[work 9] Liquid

Movie

Source code

about

  • ボールを落下させる
  • 空気中の落下と液体中の落下を表現する

file

  • 上部にあるファイル名が表示されているボタンを押すと、表示されるファイルが切り替わります
  • 別ウィンドウ表示したい時や行番号などが無いRawMode表示したい時は、コード内右上のボタンを押してください(ボタンはマウスオーバーすると表示されます)
#include "ofMain.h"
#include "ofApp.h"

//========================================
int main( ){

    // 4K:4096x2160
    // 2K:2048x1080
    // FullHD:1920x1080
    // HD:1440x1080
    // HD720p:1280x720
    // DVD:720x480
	ofSetupOpenGL(1280,720, OF_WINDOW);

	// this kicks off the running of my app
	// can be OF_WINDOW or OF_FULLSCREEN
	// pass in width and height too:
	ofRunApp( new ofApp());

}
#pragma once

#include "ofMain.h"
#include <random>

#include "Mover.hpp"
#include "Liquid.hpp"

#include "myColorLib.hpp"


class ofApp : public ofBaseApp{
	public:
    ofApp();
    ~ofApp();
    
		void setup();
		void update();
		void draw();
		
		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 mouseEntered(int x, int y);
		void mouseExited(int x, int y);
		void windowResized(int w, int h);
		void dragEvent(ofDragInfo dragInfo);
		void gotMessage(ofMessage msg);
    
private:
    Liquid *liquid;
    Mover *m[MOVER_MAX];
    ofVec2f gravity;
    ofVec2f wind;
    
    myColorLib *myColLib;
};
#include "ofApp.h"


ofApp::ofApp(){
    myColLib = new myColorLib(MYCOL_ALL);
    
    liquid = new Liquid(0, ofGetHeight() / 2, ofGetWidth(), ofGetHeight() / 2, 0.1);
    
    for (int i = 0; i < MOVER_MAX; i++) {
        m[i] = new Mover(ofRandom(0.5, 2), ofRandomWidth(), ofGetHeight() / ofRandom(4, 10), myColLib->getColor(ofRandom(1)));
    }
    
}

ofApp::~ofApp(){

    for (int i = 0; i < MOVER_MAX; i++) {
        if (m[i] != nullptr) {
            delete m[i];
        }
    }
    
    delete liquid;
    
    delete myColLib;
    
}

//--------------------------------------------------------------
void ofApp::setup(){
    double fps = 30;
    
    ofSetFrameRate(fps);
    ofBackground(255,255,255);
    ofSetBackgroundAuto(true);
    
    gravity = ofVec2f(0, 0);
    wind = ofVec2f(0, 0);
}

//--------------------------------------------------------------
void ofApp::update(){
    wind = ofVec2f(ofRandom(-0.1, 0.1), 0);
    
    for (int i = 0; i < MOVER_MAX; i++) {
        if (m[i] != nullptr) {
            if (liquid->contains(*m[i])) {
                ofVec2f dragForce = liquid->drag(*m[i]);
                m[i]->applyForce(dragForce);
            }
            
            gravity = ofVec2f(0, 0.2 * m[i]->getMass());
            m[i]->applyForce(gravity);
            
            m[i]->applyForce(wind);
            
            m[i]->update();
            
            if (m[i]->getLife() == 0) {
                delete m[i];
                m[i] = nullptr;
            }
        }
    }
}


//--------------------------------------------------------------
void ofApp::draw(){
    liquid->display();
    
    for (int i = 0; i < MOVER_MAX; i++) {
        if (m[i] != nullptr) {
            m[i]->display();
        }
    }
}
#ifndef Liquid_hpp
#define Liquid_hpp

#include <stdio.h>
#include "Mover.hpp"
#include "ofMain.h"


class Liquid {
public:
    Liquid(float x_, float y_, float w_, float h_, float c_);
    ~Liquid();
    void display();
    bool contains(Mover m);
    ofVec2f drag(Mover m);
    
private:
    float x, y, w, h;   // Field
    float c;            // Drag coefficient
};
#endif /* Liquid_hpp */
#include "Liquid.hpp"


Liquid::Liquid(float x_, float y_, float w_, float h_, float c_)
{
    x = x_;
    y = y_;
    w = w_;
    h = h_;
    c = c_;
}


Liquid::~Liquid()
{
    
}


void Liquid::display()
{
    ofSetColor(0, 16, 128, 128);
    ofFill();
    ofDrawRectangle(x, y, w, h);
}


bool Liquid::contains(Mover m)
{
    ofVec2f l = m.getLocation();
    bool ret = ((l.x > x) && (l.x < x + w)) && ((l.y > y) && (l.y < y + h));
    
    return ret;
}


ofVec2f Liquid::drag(Mover m)
{
    ofVec2f l = m.getLocation();
    float s = m.getSurface();
    float speed = m.getVelocity().length();
    float dragMag = c * speed * speed * (s * 0.015);
    
    ofVec2f dragForce = m.getVelocity() * (-1);
    dragForce.normalize();
    dragForce *= dragMag;
    
    return dragForce;
}
#ifndef Mover_hpp
#define Mover_hpp

#include <stdio.h>
#include "ofMain.h"

#define MOVER_MAX (30)

class Mover {
public:
    Mover();
    Mover(float m, float x, float y, ofColor c);
    ~Mover();
    void update();
    bool checkEdges();
    void applyForce(ofVec2f force);
    float getMass();
    unsigned int getLife();
    ofVec2f getVelocity();
    ofVec2f getLocation();
    float getSurface();
    void display();
    
private:
    ofVec2f location;
    ofVec2f velocity;
    ofVec2f acceleration;
    float radius;
    float mass;
    ofColor color;
    unsigned int life;
    const unsigned int lifeMin = 400;
    const unsigned int lifeMax = 1000;
};

#endif /* Mover_hpp */
#include "Mover.hpp"


Mover::Mover()
{
    location = ofVec2f(ofGetWidth() / 2, ofGetHeight() / 2);
    velocity = ofVec2f(0, 0);
    acceleration = ofVec2f(0, 0);
    radius = 10;
    mass = 1;
    life = 30;
    color = ofColor(0);
}

Mover::Mover(float m, float x, float y, ofColor c)
{
    location = ofVec2f(x, y);
    velocity = ofVec2f(0, 0);
    acceleration = ofVec2f(0, 0);
    mass = m;
    radius = mass * 20;
    life = (unsigned int)ofRandom(lifeMin, lifeMax);
    color = c;
}

Mover::~Mover()
{
    
}


void Mover::update()
{
    velocity += acceleration;
    location += velocity;
    if (checkEdges() != false) {
        velocity += acceleration;
        location += velocity;
    }
    acceleration *= 0;
    
    if (life > 0) {
        life--;
    }
}


bool Mover::checkEdges()
{
    bool result = false;
    
    if ((int)(location.x + radius) >= ofGetWidth()) {
        location.x = ofGetWidth() - radius;
        applyForce(ofVec2f(mass * velocity.x * -2, 0));
        result = true;
    } else if ((int)(location.x - radius) <= 0) {
        location.x = radius;
        applyForce(ofVec2f(mass * velocity.x * -2, 0));
        result = true;
    }
    
    if ((int)(location.y + radius) >= ofGetHeight()) {
        location.y = ofGetHeight() - radius;
        applyForce(ofVec2f(0, mass * velocity.y * -2));
        result = true;
    } else if ((int)(location.y - radius) <= 0) {
        location.y = radius;
        applyForce(ofVec2f(0, mass * velocity.y * -2));
        result = true;
    }
    
    return result;
}

void Mover::applyForce(ofVec2f force)
{
    acceleration += force / mass;
}

float Mover::getMass()
{
    return mass;
}

unsigned int Mover::getLife()
{
    return life;
}

ofVec2f Mover::getVelocity()
{
    return velocity;
}


ofVec2f Mover::getLocation()
{
    return location;
}


float Mover::getSurface()
{
    return PI * radius;
}

void Mover::display()
{
    color.a = (int)ofMap(life, 0, lifeMax, 0, 255, true);
    ofSetColor(color);
    ofDrawCircle(location.x, location.y, radius);
}

Development environment

  • openframeworks 0.10.1
  • c++
  • macOS
  • Xcode