src/PhysicsObject.hh
author terom
Mon, 08 Dec 2008 12:02:20 +0000
changeset 282 e0e4dfc3e528
parent 279 e36f5e1a1c8d
child 285 c080c8c70333
permissions -rw-r--r--
compiles cleanly with -Wall -Wextra -Wconversion, not tested, but that shouldn't break anything :)
#ifndef PHYSICS_OBJECT_HH
#define PHYSICS_OBJECT_HH

#include <ClanLib/display.h>
#include <utility>

// Forward declares
class PhysicsObject;
struct Derivative;

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

// Type definitions
typedef Vector Force;
    
enum ObjectType { PLAYER, PROJECTILE, ROPE };

enum FacingDirection {
    FACING_LEFT,
    FACING_RIGHT
};

/**
 * PhysicObject class. A basic PhysicsObject class.
 */
class PhysicsObject {
public:
    PhysicsWorld &world;

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

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

    bool alive;
    bool shouldDelete;
    
    ObjectType type;

    PhysicsObject *pivot;

    PhysicsObject (PhysicsWorld &world, float mass, Vector position, Vector velocity, ObjectType type, 
            float collision_elasticity, bool enabled = true);
    virtual ~PhysicsObject (void);


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

    /**
     * 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 (FacingDirection facing);

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

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

    /**
     * Put object to the objects list so that its movement will be calculated.
     */
    void enable (void);

    /**
     * Remove object from the objects list but don't delete the object itself.
     */
    void disable (void);

private:
    // Shape of the object. Edge points of the shape polygon.
    std::vector<Vector> shape;

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

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

    // 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, Vector &posAfterTick, Vector &velAfterTick);

    /**
     * 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, 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);
    Vector walk_one_step(float, bool);

    /**
     * Define object behaviour on collisions.
     *
     * XXX: make this pure-virtual
     */
    virtual void onCollision (Vector collisionPoint, PhysicsObject *other);

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

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

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

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

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

    /**
     * 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)
     */
    FacingDirection getFacing() const;

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

    /**
     * Returns facing+aim as a unit vector
     */
    Vector getDirection (void) const;

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

    /*
     * Had the object been destroyed?
     */
    bool isDestroyed (void);
    
    /**
     * Delete ourselves if we've been destroyed and return true, else return false
     */
    bool removeIfDestroyed (void);

    /**
     * Sets this object's pivot to the given value, which will then exert a force on this object
     */
    void setPivot (PhysicsObject *pivot);

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

    /**
     * Compute the force that this object (as a pivot) exerts on the given object
     */
    virtual float getPivotForce (PhysicsObject *bob);

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

struct Derivative {
    Vector dx; // Velocity
    Vector dv; // Acceleration
};

/**
 * 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