src/PhysicsWorld.cc
author terom
Mon, 08 Dec 2008 18:12:43 +0000
changeset 300 417183866f35
parent 288 47a5d7896aec
child 351 7e6d373d8c98
permissions -rw-r--r--
suicide key and respawning

#include "PhysicsWorld.hh"
#include "Engine.hh"

#include <functional>

PhysicsWorld::PhysicsWorld (Vector gravity, Vector dimensions) :
    // XXX: assume Vector == PixelCoordinate
    Terrain((unsigned int) dimensions.x, (unsigned int) dimensions.y, 1337), 
    dimensions(dimensions), 
    gravity(gravity),
    tick_timer(PHYSICS_TICK_MS)
{
    slots.connect(tick_timer.sig_tick(), this, &PhysicsWorld::tick);
    tick_timer.start();
}

void PhysicsWorld::addPhysicsObject (PhysicsObject *po) {
    objects.push_back(po);
}

void PhysicsWorld::removePhysicsObject (PhysicsObject *po) {
    objects.remove(po);
}


float distancePointToLine(Vector l1, Vector l2, Vector p) {
    Vector v(l2.y - l1.y, -(l2.x - l1.x));
    Vector r(l1.x-p.x, l1.y-p.y);
    v = v/v.length();
    float dist = v*r/v.sqrLength();
    return dist;
}

void PhysicsWorld::tick (TimeMS tick_length) {
    // tick each object in turn
    for (std::list<PhysicsObject*>::iterator i = objects.begin(); i != objects.end(); i++) {
        (*i)->tick(tick_length); 
    }
    for (std::list<PhysicsObject*>::iterator i = objects.begin(); i != objects.end(); i++) {
        for (std::list<PhysicsObject*>::iterator j = i; j != objects.end(); j++) {
            if(i == j)
                continue;
            float range_sum_sqr = 2;
            if((*i)->getType() == PLAYER) {
                range_sum_sqr += PLAYER_RADIUS-1;
            }
            if((*j)->getType() == PLAYER) {
                range_sum_sqr += PLAYER_RADIUS-1;
            }
            range_sum_sqr *= range_sum_sqr;
            bool collision = false;
            Vector a1 = (*i)->getPreviousPosition();
            Vector a2 = (*i)->getPosition();
            Vector b1 = (*j)->getPreviousPosition();
            Vector b2 = (*j)->getPosition();
/*            if(a1 == a2) {
                float d = abs(distancePointToLine(b1, b2, a1));
                if(d*d < range_sum_sqr)
                    collision = true;
            } else if(b1 == b2) {
                float d = abs(distancePointToLine(a1, a2, b1));
                if(d*d < range_sum_sqr)
                    collision = true;
            } else {*/
                float db1 = distancePointToLine(a1, a2, b1);
                float db2 = distancePointToLine(a1, a2, b2);
                float da1 = distancePointToLine(b1, b2, a1);
                float da2 = distancePointToLine(b1, b2, a2);
                if(db1*db2 < 0 && da1*da2 < 0) {
                    // lines intersected
//                    collision = true;
                }
                float dab = (a2-b2).sqrLength();
                if(dab < range_sum_sqr) {
                    collision = true;
                }
//            }
            if(collision) {
                (*i)->onCollision(a2, *j);
                (*j)->onCollision(b2, *i);
            }
        }
    }

    // Delete destroyed objects
    objects.remove_if(std::mem_fun(&PhysicsObject::removeIfDestroyed));
}

TickCount PhysicsWorld::getTicks (void) {
    return tick_timer.get_ticks();
}