485 lines
18 KiB
C++
485 lines
18 KiB
C++
#include "Object.h"
|
|
|
|
#include <limits>
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
using namespace ::Oyster::Math;
|
|
using namespace ::Oyster::Collision;
|
|
using namespace ::Oyster::Game;
|
|
using ::std::string;
|
|
using ::std::vector;
|
|
using ::std::map;
|
|
|
|
namespace GameLogic
|
|
{
|
|
namespace PrivateStatic
|
|
{
|
|
struct EntityFileState
|
|
{
|
|
bool isLoaded;
|
|
vector<unsigned int> bluePrintRef;
|
|
EntityFileState() : isLoaded(false), bluePrintRef() {}
|
|
};
|
|
|
|
map<string, EntityFileState> loadedEntityFileLibrary;
|
|
map<string, unsigned int> blueprintIndex = map<string, unsigned int>();
|
|
vector<InstanceBlueprint*> blueprint = vector<InstanceBlueprint*>();
|
|
const InstanceBlueprint invalidBluePrint = InstanceBlueprint();
|
|
unsigned int numCreatedObjects = 0;
|
|
|
|
class WatchDog
|
|
{
|
|
public:
|
|
WatchDog( ) {}
|
|
~WatchDog( )
|
|
{
|
|
vector<InstanceBlueprint*>::size_type numBluePrints = PrivateStatic::blueprint.size();
|
|
for( vector<InstanceBlueprint*>::size_type i = 0; i < numBluePrints; ++i ) delete PrivateStatic::blueprint[i];
|
|
}
|
|
} watchDog;
|
|
}
|
|
|
|
const unsigned int Object::invalidID = ::std::numeric_limits<unsigned int>::max();
|
|
|
|
Object::Result Object::init( const string &iniFile )
|
|
{/*
|
|
if( PrivateStatic::blueprint.size() > 0 )
|
|
{ // ReInit friendly
|
|
vector<InstanceBlueprint*>::size_type numBluePrints = PrivateStatic::blueprint.size();
|
|
for( vector<InstanceBlueprint*>::size_type i = 0; i < numBluePrints; ++i ) delete PrivateStatic::blueprint[i];
|
|
PrivateStatic::blueprint = vector<InstanceBlueprint*>();
|
|
}*/
|
|
|
|
// remove?
|
|
return Success;
|
|
}
|
|
|
|
Object::Result Object::importEntities( vector<unsigned int> &outputConfigID, const string &entityFile, const Float4x4 &transform )
|
|
{
|
|
outputConfigID.resize( 0 );
|
|
|
|
PrivateStatic::EntityFileState *entityFileState = &PrivateStatic::loadedEntityFileLibrary[entityFile];
|
|
|
|
if( entityFileState->isLoaded )
|
|
{
|
|
outputConfigID = entityFileState->bluePrintRef;
|
|
return Success;
|
|
}
|
|
|
|
vector<InstanceBlueprint*> loadedBlueprint;
|
|
vector<string> loadedBlueprintRefNames;
|
|
if( InstanceBlueprint::loadFromFile( loadedBlueprint, loadedBlueprintRefNames, entityFile, transform ) == InstanceBlueprint::Success )
|
|
{
|
|
vector<InstanceBlueprint*>::size_type i = 0,
|
|
numLoaded = loadedBlueprint.size();
|
|
|
|
for( ; i < numLoaded; ++i )
|
|
{
|
|
outputConfigID.push_back( (unsigned int)PrivateStatic::blueprint.size() );
|
|
PrivateStatic::blueprintIndex[ ::Utility::String::toLowerCase(loadedBlueprintRefNames[i]) ] = (unsigned int)PrivateStatic::blueprint.size();
|
|
PrivateStatic::blueprint.push_back( loadedBlueprint[i] );
|
|
}
|
|
|
|
entityFileState->isLoaded = true;
|
|
entityFileState->bluePrintRef = outputConfigID;
|
|
return Success;
|
|
}
|
|
return Failure;
|
|
}
|
|
|
|
void Object::clearEntityresources( )
|
|
{
|
|
PrivateStatic::loadedEntityFileLibrary.clear();
|
|
|
|
vector<InstanceBlueprint*>::size_type numBluePrints = PrivateStatic::blueprint.size();
|
|
for( vector<InstanceBlueprint*>::size_type i = 0; i < numBluePrints; ++i )
|
|
delete PrivateStatic::blueprint[i];
|
|
|
|
PrivateStatic::blueprint.resize( 0 );
|
|
}
|
|
|
|
unsigned int Object::getNumObjectsCreated( )
|
|
{ return PrivateStatic::numCreatedObjects; }
|
|
|
|
const InstanceBlueprint & Object::getConfig( unsigned int id )
|
|
{
|
|
if( id < PrivateStatic::blueprint.size() )
|
|
return *PrivateStatic::blueprint[id];
|
|
else
|
|
return PrivateStatic::invalidBluePrint;
|
|
}
|
|
|
|
const InstanceBlueprint & Object::getConfig( const ::std::string &handle )
|
|
{
|
|
map<string, unsigned int>::const_iterator i = PrivateStatic::blueprintIndex.find( ::Utility::String::toLowerCase(string(handle)) );
|
|
if( i != PrivateStatic::blueprintIndex.end() )
|
|
return *PrivateStatic::blueprint[i->second];
|
|
else
|
|
return PrivateStatic::invalidBluePrint;
|
|
}
|
|
|
|
void Object::onCollisionAction( Object *visitor, Object *hitEntity )
|
|
{
|
|
if( visitor == hitEntity ) return;
|
|
if( visitor->body.Intersects( &hitEntity->body ) )
|
|
{
|
|
Float3 pushVector = (visitor->body.orientation.v[3].xyz - hitEntity->body.orientation.v[3].xyz).getNormalized();
|
|
pushVector = vectorProjection( visitor->speed, pushVector );
|
|
pushVector *= 2.0f;
|
|
visitor->speed -= pushVector;
|
|
visitor->acceleration=Float3::null;
|
|
}
|
|
}
|
|
|
|
// INSTANCE /////////////////////////////////////////////////////////
|
|
|
|
Object::Object( )
|
|
: MoveAble(), objectID(PrivateStatic::numCreatedObjects++), configID(Object::invalidID),
|
|
physicsID(CollisionHandler<Object>::Reference::invalid), mass(1.0f), disableReduceMovementCount(0),
|
|
disableReduceRotationCount(0), scaling(1.0f, 1.0f, 1.0f), view(Float4x4::identity), world(Float4x4::identity), viewIsOutOfDate(true), worldIsOutOfDate(true)
|
|
{
|
|
this->movementProperty.maxSpeed = this->movementProperty.deAcceleration = this->movementProperty.acceleration.forward = this->movementProperty.acceleration.backward = this->movementProperty.acceleration.horizontal = this->movementProperty.acceleration.vertical = 0.0f;
|
|
this->rotationProperty.maxSpeed = this->rotationProperty.deAcceleration = this->rotationProperty.acceleration.pitch = this->rotationProperty.acceleration.yaw = this->rotationProperty.acceleration.roll = 0.0f;
|
|
}
|
|
|
|
Object::Object( const Object &object )
|
|
: MoveAble(object), objectID(object.objectID), configID(object.configID), physicsID(object.physicsID), mass(object.mass),
|
|
movementProperty(object.movementProperty), rotationProperty(object.rotationProperty),
|
|
disableReduceMovementCount(object.disableReduceMovementCount), disableReduceRotationCount(object.disableReduceRotationCount),
|
|
scaling(object.scaling), view(object.view), world(object.world), viewIsOutOfDate(object.viewIsOutOfDate), worldIsOutOfDate(object.worldIsOutOfDate) {}
|
|
|
|
Object::Object( const Float4x4 &orientation, const Float3 ¢erOfMass )
|
|
: MoveAble(orientation, centerOfMass), objectID(PrivateStatic::numCreatedObjects++), configID(invalidID),
|
|
physicsID(CollisionHandler<Object>::Reference::invalid), mass(1.0f), disableReduceMovementCount(0),
|
|
disableReduceRotationCount(0), scaling(1.0f, 1.0f, 1.0f), view(Float4x4::identity), world(Float4x4::identity), viewIsOutOfDate(true), worldIsOutOfDate(true)
|
|
{ this->movementProperty.maxSpeed = this->movementProperty.deAcceleration = this->movementProperty.acceleration.forward = this->movementProperty.acceleration.backward = this->movementProperty.acceleration.horizontal = this->movementProperty.acceleration.vertical = 0.0f; }
|
|
|
|
Object::Object( const Box &body, const Float3 ¢erOfMass )
|
|
: MoveAble(body, centerOfMass), objectID(PrivateStatic::numCreatedObjects++), configID(invalidID),
|
|
physicsID(CollisionHandler<Object>::Reference::invalid), mass(1.0f), disableReduceMovementCount(0),
|
|
disableReduceRotationCount(0), scaling(1.0f, 1.0f, 1.0f), view(Float4x4::identity), world(Float4x4::identity), viewIsOutOfDate(true), worldIsOutOfDate(true)
|
|
{
|
|
this->movementProperty.maxSpeed = this->movementProperty.deAcceleration = this->movementProperty.acceleration.forward = this->movementProperty.acceleration.backward = this->movementProperty.acceleration.horizontal = this->movementProperty.acceleration.vertical = 0.0f;
|
|
this->rotationProperty.maxSpeed = this->rotationProperty.deAcceleration = this->rotationProperty.acceleration.pitch = this->rotationProperty.acceleration.yaw = this->rotationProperty.acceleration.roll = 0.0f;
|
|
}
|
|
|
|
Object::~Object( ) {}
|
|
|
|
Object & Object::operator = ( const Object &object )
|
|
{
|
|
MoveAble::operator=(object);
|
|
this->objectID = object.objectID;
|
|
this->configID = object.configID;
|
|
this->physicsID = object.physicsID;
|
|
this->mass = object.mass;
|
|
this->movementProperty = object.movementProperty;
|
|
this->rotationProperty = object.rotationProperty;
|
|
this->disableReduceMovementCount = object.disableReduceMovementCount;
|
|
this->disableReduceRotationCount = object.disableReduceRotationCount;
|
|
this->scaling = object.scaling;
|
|
|
|
if( !object.viewIsOutOfDate )
|
|
this->view = object.view;
|
|
if( !object.worldIsOutOfDate )
|
|
this->world = object.world;
|
|
this->viewIsOutOfDate = object.viewIsOutOfDate;
|
|
this->worldIsOutOfDate = object.worldIsOutOfDate;
|
|
|
|
return *this;
|
|
}
|
|
|
|
Object * Object::clone( ) const
|
|
{ return new Object(*this); }
|
|
|
|
Object::Type Object::getType( ) const
|
|
{ return Undefined; }
|
|
|
|
const unsigned int & Object::getObjectID( ) const
|
|
{ return this->objectID; }
|
|
|
|
const unsigned int & Object::getConfigID( ) const
|
|
{ return this->configID; }
|
|
|
|
const CollisionHandler<Object>::Reference & Object::getPhysicsID( ) const
|
|
{ return this->physicsID; }
|
|
|
|
const Float & Object::getMass( ) const
|
|
{ return this->mass; }
|
|
|
|
const Float3 & Object::getCenterOfMass( ) const
|
|
{ return this->rotationPivot; }
|
|
|
|
Float3 Object::getInertia( const Float3 &offset ) const
|
|
{ return MoveAble::getMovement( offset ) *= this->mass; }
|
|
|
|
const Box & Object::getCollisionBox( ) const
|
|
{ return this->body; }
|
|
|
|
bool Object::isActive( ) const
|
|
{ return this->physicsID.isActive(); }
|
|
|
|
void Object::setConfig( unsigned int id )
|
|
{
|
|
this->configID = id;
|
|
this->loadConfig();
|
|
}
|
|
|
|
void Object::setConfig( const ::std::string &id )
|
|
{
|
|
map<string, unsigned int>::const_iterator ref = PrivateStatic::blueprintIndex.find( ::Utility::String::toLowerCase(string(id)) );
|
|
if( ref != PrivateStatic::blueprintIndex.end() )
|
|
{
|
|
this->configID = ref->second;
|
|
this->loadConfig();
|
|
}
|
|
}
|
|
|
|
void Object::loadConfig( )
|
|
{
|
|
if( this->configID != Object::invalidID )
|
|
this->loadConfig( *PrivateStatic::blueprint[this->configID] );
|
|
}
|
|
|
|
void Object::setPhysicsID( const CollisionHandler<Object>::Reference &id )
|
|
{ this->physicsID = id; }
|
|
|
|
void Object::setMass( const Float &mass )
|
|
{ this->mass = mass; }
|
|
|
|
void Object::setCenterOfMass( const Float3 &localPos )
|
|
{ this->rotationPivot = localPos; }
|
|
|
|
void Object::setScaling( const ::Oyster::Math::Float3 &scaleL )
|
|
{
|
|
this->body.boundingOffset.x /= this->scaling.x;
|
|
this->body.boundingOffset.y /= this->scaling.y;
|
|
this->body.boundingOffset.z /= this->scaling.z;
|
|
this->body.boundingOffset *= scaleL;
|
|
|
|
if( this->physicsID != CollisionHandler<Object>::Reference::invalid )
|
|
this->physicsID.setBoundaryReach( this->body.boundingOffset.length() );
|
|
|
|
this->scaling = scaleL;
|
|
this->worldIsOutOfDate = this->viewIsOutOfDate = true;
|
|
}
|
|
|
|
void Object::applyForceL( const Float3 &localForce, const Float3 &localPos )
|
|
{ MoveAble::accelerate( localForce / this->mass, localPos ); }
|
|
|
|
void Object::applyForceW( const Float3 &worldForce, const Float3 &worldPos )
|
|
{
|
|
Float4 localForce, localPos;
|
|
transformVector( localForce, Float4(worldForce, 0.0f), this->getViewNormalMatrix() );
|
|
transformVector( localPos, Float4(worldPos, 1.0f), this->getViewPointMatrix() );
|
|
|
|
MoveAble::accelerate( localForce.xyz / this->mass, localPos.xyz );
|
|
}
|
|
|
|
void Object::moveToLimbo( )
|
|
{
|
|
Float4x4 m = this->getOrientation();
|
|
m.v[0]=m.v[1]=m.v[2]=m.v[3] = Float4::null;
|
|
this->setOrientation(m);
|
|
this->stop();
|
|
this->physicsID.moveToLimbo();
|
|
}
|
|
|
|
void Object::releaseFromLimbo( )
|
|
{
|
|
this->physicsID.leaveLimbo();
|
|
}
|
|
|
|
void Object::update( )
|
|
{
|
|
// Speed Control
|
|
Float speedSquared = this->speed.dot( this->speed );
|
|
|
|
if( speedSquared > ( this->movementProperty.maxSpeed * this->movementProperty.maxSpeed ) )
|
|
{ // drop the speed to max and kill acceleration this update
|
|
this->speed *= ( this->movementProperty.maxSpeed / ::std::sqrt(speedSquared) );
|
|
//this->acceleration = Float3::null;
|
|
}
|
|
if( this->disableReduceMovementCount == 0 )
|
|
{ // kill movement if moving slow enough, or deAccelerate
|
|
Float deAccelerate = this->movementProperty.deAcceleration * MoveAble::getDiscreteTimeSlice();
|
|
|
|
if( speedSquared <= ( deAccelerate * deAccelerate ) )
|
|
this->speed = Float3::null;
|
|
else
|
|
{
|
|
speedSquared = ::std::sqrt(speedSquared);
|
|
this->speed *= (speedSquared - deAccelerate) / speedSquared;
|
|
}
|
|
}
|
|
|
|
// Rotation Control
|
|
speedSquared = this->rotationalSpeed.dot( this->rotationalSpeed );
|
|
|
|
if( speedSquared > ( this->rotationProperty.maxSpeed * this->rotationProperty.maxSpeed ) )
|
|
{ // drop the rotationSpeed to max and kill acceleration this update
|
|
this->rotationalSpeed *= ( this->rotationProperty.maxSpeed / ::std::sqrt(speedSquared) );
|
|
this->rotationalAcceleration = Float3::null;
|
|
}
|
|
if( this->disableReduceRotationCount == 0 )
|
|
{ // kill rotation if moving slow enough, or deAccelerate
|
|
Float deAccelerate = this->rotationProperty.deAcceleration * MoveAble::getDiscreteTimeSlice();
|
|
|
|
if( speedSquared <= ( deAccelerate * deAccelerate ) )
|
|
this->rotationalSpeed = Float3::null;
|
|
else
|
|
{
|
|
speedSquared = ::std::sqrt(speedSquared);
|
|
this->rotationalSpeed *= (speedSquared - deAccelerate) / speedSquared;
|
|
}
|
|
}
|
|
|
|
MoveAble::update();
|
|
if( this->physicsID != CollisionHandler<Object>::Reference::invalid )
|
|
this->physicsID.setPosition( this->body.orientation.v[3].xyz );
|
|
this->worldIsOutOfDate = this->viewIsOutOfDate = true;
|
|
}
|
|
|
|
void Object::pitchUp( )
|
|
{ this->accelerateTurn( this->body.orientation.v[0].xyz * -this->rotationProperty.acceleration.pitch ); }
|
|
|
|
void Object::pitchDown( )
|
|
{ this->accelerateTurn( this->body.orientation.v[0].xyz * this->rotationProperty.acceleration.pitch ); }
|
|
|
|
void Object::yawLeft( )
|
|
{ this->accelerateTurn( this->body.orientation.v[1].xyz * -this->rotationProperty.acceleration.yaw ); }
|
|
|
|
void Object::yawRight( )
|
|
{ this->accelerateTurn( this->body.orientation.v[1].xyz * this->rotationProperty.acceleration.yaw ); }
|
|
|
|
void Object::rollLeft( )
|
|
{ this->accelerateTurn( this->body.orientation.v[2].xyz * this->rotationProperty.acceleration.roll ); }
|
|
|
|
void Object::rollRight( )
|
|
{ this->accelerateTurn( this->body.orientation.v[2].xyz * -this->rotationProperty.acceleration.roll ); }
|
|
|
|
void Object::thrustForward( )
|
|
{ this->accelerate( this->body.orientation.v[2].xyz * this->movementProperty.acceleration.forward ); }
|
|
|
|
void Object::thrustBackward( )
|
|
{ this->accelerate( this->body.orientation.v[2].xyz * -this->movementProperty.acceleration.backward ); }
|
|
|
|
void Object::strafeLeft( )
|
|
{ this->accelerate( this->body.orientation.v[0].xyz * -this->movementProperty.acceleration.horizontal ); }
|
|
|
|
void Object::strafeRight( )
|
|
{ this->accelerate( this->body.orientation.v[0].xyz * this->movementProperty.acceleration.horizontal ); }
|
|
|
|
void Object::climb( )
|
|
{ this->accelerate( this->body.orientation.v[1].xyz * this->movementProperty.acceleration.vertical ); }
|
|
|
|
void Object::dive( )
|
|
{ this->accelerate( this->body.orientation.v[1].xyz * -this->movementProperty.acceleration.vertical ); }
|
|
|
|
void Object::disableMovementReduction( )
|
|
{ ++this->disableReduceMovementCount; }
|
|
|
|
void Object::enableMovementReduction( bool forceIt )
|
|
{
|
|
if( forceIt )
|
|
this->disableReduceMovementCount = 0;
|
|
else if( --this->disableReduceMovementCount < 0) this->disableReduceMovementCount = 0;
|
|
}
|
|
|
|
void Object::disableRotationReduction( )
|
|
{ ++this->disableReduceRotationCount; }
|
|
|
|
void Object::enableRotationReduction( bool forceIt )
|
|
{
|
|
if( forceIt )
|
|
this->disableReduceRotationCount = 0;
|
|
else if( --this->disableReduceRotationCount < 0) this->disableReduceRotationCount = 0;
|
|
}
|
|
|
|
Object::Result Object::writeToKeyFrame( KeyFrame &buffer ) const
|
|
{
|
|
if( buffer.numObjects < (signed)::Utility::StaticArray::numElementsOf( buffer.Objects ) )
|
|
{
|
|
buffer.Objects[buffer.numObjects].id = this->objectID;
|
|
buffer.Objects[buffer.numObjects].TypeId = this->configID;
|
|
buffer.Objects[buffer.numObjects].RotationVec = this->rotationalSpeed;
|
|
buffer.Objects[buffer.numObjects].MoveVec = this->speed;
|
|
|
|
//TODO: edit to world when they are avaliable
|
|
buffer.Objects[buffer.numObjects].World = this->body.orientation;
|
|
|
|
//buffer.Objects[buffer.numObjects].ForwardVec = this->body.orientation.v[2].xyz;
|
|
//buffer.Objects[buffer.numObjects].UpVec = this->body.orientation.v[1].xyz;
|
|
|
|
++buffer.numObjects;
|
|
return Success;
|
|
}
|
|
return Failure;
|
|
}
|
|
|
|
const Float4x4 & Object::getWorldPointMatrix( ) const
|
|
{
|
|
if( this->worldIsOutOfDate )
|
|
{
|
|
transformMatrix( this->world,
|
|
Float4x4( Float4::standardUnitX * this->scaling.x,
|
|
Float4::standardUnitY * this->scaling.y,
|
|
Float4::standardUnitZ * this->scaling.z,
|
|
Float4::standardUnitW ),
|
|
this->body.orientation );
|
|
this->worldIsOutOfDate = false;
|
|
}
|
|
return this->world;
|
|
}
|
|
|
|
const Float4x4 & Object::getViewPointMatrix( ) const
|
|
{
|
|
if( this->viewIsOutOfDate )
|
|
{
|
|
this->view = this->getWorldPointMatrix().getInverse();
|
|
this->viewIsOutOfDate = false;
|
|
}
|
|
return this->view;
|
|
}
|
|
|
|
void Object::setOrientation( const Float4x4 & orientation )
|
|
{
|
|
MoveAble::setOrientation( orientation );
|
|
if( this->physicsID != CollisionHandler<Object>::Reference::invalid )
|
|
this->physicsID.setPosition( orientation.v[3].xyz );
|
|
this->worldIsOutOfDate = this->viewIsOutOfDate = true;
|
|
}
|
|
|
|
const InstanceBlueprint & Object::getConfigData( unsigned int configID )
|
|
{ return *PrivateStatic::blueprint[configID]; }
|
|
|
|
void Object::loadConfig( const InstanceBlueprint &config )
|
|
{
|
|
this->mass = (Float)config.mass;
|
|
this->setCenterOfMass( config.centerOfMass );
|
|
this->body.boundingOffset = ::Utility::Value::abs( config.hitBox.position ) + config.hitBox.halfSize;
|
|
|
|
this->movementProperty.maxSpeed = config.movementProperty.maxSpeed;
|
|
this->movementProperty.deAcceleration = config.movementProperty.deAcceleration;
|
|
this->movementProperty.acceleration.forward = config.movementProperty.acceleration.forward;
|
|
this->movementProperty.acceleration.backward = config.movementProperty.acceleration.backward;
|
|
this->movementProperty.acceleration.horizontal = config.movementProperty.acceleration.horizontal;
|
|
this->movementProperty.acceleration.vertical = config.movementProperty.acceleration.vertical;
|
|
|
|
this->rotationProperty.maxSpeed = config.rotationProperty.maxSpeed;
|
|
this->rotationProperty.deAcceleration = config.rotationProperty.deAcceleration;
|
|
this->rotationProperty.acceleration.pitch = config.rotationProperty.acceleration.pitch;
|
|
this->rotationProperty.acceleration.yaw = config.rotationProperty.acceleration.yaw;
|
|
this->rotationProperty.acceleration.roll = config.rotationProperty.acceleration.roll;
|
|
|
|
if( this->physicsID != CollisionHandler<Object>::Reference::invalid )
|
|
this->physicsID.setBoundaryReach( this->body.boundingOffset.length() );
|
|
}
|
|
}
|
|
|
|
namespace Oyster { namespace Game
|
|
{
|
|
template <>
|
|
bool CollisionHandler<::GameLogic::Object>::simpleCollisionConfirmation( const typename ::GameLogic::Object &entity, const ::Oyster::Collision::ICollideable *sampler )
|
|
{ return sampler->Intersects( &entity.getCollisionBox() ); }
|
|
} } |