src/proto2/Physics.hh
author saiam
Sun, 30 Nov 2008 17:13:16 +0000
changeset 150 5e032b540af3
parent 138 cc326b64ae20
child 153 73402d5b778e
permissions -rw-r--r--
Now it uses Terrain class, but it isn't properly integrated to the infrastructure.
#ifndef PHYSICS_HH
#define PHYSICS_HH

#include <vector>
#include <queue>
#include <ClanLib/core.h>
#include <ClanLib/display.h>

#include "Vector.hh"
#include "Config.hh"
#include "Terrain.hh"

// Forward declares
class PhysicsWorld;
class PhysicsObject;
class PlayerObject;
class ProjectileObject;
class Shape;
struct Derivative;

// Type definitions
typedef uint16_t TimeMS;
typedef Vector Force;

// TODO: Random definitions. Should these be somewhere else?
//enum TerrainType {EMPTY, DIRT, ROCK};

// Yeah?!?!?! Atleast this could be documented. Contains vectors
// presenting all the 8 directions in a square grid?
//const Vector DIRECTIONS[] = { Vector(0,-1), Vector(1,-1), Vector(1,0), 
//                            Vector(1,1), Vector(0,1), Vector(-1,1), 
//                            Vector(-1,0), Vector(-1,-1) };


/**
 * PhysicsWorld class. PhysicsWorld contains PhysicsObjects that are
 * simulated in the PhysicsWorld.
 */
class PhysicsWorld {
    friend class PhysicsObject;

private:
    CL_Timer tick_timer;
    uint32_t tick_counter;

    Terrain terrain;

protected:
    //std::vector<PlayerObject*> players;
    //std::vector<ProjectileObject*> projectiles;
    std::vector<PhysicsObject*> objects;

    // Contains connections between signals and slots
    CL_SlotContainer slots;

    PhysicsWorld(Vector gravity, Vector dimensions);

    // TODO: Should these be somewhere else?
    Vector dimensions;
    Vector gravity;



public:
    // TODO: Replace addObject with these?
    //void addPlayerObject(PlayerObject *object);
    //void addProjectileObject(ProjectileObject *object);
    
    /**
     * Add object to the PhysicsWorld.
     *
     * @param object Pointer to the PhysicsObject to add.
     */
    void addObject(PhysicsObject *object);

    /**
     * Advance one time step in physics simulation.
     */
    void tick();

    /**
     * Get current tick in physics simulation.
     *
     * @return tick Current simulation tick.
     */
    uint32_t getTick();

    // ?!!?!?!?!?!?!
    // TODO: If there were a terrain class, these could it's members.
    /**
     * Generate random terrain.
     *
     * @param seed Random generator seed.
     */
    void generateTerrain(int seed);
    /**
     * Remove ground from the terrain. Removes a circle.
     *
     * @param x Circle x-coordinate
     * @param y Circle y-coordinate
     * @param r Circle radius
     */
    void removeGround(int x, int y, float r);
    /**
     * Remove ground from the terrain. Removes a circle.
     *
     * @param pos Circle location
     * @param r Circle radius
     */
    void removeGround(Vector pos, float r);
    /**
     * Return normal for the wall that has been hit.
     *
     * @param hitPoint The point of the wall that has been hit.
     * @param prevPoint The point from where we were coming.
     */
    Vector getNormal(Vector hitPoint, Vector prevPoint);
    /**
     * Return terrain type in given position.
     *
     * @param x X-coordinate
     * @param y Y-coordinate
     */
    TerrainType getType(int x, int y) const;
    /**
     * Return terrain type in given position.
     *
     * @param pos Coordinate vector
     */
    TerrainType getType(Vector pos) const;

    void drawTerrain(CL_GraphicContext *gc);
};

/**
 * PhysicObject class. A basic PhysicsObject class.
 */
class PhysicsObject {
protected:
    // This probably shouldn't be done this way.
    PhysicsWorld &world;

    Vector position;
    Vector velocity;
    float mass;
    bool inAir; // Is the object "on the ground"

    // Attributes for players
    float aim; // Aim direction (half circle)
    bool facingRight; // Player facing

    PhysicsObject(PhysicsWorld &world, float mass, Vector position, 
                  Vector velocity);
    ~PhysicsObject() {}


    /**
     * Add force to the force queue to be applied on next tick.
     *
     * @param force Force vector
     */
    void applyForce(Force force);

    /**
     * Change player aim
     *
     * @param da Aim angle change
     */
    void changeAim(float da);
   
    /**
     * Set player facing.
     *
     * @param facingRight True if player is facing right.
     */
    void setFacing(bool facingRight);

    /**
     * Handle ground-jumping
     */
    void jump();

    /** 
     * Handle ground-bounce
     *
     * @param normal Normal vector relative to which to bounce
     */
    void bounce(Vector normal);

    /**
     * Called on network clients to sync state from server
     *
     * @param position New position
     * @param velocity New velocity
     * @param inAir New inAir value
     */
    void updatePhysics(Vector position, Vector velocity, bool inAir);

private:
    // TODO: I'd be tempted to use some already made ClanLib structure
    // here.  
    // Shape of the object. Edge points of the shape polygon.
    std::vector<Vector> shape;

    // TODO: Should these operations be moved to PhysicsWorld?
    // Force queue that is emptied on every tick
    std::queue<Force> forceq;
    // Helper variables for integration
    Vector posAfterTick;
    Vector velAfterTick;

    /**
     * Handle player movement and apply forces.
     */
    void updatePosition();

    // TODO: Should these be moved to PhysicsWorld?
    /**
     * Use RK4 to integrate the effects of force over a time interwall.
     *
     * @param force Force to integrate
     * @param dt Time intervall
     */
    void integrate(Force force, TimeMS dt);

    /**
     * Evaluate the value of the derivative at given time
     *
     * @param force Force
     * @param dt Time
     * @param d Previous derivative
     */
    Derivative evaluate(Force force, TimeMS dt, Derivative &d);

    /**
     * Return object acceleration with given force.
     *
     * @param force Force
     * @return Acceleration
     */
    Vector acceleration(const Force &force);

    // TODO: If integration is moved to PhysicsWorld then this should
    // also move there.
    /**
     * Handle ground movement.
     *
     * @param right Boolean describing the movement direction.
     * @return New position
     */
    Vector walk(bool right);

    /*
     * Handle collision. TODO: This is not used. It probably should
     * be?
     */
    virtual void onCollision() {}

    /*
     * TODO: This probably does some kind of collision
     * detection. Could be named/documented better.
     */
    bool possibleLocation(Vector loc);

public:
    /**
     * Get current object position.
     *
     * @return Position vector
     */
    Vector getPosition();

    /**
     * Return object shape.
     *
     * @return Polygon points
     */
    std::vector<Vector>& getShape();

    /**
     * Set object shape.
     *
     * @param shape Vector containing polygon poinst
     */
    void setShape(std::vector<Vector> shape);

    /**
     * Return object facing.
     *
     * @return Object facing (true if facing right)
     */
    bool getFacing();

    /**
     * Return object aim angle.
     *
     * @return Object aim angle
     */
    float getAim();

    /**
     * Update object in physics simulation.
     */
    void tick();
};

// TODO: This could probably be moved somewhere else or removed
// completely.
struct Derivative {
    Vector dx; // Velocity
    Vector dv; // Acceleration
};


// TODO: These are drafts
/**
 * PlayerObject class. Represents a player in the physics engine.
 */
//class PlayerObject : public PhysicsObject {

//};

/**
 * ProjectileObject class. Represents different projectiles in the
 * physics (i.e. not players) in the physics engine.
 */
//class ProjectileObject : public PhysicsObject {

//};

#endif