mcaden
04-10-2008 20:01:14
I'm not quite ready yet on the blender importer but here's the bulk of the physics stuff:
That sets all the physics properties...then you react accordingly to use the correct class:
Right now my XML has a player node:
And it reads in both the physics properties, AND the extra player properties I specified in the second function and applies them accordingly.
For a player class this basically means I don't have to recompile each time I edit or add a new attack or if I change the name of a bone or something for a particle emitter. Not as big a deal...but when I start adding enemies all with their own attacks and particles along with adding AI properties for aggression, sight range, movement speed, etc...the time saved and ease of editing will really add up.
Right now my terrain and enemy are using the default Body class...later on they'll use <Terrain> and <Enemy> through the new body templating system available in '22.
Eventually I soon hope to release full code to the community for a dotScene importer with physics capabilities, but I wanted to get some feedback first.
void DotSceneLoader::parsePhysicsProperties(SceneNode* pNode, Entity* mesh, vector<NodeProperty> props)
{
char* sizeValue = new char[5];
String size = itoa( props.size(), sizeValue, 10 );
LogManager::getSingleton().logMessage( "object " + pNode->getName() + " has " + size + " properties" );
NodeRenderableParams renderParams;
renderParams.setToDefault();
renderParams.mGraphicsModel = mesh->getName();
renderParams.mGraphicsModelScale = NxVec3(1, 1, 1);
renderParams.mIdentifier = pNode->getName();
renderParams.mIdentifierUsage = renderParams.IU_Use;
renderParams.mMode = RenderableSource::RM_Interpolate;
ActorParams actorParams;
actorParams.setToDefault();
actorParams.mMass = 10;
actorParams.mDensity = 0;
actorParams.mLinearDamping = 5;
actorParams.mAngularDamping = 5;
//actorParams.mGroup = "default";
vector<NodeProperty> classProperties;
DOTSCENE_OBJECT_TYPE objectType = DS_NXOBTYPE_UNSET;
DOTSCENE_COLLISION_TYPE collisionType = DS_NXCOLTYPE_UNSET;
Real collisionSize = 1;
while( props.size() > 0 )
{
NodeProperty prop = props.back();
props.pop_back();
if( prop.propertyNm == "ObType" )
{
if( prop.valueName == "Player" )
objectType = DS_NXOBTYPE_PLAYER;
else if( prop.valueName == "Terrain" )
{
objectType = DS_NXOBTYPE_TERRAIN;
actorParams.mMass = 0;
actorParams.Static( true );
collisionType = DS_NXCOLTYPE_TRIANGLE;
}
else if( prop.valueName == "Generic_Dynamic" )
objectType = DS_NXOBTYPE_GENERIC_DYNAMIC;
else if( prop.valueName == "Generic_Static" )
objectType = DS_NXOBTYPE_GENERIC_STATIC;
}
else if( prop.propertyNm == "ColType" )
{
if( prop.valueName == "Sphere" )
collisionType = DS_NXCOLTYPE_SPHERE;
else if( prop.valueName == "Triangle" )
collisionType = DS_NXCOLTYPE_TRIANGLE;
else if( prop.valueName == "Convex" )
collisionType = DS_NXCOLTYPE_CONVEX;
else
collisionType = DS_NXCOLTYPE_CUBE;
}
else if( prop.propertyNm == "ColSize" )
{
collisionSize = atof( prop.valueName.c_str() );
}
else if( prop.propertyNm == "LinearDamping" )
{
actorParams.mLinearDamping = atof( prop.valueName.c_str() );
}
else if( prop.propertyNm == "AngularDamping" )
{
actorParams.mAngularDamping = atof( prop.valueName.c_str() );
}
else if( prop.propertyNm == "Mass" )
{
actorParams.mMass = atof( prop.valueName.c_str() );
}
else if( prop.propertyNm == "Group" )
{
actorParams.mGroup = prop.valueName;
}
else if( prop.propertyNm == "FreezeRotX" )
{
actorParams.mFreeze.mRotation.x = true;
}
else if( prop.propertyNm == "FreezeRotY" )
{
actorParams.mFreeze.mRotation.y = true;
}
else if( prop.propertyNm == "FreezeRotZ" )
{
actorParams.mFreeze.mRotation.z = true;
}
else
{
classProperties.push_back( prop );
}
}
Shape* collisionShape = NULL;
if( collisionType == DS_NXCOLTYPE_TRIANGLE || collisionType == DS_NXCOLTYPE_CONVEX )
{
Ogre::String collisionMesh;
collisionMesh = mesh->getMesh()->getName() + ".nxs"; // ____.mesh.nxs is the file format..easily changeable
NxOgre::Resources::ResourceSystem::getSingleton()->addMesh("file://" + collisionMesh); //set the path here
if( collisionType == DS_NXCOLTYPE_TRIANGLE )
collisionShape = new TriangleMesh(NxOgre::Resources::ResourceSystem::getSingleton()->getMesh( collisionMesh ));
else
collisionShape = new Convex( NxOgre::Resources::ResourceSystem::getSingleton()->getMesh( collisionMesh ) );
}
else if( collisionType == DS_NXCOLTYPE_SPHERE )
{
collisionShape = new NxOgre::Sphere( collisionSize );
}
else //If shape isn't specified, or there's an error - default to ( collisionType == DS_NXCOLTYPE_CUBE )
{
Ogre::AxisAlignedBox meshBounds = pNode->getAttachedObject( mesh->getName() )->getBoundingBox();
collisionShape = new Cube( meshBounds.getSize() );
}
createPhysXObject( pNode, classProperties, objectType, collisionShape,
actorParams, renderParams );
}
That sets all the physics properties...then you react accordingly to use the correct class:
void DotSceneLoader::createPhysXObject( SceneNode* node, vector<NodeProperty> props, DOTSCENE_OBJECT_TYPE objectType,
Shape* collisionShape, ActorParams actorParams,
NodeRenderableParams renderParams )
{
vector<NodeProperty> unusedClassProperties;
NxOgre::Pose actorPose( node->getPosition(), node->getOrientation() );
switch( objectType )
{
case( DS_NXOBTYPE_TERRAIN ):
try
{
Actor* myActor = mScene->createBody<Body>(renderParams.mIdentifier,
collisionShape, actorPose, renderParams, actorParams);
myActor->setGroup( mScene->getActorGroup( "terrain" ) );
LogManager::getSingleton().logMessage( "-= Terrain Object - '" + myActor->getName() + "' created successfully =-" );
}
catch(...)
{
LogManager::getSingleton().logMessage( "-= Terrain Creation Error - Not applying physics to terrain object '" + node->getName() + "' =-" );
}
break;
case( DS_NXOBTYPE_PLAYER ):
try
{
mPlayer = (Player*)mScene->createBody<Player>(renderParams.mIdentifier,
collisionShape, actorPose, renderParams, actorParams);
mPlayer->setGroup( mScene->getActorGroup( "player" ) );
LogManager::getSingleton().logMessage( "-= Player Object - '" + mPlayer->getName() + "' created successfully =-" );
mPlayer->initialize( mSceneMgr, (Entity*)node->getAttachedObject( node->getName() ), 200, 50.0f, mSceneMgr->getCameraIterator().getNext() );
while( props.size() > 0 )
{
NodeProperty prop = props.back();
props.pop_back();
if( StringUtil::startsWith( prop.propertyNm, "attack" ) )
{
vector<String>params = StringUtil::split( prop.valueName, "," );
if( params.size() == 4 )
{
mPlayer->addAttack( params.at(0), params.at(1),
StringConverter::parseInt( params.at( 2 )),
StringConverter::parseVector3( params.at( 3 )) );
}
else if( params.size() == 3 )
{
mPlayer->addAttack( params.at(0), params.at(1),
StringConverter::parseInt( params.at( 2 )));
}
}
else if( StringUtil::startsWith( prop.propertyNm, "particle" ) )
{
vector<String>params = StringUtil::split( prop.valueName, "," );
if( params.size() == 3 )
{
mPlayer->attachParticles( params.at(0), params.at(1), params.at(2) );
}
}
else
{
unusedClassProperties.push_back( prop );
}
}
LogManager::getSingleton().logMessage( "-= Player Creation Completed with '" + StringConverter::toString( unusedClassProperties.size() ) + "' unused properties =-" );
Light* mLight = mSceneMgr->createLight("Light2");
mLight->setType(Ogre::Light::LT_POINT);
mLight->setPosition( 0, 0, 1 );
mLight->setAttenuation( 32, 0.00000, 0.100000, 0.070000 );
mLight->setDiffuseColour( 0.39, 1.0, 0.39 );
mLight->setSpecularColour( 0.0, 1.0, 0.0 );
mPlayer->attachObject( "Torso", mLight );
mPlayer->cameraPitch( Ogre::Degree(40) );
}
catch(...)
{
LogManager::getSingleton().logMessage( "-= Player Creation Error - Exception thrown on player object '" + node->getName() + "' =-" );
}
break;
case( DS_NXOBTYPE_GENERIC_STATIC ):
case( DS_NXOBTYPE_GENERIC_DYNAMIC ):
case( DS_NXOBTYPE_UNSET ):
if( collisionShape != NULL )
{
try
{
Actor* myActor = mScene->createBody<Body>(renderParams.mIdentifier, collisionShape,
actorPose, renderParams, actorParams);
myActor->setGroup( mScene->getActorGroup( "enemy" ) );
LogManager::getSingleton().logMessage( "-= Generic Physics-Enabled Object - '" + myActor->getName() + "' created successfully =-" );
}
catch(...)
{
LogManager::getSingleton().logMessage( "-= Generic Physics-Enabled Object Creation Error - Not applying physics to object '" + node->getName() + "' =-" );
}
}
break;
}
}
Right now my XML has a player node:
<node name="Garm">
<position x="6.337165" y="0" z="-9.414388"/>
<quaternion x="0.000000" y="-0.325688" z="0.000000" w="0.945477"/>
<scale x="1.000000" y="1.000000" z="1.000000"/>
<entity name="Garm" meshFile="Garm.mesh"/>
<userData>
<property type="FLOAT" name="ColSize" data="1.0"/>
<property type="STRING" name="ColType" data="Cube"/>
<property type="STRING" name="ObType" data="Player"/>
<property type="STRING" name="FreezeRotX" data="true"/>
<property type="STRING" name="FreezeRotZ" data="true"/>
<property type="STRING" name="Mass" data="15"/>
<property type="FLOAT" name="LinearDamping" data="0.0"/>
<property type="FLOAT" name="AngularDamping" data="12.0"/>
<property type="STRING" name="Group" data="player"/>
<property type="STRING" name="Attack1" data="Bite,Bite,30"/>
<property type="STRING" name="Particle1" data="backParticles1,Player/Garm_back,Torso"/>
<property type="STRING" name="Particle2" data="backParticles2,Player/Garm_back2,Torso"/>
<property type="STRING" name="Particle3" data="eyeParticles_L,Player/Garm_eye,Eye_L"/>
<property type="STRING" name="Particle4" data="eyeParticles_R,Player/Garm_eye,Eye_R"/>
</userData>
</node>
And it reads in both the physics properties, AND the extra player properties I specified in the second function and applies them accordingly.
For a player class this basically means I don't have to recompile each time I edit or add a new attack or if I change the name of a bone or something for a particle emitter. Not as big a deal...but when I start adding enemies all with their own attacks and particles along with adding AI properties for aggression, sight range, movement speed, etc...the time saved and ease of editing will really add up.
Right now my terrain and enemy are using the default Body class...later on they'll use <Terrain> and <Enemy> through the new body templating system available in '22.
Eventually I soon hope to release full code to the community for a dotScene importer with physics capabilities, but I wanted to get some feedback first.