src/PhysicsObject.hh
author nireco
Sat, 31 Jan 2009 12:33:08 +0200
changeset 443 5d1119729f58
parent 428 712b943195a6
permissions -rw-r--r--
worm02 two pics to comment
#ifndef PHYSICS_OBJECT_HH
#define PHYSICS_OBJECT_HH


// Forward declares
class PhysicsObject;
struct Derivative;

#include "PhysicsWorld.hh"
#include "Vector.hh"
#include "Timer.hh"
#include "Config.hh"

#include <utility>
#include <queue>

// Type definitions
typedef Vector Force;

/** Specifies possible object types. */
enum ObjectType { PLAYER, PROJECTILE, ROPE };

/** Specifies possible facing directions for objects. */
enum FacingDirection {
    FACING_LEFT,
    FACING_RIGHT
};

/**
 * PhysicsObject class. Represents an object in the physics simulation.
 */
class PhysicsObject {
protected:
    /** Reference to PhysicsWorld. */
    PhysicsWorld &world;

private:
    /** Position */
    Vector position;

    /** Position at previous tick */
    Vector previousPosition;

    /** Velocity */
    Vector velocity;

    /** Mass */
    float mass; 
 
    /** Object's shape, polygon vertices */
    std::vector<Vector> shape;

    /** Force queue, emptied on every physics tick */
    std::queue<std::pair<Force, TimeMS> > forceq;


protected:
    /** Tells if the object is "on the ground" */
    bool inAir;

    /** Object elasticity */
    float collision_elasticity;

    /** Aim angle in radians */
    float aim; 

    /** Player facing */
    FacingDirection facing; 

    /** Specifies if the object should be simulated */
    bool alive;

    /** True if !alive, and the object can be delete'd */
    bool shouldDelete;
    
    /** Type of the object */
    ObjectType type;

    /** Pivot object for this object */
    PhysicsObject *pivot;

    /** 
     * Class constructor
     *
     * @param world Reference to PhysicsWorld
     * @param mass Object mass
     * @param position Object position
     * @param velocity Object velocity
     * @param type Object type
     * @param collision_elasticity Object elasticity
     * @param enabled Is the object currently part of the simulation
     */
    PhysicsObject (PhysicsWorld &world, float mass, Vector position, Vector velocity, ObjectType type, 
            float collision_elasticity, bool enabled = true);
    
    /**
     * Virtual destructor
     */
    virtual ~PhysicsObject (void);

    /**
     * Apply a force to the object. The force is applied to the object
     * on the next physics tick.
     *
     * @param force Force vector
     */
    void applyForce (Force force, TimeMS dt = PHYSICS_TICK_MS);

    /**
     * Change player aim. This function takes care that aim angle
     * stays inside limits.
     *
     * @param da Aim angle change in radians
     */
    void changeAim (float da);
   
    /**
     * Set player facing.
     *
     * @param facingRight True if player is facing right.
     */
    void setFacing (FacingDirection facing) {
        this->facing = facing;
    }

    /**
     * Makes the player jump in the air.
     *
     * @param direction -1: jump left, 0: jump up, 1: jump right
     */
    void jump (int direction);

    /** 
     * Handle object 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
     * @param facingRight New facingRight value
     * @param aim New aim
     */
    virtual void updatePhysics (Vector position, Vector velocity, bool inAir, FacingDirection facing, float aim);

    /**
     * Put the object in the physics simulation. When the object is in
     * the physics simulation it's movements will be calculated.
     */
    void enable (void);

    /**
     * Remove object from the objects physics simulation. When the
     * object isn't in the physics simulation it won't be deleted but
     * its movements will not be calculated.
     */
    void disable (void);

private:
    /**
     * Handle player movement and apply forces.
     *
     * @param dt Time intervall
     */
    void updatePosition (TimeMS dt);

    /**
     * Use RK4 to integrate the effects of force over a time interwall.
     *
     * @param force Force to integrate
     * @param dt Time intervall
     * @param posAfterTick Reference to object postition after integration.
     * @param velAfterTick Reference to object velocity after integration.
     */
    void integrate (Force force, TimeMS dt, Vector &posAfterTick, Vector &velAfterTick);

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

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

     /**
     * Handle ground movement.
     *
     * @param right Boolean describing the movement direction.
     * @return New position
     */
    void walk (TimeMS, bool right);

    /*
     * Undocumented private method
     */
    Vector walk_one_step (float, bool);

public:
    /**
     * Define object behaviour on collisions.
     *
     * @param collisionPoint Point of collision.
     * @param other The other object we have collided with.
     */
    virtual void onCollision (Vector collisionPoint, PhysicsObject *other = NULL);

    /**
     * Get object type.
     *
     * @return Object type
     */
    ObjectType getType (void) const {
        return type;
    }

    /**
     * Checks if it is possible for the object to be in the given
     * location.
     *
     * @param loc Location
     */
    bool possibleLocation (Vector loc);

    /**
     * Get current object position.
     *
     * @return position vector
     */
    Vector getPosition (void) const {
        return position;
    }

    /**
     * Get previous object position.
     *
     * @return position vector
     */
    Vector getPreviousPosition (void) const {
        return previousPosition;
    }

    /**
     * Get current object screen coordinates
     *
     * @return PixelCoordinate position
     */
    PixelCoordinate getCoordinate (void) const;

    /**
     * Get current object velocity.
     *
     * @return Velocity vector
     */
    Vector getVelocity (void) const {
        return velocity;
    }

    /**
     * Return object facing.
     *
     * @return Object facing (true if facing right)
     */
    FacingDirection getFacing (void) const {
        return facing;
    }

    /**
     * Return object aim angle.
     *
     * @return Object aim angle
     */
    float getAim (void) const {
        return aim;
    }

    /**
     * Get object direction.
     *
     * @return Unit vector to facing+aim
     */
    Vector getDirection (void) const;

    /**
     *  Mark object as destroyed, it will be delete'd later
     */
    void destroy (void);

    /**
     * Check if the object is alive.
     *
     * @return Is the object alive?
     */
    bool isAlive (void) const {
        return alive;
    }
    
    /**
     * Tells the state of the object.
     *
     * @return True if object has been destroyed.
     */
    bool removeIfDestroyed (void);

    /**
     * Set object pivot.
     *
     * @param pivot Pivot object
     */
    void setPivot (PhysicsObject *pivot) {
        this->pivot = pivot;
    }

    /**
     * Return the pivot object pointer.
     */
    PhysicsObject *getPivot (void) {
        return pivot;
    }

    /**
     * Compute the force that this object (as a pivot) exerts on the given object
     *
     * @param bob Othe object
     * @return Force
     */
    virtual Vector getPivotForce (void);

    /**
     * Checks if object collides with other objects
     *
     * @param obj Other PhysicsObject
     * @return Did we collide?
     */
    bool collides (const PhysicsObject &obj);

    /**
     * Update object in physics simulation.
     *
     * @param tick_length Length of the physics tick
     */
    virtual void tick (TimeMS tick_length);

protected:
    /**
     * Set object shape.
     *
     * XXX: constructor
     *
     * @param shape Vector containing polygon points
     */
    void setShape(std::vector<Vector> shape) {
        this->shape = shape;
    }

    /**
     * Update object position, also updating our previous position
     *
     * @param pos new position
     */
    void setPosition (Vector pos);

    /**
     * Update current object velocity.
     *
     * @param velocity new velocity
     */
    void setVelocity (Vector velocity) {
        this->velocity = velocity;
    }

    /**
     * Reset state and disable, ready to be resume()'d again in a different place
     */
    void reset (void);

    /**
     * Resume after a reset() at the given position with a zero velocity
     */
    void resume (Vector position);
};

/** Helper struct for the integration */
struct Derivative {
    /**
     * Velocity
     */
    Vector dx;

    /**
     * Acceleration
     */ 
    Vector dv; 
    
    Derivative () : dx(), dv() { }
    Derivative (Vector dx, Vector dv) : dx(dx), dv(dv) { }
};

/**
 * Returns the "sign" of the cross product between given points. In
 * practice the sign of the return value tels on which side of the
 * line drawn between p1 and p2 the point p3 is.
 *
 * @param p1 Line start point
 * @param p2 Line end point
 * @param p3 Point
 * @return Variable, the sign of which tells on which side of the line p3 is.
 */
int8_t crossProduct(const Vector &p1, const Vector &p2, const Vector &p3);

#endif