mirror of
https://github.com/thug1src/thug.git
synced 2024-12-02 12:56:45 +00:00
305 lines
10 KiB
C
305 lines
10 KiB
C
|
//****************************************************************************
|
||
|
//* MODULE: Gel/Components
|
||
|
//* FILENAME: RigidBodyComponent.h
|
||
|
//* OWNER: Dan
|
||
|
//* CREATION DATE: 1/22/3
|
||
|
//****************************************************************************
|
||
|
|
||
|
#ifndef __COMPONENTS_RIGIDBODYCOMPONENT_H__
|
||
|
#define __COMPONENTS_RIGIDBODYCOMPONENT_H__
|
||
|
|
||
|
#include <core/defines.h>
|
||
|
#include <core/support.h>
|
||
|
|
||
|
#include <gel/object/basecomponent.h>
|
||
|
#include <gel/collision/collcache.h>
|
||
|
|
||
|
#define CRC_RIGIDBODY CRCD(0xffb39248, "RigidBody")
|
||
|
#define GetRigidBodyComponent() ((Obj::CRigidBodyComponent*)GetComponent(CRC_RIGIDBODY))
|
||
|
#define GetRigidBodyComponentFromObject(pObj) ((Obj::CRigidBodyComponent*)(pObj)->GetComponent(CRC_RIGIDBODY))
|
||
|
|
||
|
#define vRP_GRAVITATIONAL_ACCELERATION (-386.4f)
|
||
|
#define vRP_DEFAULT_MASS_OVER_MOMENT (0.003f)
|
||
|
#define vRP_DEFAULT_COEFF_RESTITUTION (0.4f)
|
||
|
#define vRP_DEFAULT_COEFF_FRICTION (0.5f)
|
||
|
#define vRP_DEFAULT_SPRING_CONST (10.0f)
|
||
|
#define vRP_DEFAULT_SKATER_COLLISION_RADIUS (12.0f + 36.0f)
|
||
|
#define vRP_DEFAULT_SKATER_COLLISION_APPLICATION_RADIUS (12.0f)
|
||
|
#define vRP_DEFAULT_SKATER_COLLISION_ASSENT (25.0f)
|
||
|
#define vRP_DEFAULT_SKATER_COLLISION_IMPULSE_FACTOR (1.0f)
|
||
|
#define vRP_DEFAULT_SKATER_COLLISION_ROTATION_FACTOR (1.0f)
|
||
|
#define vRP_SKATER_COLLISION_VELOCITY_FACTOR (1.0f)
|
||
|
#define vRP_SKATER_COLLISION_VELOCITY_THRESHOLD_INCREMENT (50.0f)
|
||
|
#define vRP_DEFAULT_LINEAR_VELOCITY_SLEEP_POINT (10.0f)
|
||
|
#define vRP_DEFAULT_ANGULAR_VELOCITY_SLEEP_POINT (0.4f)
|
||
|
#define vRP_DEFAULT_IGNORE_SKATER_DURATION (5.0f / 60.0f)
|
||
|
#define vRP_DEFAULT_COLLIDE_MUTE_DELAY (1000)
|
||
|
#define vRP_DEFAULT_GLOBAL_COLLIDE_MUTE_DELAY (100)
|
||
|
#define vRP_DEFAULT_BOUNCE_VELOCITY_CALLBACK_THRESHOLD (20.0f)
|
||
|
#define vRP_DEFAULT_BOUNCE_VELOCITY_FULL_SPEED (300.0f)
|
||
|
|
||
|
namespace Script
|
||
|
{
|
||
|
class CScript;
|
||
|
class CStruct;
|
||
|
}
|
||
|
|
||
|
namespace Obj
|
||
|
{
|
||
|
class CSoundComponent;
|
||
|
|
||
|
class CRigidBodyComponent : public CBaseComponent
|
||
|
{
|
||
|
enum ERigidBodyStateType
|
||
|
{
|
||
|
ASLEEP, AWAKE
|
||
|
};
|
||
|
|
||
|
enum EObjectGeometryType
|
||
|
{
|
||
|
BOX, PYRAMID, CYLINDER, TRIANGLE, NO_GEOMETRY
|
||
|
};
|
||
|
|
||
|
enum EFlagType
|
||
|
{
|
||
|
DIE_UPON_SLEEP,
|
||
|
PLAYER_COLLISION_DISABLED
|
||
|
};
|
||
|
|
||
|
struct SContact
|
||
|
{
|
||
|
// defining element of a rigidbody contact point; position
|
||
|
Mth::Vector p;
|
||
|
|
||
|
// the axis of friction
|
||
|
Mth::Vector friction_direction;
|
||
|
|
||
|
// if friction at this contact occurs only along a single axis
|
||
|
char directed_friction;
|
||
|
};
|
||
|
|
||
|
struct SContactState
|
||
|
{
|
||
|
// offset to the contact point in world space
|
||
|
Mth::Vector p_world;
|
||
|
|
||
|
// normal of the surface is it colliding with
|
||
|
Mth::Vector normal;
|
||
|
|
||
|
// the effective mass of this contact for impulses applied along the normal
|
||
|
float normal_eff_mass;
|
||
|
|
||
|
// keeps track of the total impulse magnitude of the normal force in a frame; used to limit the frictional impulse
|
||
|
float normal_impulse_magnitude;
|
||
|
|
||
|
// depth of the contact; negative corresponds to interpenetration
|
||
|
float depth;
|
||
|
|
||
|
// is this contact in collision
|
||
|
char collision;
|
||
|
|
||
|
// false before the normal_inv_mass has been set
|
||
|
char normal_eff_mass_set;
|
||
|
};
|
||
|
|
||
|
// if the number of free voices is this number or less, don't play bounce sounds
|
||
|
static const int vRP_NUM_UNTOUCHABLE_VOICES = 12;
|
||
|
|
||
|
// maximum number of contacts allowed on a single rigidbody
|
||
|
static const unsigned int vRP_MAX_NUM_CONTACTS = 24;
|
||
|
|
||
|
public:
|
||
|
CRigidBodyComponent();
|
||
|
virtual ~CRigidBodyComponent();
|
||
|
|
||
|
public:
|
||
|
virtual void Update();
|
||
|
virtual void InitFromStructure( Script::CStruct* pParams );
|
||
|
virtual void Finalize();
|
||
|
|
||
|
virtual EMemberFunctionResult CallMemberFunction( uint32 Checksum, Script::CStruct* pParams, Script::CScript* pScript );
|
||
|
virtual void GetDebugInfo( Script::CStruct* p_info );
|
||
|
|
||
|
static CBaseComponent* s_create();
|
||
|
|
||
|
static void sToggleDrawRigidBodyDebugLines ( );
|
||
|
|
||
|
private:
|
||
|
|
||
|
void setup_contact_states ( );
|
||
|
void handle_skater_collisions ( );
|
||
|
void update_dynamic_state ( float time_step );
|
||
|
void consider_sleeping ( );
|
||
|
void wake ( );
|
||
|
void sleep ( );
|
||
|
bool detect_collisions ( );
|
||
|
float calculate_effective_mass ( const Mth::Vector& direction, const SContactState& contact_state ) const;
|
||
|
void resolve_collisions ( );
|
||
|
void draw_debug_lines ( ) const;
|
||
|
void get_sound_setup ( uint32 sound_type_id );
|
||
|
void setup_contacts_as_box ( const Mth::Vector& top_half_dimensions, const Mth::Vector& bottom_half_dimensions );
|
||
|
void setup_contacts_as_pyramid ( float radius, float half_depth );
|
||
|
void setup_contacts_as_cylinder ( float top_radius, float bottom_radius, float half_depth, int edges = 6 );
|
||
|
void setup_contacts_as_triangle ( const Mth::Vector& half_dimensions );
|
||
|
void setup_contacts_from_array ( Script::CArray *pArray );
|
||
|
|
||
|
private:
|
||
|
|
||
|
// properties:
|
||
|
|
||
|
// object's don't have masses or moments of inertia;
|
||
|
// instead, a single scalar is used for the moment of inertia and only the ratio of mass over moment is used;
|
||
|
// this ratio controls the object's relative tendency to move linearly or rotationally;
|
||
|
// if proper external forces are ever applied to rigidbodies, they will need a mass;
|
||
|
// units are inverse inches squared; should be on the order of the inverse of the square of the characteristic
|
||
|
// distance between the contact points and the center of mass
|
||
|
float m_mass_over_moment;
|
||
|
|
||
|
// object's acceleration due to constant force on its center of mass (gravity)
|
||
|
float m_const_acc;
|
||
|
|
||
|
// coefficient of restitution; bounce factor
|
||
|
float m_coeff_restitution;
|
||
|
|
||
|
// coefficient of friction
|
||
|
float m_coeff_friction;
|
||
|
|
||
|
// spring constant used to prevent interpenetration
|
||
|
float m_spring_const;
|
||
|
|
||
|
// effectively the sum of the object radius and the skater radius; when the center-to-center distance is below this, there is a collision
|
||
|
float m_skater_collision_radius;
|
||
|
|
||
|
// effectively the radius of the object; the impulse is applied at this distance from the object; to have reasonable rotations, m_mass_over_moment
|
||
|
// should on the order of the inverse of this radius squared; also used in skater collisions to check their Y-interception
|
||
|
float m_skater_collision_application_radius;
|
||
|
|
||
|
// sine and cosine of the angle of assent of the skater collision impulse
|
||
|
float m_cos_skater_collision_assent;
|
||
|
float m_sin_skater_collision_assent;
|
||
|
|
||
|
// factor which adjusts the magnitude of skater collision impulses; sort of like an inverse mass
|
||
|
float m_skater_collision_impulse_factor;
|
||
|
|
||
|
// scales the rotation the object gains from a collision with the skater
|
||
|
float m_skater_collision_rotation_factor;
|
||
|
|
||
|
// if the velocities are below these points, the object may go to sleep
|
||
|
float m_linear_velocity_sleep_point_sqr;
|
||
|
float m_angular_velocity_sleep_point_sqr;
|
||
|
|
||
|
// currently, we assume a box; the algorithm is general enough to do anything
|
||
|
SContact* mp_contacts;
|
||
|
unsigned short m_num_contacts;
|
||
|
|
||
|
// center of mass of the object
|
||
|
Mth::Vector m_center_of_mass;
|
||
|
|
||
|
// offset from the center of mass to the origin of the model
|
||
|
Mth::Vector m_model_offset;
|
||
|
|
||
|
// number of frames after a skater collision before we begin checking for skater collisions again
|
||
|
float m_ignore_skater_duration;
|
||
|
|
||
|
// callback script names
|
||
|
struct SScriptCallbackNames
|
||
|
{
|
||
|
uint32 collide;
|
||
|
uint32 bounce;
|
||
|
uint32 settle;
|
||
|
uint32 stuck;
|
||
|
} m_script_names;
|
||
|
|
||
|
// parameter structure passed to callback scripts
|
||
|
Script::CStruct* mp_script_params;
|
||
|
|
||
|
// sound setup
|
||
|
struct SSoundSetup
|
||
|
{
|
||
|
Script::CStruct* collide_sound;
|
||
|
Script::CStruct* bounce_sound;
|
||
|
Tmr::Time collide_mute_delay;
|
||
|
Tmr::Time global_collide_mute_delay;
|
||
|
float bounce_velocity_callback_threshold;
|
||
|
float bounce_velocity_full_speed;
|
||
|
} m_sound_setup;
|
||
|
|
||
|
// time when the next collide sound is allowed
|
||
|
Tmr::Time m_collide_sound_allowed_time;
|
||
|
|
||
|
// time when the any next collide sound is allowed
|
||
|
static Tmr::Time s_collide_sound_allowed_time;
|
||
|
|
||
|
// used to allow dynamic updating of sounds
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
uint32 m_sound_type_id;
|
||
|
#endif
|
||
|
|
||
|
// property flags
|
||
|
Flags<EFlagType> m_flags;
|
||
|
|
||
|
// position at which we were last woke
|
||
|
Mth::Vector m_wake_pos;
|
||
|
|
||
|
// countdown to dying; not active if set to -1.0f
|
||
|
float m_die_countdown;
|
||
|
|
||
|
// primary state variables:
|
||
|
|
||
|
// object's state; objects sleep when they are not active
|
||
|
ERigidBodyStateType m_state;
|
||
|
|
||
|
// object's center of mass position
|
||
|
Mth::Vector m_pos;
|
||
|
|
||
|
// object's velocity
|
||
|
Mth::Vector m_vel;
|
||
|
|
||
|
// object's orientation around center of mass
|
||
|
Mth::Quat m_orientation;
|
||
|
|
||
|
// object's angular velocity
|
||
|
Mth::Vector m_rotvel;
|
||
|
|
||
|
// dependent state variables:
|
||
|
|
||
|
// rotation matrix based on our orientation
|
||
|
Mth::Matrix m_matrix;
|
||
|
|
||
|
// number of contacts in current collision
|
||
|
char m_num_collisions;
|
||
|
|
||
|
// count down used to time the interval between a skater collision and the point when we begin looking for skater collisions again
|
||
|
float m_ignore_skater_countdown;
|
||
|
|
||
|
// work variables:
|
||
|
|
||
|
// collision cache; used to improve collision detection turn-around time; shared by all rigidbodies
|
||
|
static Nx::CCollCache s_collision_cache;
|
||
|
|
||
|
// longest distance between a contact point and the center of mass; used to generate the collision cache's bounding box
|
||
|
float m_largest_contact_extent;
|
||
|
|
||
|
// debug variables
|
||
|
static bool s_debug_lines_on;
|
||
|
static bool s_draw_skater_collision_circles;
|
||
|
|
||
|
// height of the skater; used when determining skater collisions and resulting impulse point of application
|
||
|
static float s_skater_head_height;
|
||
|
|
||
|
// to save memory, the rigidbodies share an array of structures which hold the state of their contacts during collision resolution
|
||
|
static SContactState sp_contact_states [ vRP_MAX_NUM_CONTACTS ];
|
||
|
|
||
|
#ifdef __NOPT_DEBUG__
|
||
|
// insures that only a single rigidbody is using sp_contact_states at a time
|
||
|
static bool s_contact_states_in_use;
|
||
|
#endif
|
||
|
|
||
|
// peer components
|
||
|
CSoundComponent* mp_sound_component;
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif
|