rigidShape.cpp
Engine/source/T3D/rigidShape.cpp
Public Variables
Public Functions
ConsoleDocClass(RigidShape , "@brief The <a href="/coding/class/classrigidshape/">RigidShape</a> class implements rigid-body physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> DTS objects in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">world.\n\n</a>" "\"Rigid body physics\" refers <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> a system whereby objects are assumed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have a finite size, \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "equally distributed masses, and where deformations of the objects themselves are not accounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">for.\n</a>" "Uses the <a href="/coding/class/classrigidshape/">RigidShape</a> class <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">physics.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" " datablock <a href="/coding/class/classrigidshapedata/">RigidShapeData</a>(BouncingBoulder)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " category=\"RigidShape\";\n" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " shapeFile = \"~/data/shapes/boulder/boulder.dts\";\n" " emap = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // <a href="/coding/class/classrigid/">Rigid</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Body\n</a>" " mass = 500;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " massCenter = \"0 0 0\"; // Center of mass <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> rigid <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">body\n</a>" " massBox = \"0 0 0\"; // Size of box used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> moment of inertia,\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> zero it defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> object bounding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">box\n</a>" " drag = 0.2; // Drag <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">coefficient\n</a>" " bodyFriction = 0.2;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " bodyRestitution = 0.1;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minImpactSpeed = 5; // Impacts over this invoke the script <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">callback\n</a>" " softImpactSpeed = 5; // Play SoftImpact <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Sound\n</a>" " hardImpactSpeed = 15; // Play HardImpact <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Sound\n</a>" " integration = 4; // Physics integration: <a href="/coding/file/processlist_8h/#processlist_8h_1a6dfddc4b6033c4de60ed37c4fe30f650">TickSec</a>/<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rate\n</a>" " collisionTol = 0.1; // <a href="/coding/class/structcollision/">Collision</a> distance <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tolerance\n</a>" " contactTol = 0.1; // Contact velocity <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tolerance\n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minRollSpeed = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " maxDrag = 0.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minDrag = 0.01;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dustHeight = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dragForce = 0.05;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " vertFactor = 0.05;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classrigidshape/">RigidShape</a>()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dataBlock = \"BouncingBoulder\";\n" " parentGroup = EWCreatorWindow.objectGroup;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RigidShapeData\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBase\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Physics\n</a>" )
ConsoleDocClass(RigidShapeData , "@brief Defines the physics properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an individual <a href="/coding/class/classrigidshapedata/">RigidShapeData</a> physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" " datablock <a href="/coding/class/classrigidshapedata/">RigidShapeData</a>( BouncingBoulder )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " category = \"RigidShape\";\n" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " shapeFile = \"~/data/shapes/boulder/boulder.dts\";\n" " emap = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // <a href="/coding/class/classrigid/">Rigid</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Body\n</a>" " mass = 500;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " massCenter = \"0 0 0\"; // Center of mass <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> rigid <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">body\n</a>" " massBox = \"0 0 0\"; // Size of box used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> moment of inertia,\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> zero it defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> object bounding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">box\n</a>" " drag = 0.2; // Drag <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">coefficient\n</a>" " bodyFriction = 0.2;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " bodyRestitution = 0.1;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minImpactSpeed = 5; // Impacts over this invoke the script <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">callback\n</a>" " softImpactSpeed = 5; // Play SoftImpact <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Sound\n</a>" " hardImpactSpeed = 15; // Play HardImpact <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Sound\n</a>" " integration = 4; // Physics integration: <a href="/coding/file/processlist_8h/#processlist_8h_1a6dfddc4b6033c4de60ed37c4fe30f650">TickSec</a>/<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rate\n</a>" " collisionTol = 0.1; // <a href="/coding/class/structcollision/">Collision</a> distance <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tolerance\n</a>" " contactTol = 0.1; // Contact velocity <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tolerance\n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minRollSpeed = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " maxDrag = 0.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minDrag = 0.01;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dustHeight = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dragForce = 0.05;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " vertFactor = 0.05;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RigidShape\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBase\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Physics\n</a>" )
DefineEngineMethod(RigidShape , forceClientTransform , void , () , "@brief Forces the client <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> jump <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/class/classrigidshape/">RigidShape</a>'s transform rather then warp <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n\n</a>" )
DefineEngineMethod(RigidShape , freezeSim , void , (bool isFrozen) , "@brief Enables or disables the physics simulation on the <a href="/coding/class/classrigidshape/">RigidShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param isFrozen Boolean frozen state <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Define the frozen <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">state.\n</a>" "% isFrozen)
DefineEngineMethod(RigidShape , reset , void , () , "@brief Clears physic forces from the shape and sets it at <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rest.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Inform the <a href="/coding/class/classrigidshape/">RigidShape</a> object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reset.\n</a>" "%thisRigidShape.reset();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/class/structshapebasedata/">ShapeBaseData</a>" )
IMPLEMENT_CALLBACK(RigidShape , onEnterLiquid , void , (const char *objId, F32 waterCoverage, const char *liquidType) , (objId, waterCoverage, liquidType) , "@brief Called whenever this <a href="/coding/class/classrigidshape/">RigidShape</a> object enters <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">liquid.\n\n</a>" "@param objId The ID of the rigidShape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param waterCoverage Amount of water coverage the <a href="/coding/class/classrigidshape/">RigidShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">has.\n</a>" "@param liquidType Type of liquid that was <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">entered.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// The <a href="/coding/class/classrigidshape/">RigidShape</a> object falls in a body of liquid, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "RigidShape::onEnterLiquid(%this,%objId,%waterCoverage,%liquidType)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run whenever this callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs.\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBase\n\n</a>" )
IMPLEMENT_CALLBACK(RigidShape , onLeaveLiquid , void , (const char *objId, const char *liquidType) , (objId, liquidType) , "@brief Called whenever the <a href="/coding/class/classrigidshape/">RigidShape</a> object exits <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">liquid.\n\n</a>" "@param objId The ID of the <a href="/coding/class/classrigidshape/">RigidShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param liquidType Type <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> liquid that was <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">exited.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// The <a href="/coding/class/classrigidshape/">RigidShape</a> object exits in a body of liquid, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "RigidShape::onLeaveLiquid(%this,%objId,%liquidType)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run whenever this callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs.\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBase\n\n</a>" )
Detailed Description
Public Variables
U32 sTriggerMask
Public Functions
ConsoleDocClass(RigidShape , "@brief The <a href="/coding/class/classrigidshape/">RigidShape</a> class implements rigid-body physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> DTS objects in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">world.\n\n</a>" "\"Rigid body physics\" refers <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> a system whereby objects are assumed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have a finite size, \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "equally distributed masses, and where deformations of the objects themselves are not accounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">for.\n</a>" "Uses the <a href="/coding/class/classrigidshape/">RigidShape</a> class <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">physics.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" " datablock <a href="/coding/class/classrigidshapedata/">RigidShapeData</a>(BouncingBoulder)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " category=\"RigidShape\";\n" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " shapeFile = \"~/data/shapes/boulder/boulder.dts\";\n" " emap = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // <a href="/coding/class/classrigid/">Rigid</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Body\n</a>" " mass = 500;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " massCenter = \"0 0 0\"; // Center of mass <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> rigid <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">body\n</a>" " massBox = \"0 0 0\"; // Size of box used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> moment of inertia,\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> zero it defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> object bounding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">box\n</a>" " drag = 0.2; // Drag <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">coefficient\n</a>" " bodyFriction = 0.2;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " bodyRestitution = 0.1;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minImpactSpeed = 5; // Impacts over this invoke the script <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">callback\n</a>" " softImpactSpeed = 5; // Play SoftImpact <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Sound\n</a>" " hardImpactSpeed = 15; // Play HardImpact <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Sound\n</a>" " integration = 4; // Physics integration: <a href="/coding/file/processlist_8h/#processlist_8h_1a6dfddc4b6033c4de60ed37c4fe30f650">TickSec</a>/<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rate\n</a>" " collisionTol = 0.1; // <a href="/coding/class/structcollision/">Collision</a> distance <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tolerance\n</a>" " contactTol = 0.1; // Contact velocity <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tolerance\n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minRollSpeed = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " maxDrag = 0.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minDrag = 0.01;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dustHeight = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dragForce = 0.05;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " vertFactor = 0.05;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classrigidshape/">RigidShape</a>()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dataBlock = \"BouncingBoulder\";\n" " parentGroup = EWCreatorWindow.objectGroup;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RigidShapeData\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBase\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Physics\n</a>" )
ConsoleDocClass(RigidShapeData , "@brief Defines the physics properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an individual <a href="/coding/class/classrigidshapedata/">RigidShapeData</a> physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" " datablock <a href="/coding/class/classrigidshapedata/">RigidShapeData</a>( BouncingBoulder )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " category = \"RigidShape\";\n" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " shapeFile = \"~/data/shapes/boulder/boulder.dts\";\n" " emap = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // <a href="/coding/class/classrigid/">Rigid</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Body\n</a>" " mass = 500;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " massCenter = \"0 0 0\"; // Center of mass <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> rigid <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">body\n</a>" " massBox = \"0 0 0\"; // Size of box used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> moment of inertia,\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> zero it defaults <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> object bounding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">box\n</a>" " drag = 0.2; // Drag <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">coefficient\n</a>" " bodyFriction = 0.2;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " bodyRestitution = 0.1;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minImpactSpeed = 5; // Impacts over this invoke the script <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">callback\n</a>" " softImpactSpeed = 5; // Play SoftImpact <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Sound\n</a>" " hardImpactSpeed = 15; // Play HardImpact <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Sound\n</a>" " integration = 4; // Physics integration: <a href="/coding/file/processlist_8h/#processlist_8h_1a6dfddc4b6033c4de60ed37c4fe30f650">TickSec</a>/<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rate\n</a>" " collisionTol = 0.1; // <a href="/coding/class/structcollision/">Collision</a> distance <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tolerance\n</a>" " contactTol = 0.1; // Contact velocity <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tolerance\n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minRollSpeed = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " maxDrag = 0.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " minDrag = 0.01;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dustHeight = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dragForce = 0.05;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " vertFactor = 0.05;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RigidShape\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBase\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Physics\n</a>" )
DefineEngineMethod(RigidShape , forceClientTransform , void , () , "@brief Forces the client <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> jump <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/class/classrigidshape/">RigidShape</a>'s transform rather then warp <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n\n</a>" )
DefineEngineMethod(RigidShape , freezeSim , void , (bool isFrozen) , "@brief Enables or disables the physics simulation on the <a href="/coding/class/classrigidshape/">RigidShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param isFrozen Boolean frozen state <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Define the frozen <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">state.\n</a>" "% isFrozen)
DefineEngineMethod(RigidShape , reset , void , () , "@brief Clears physic forces from the shape and sets it at <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rest.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Inform the <a href="/coding/class/classrigidshape/">RigidShape</a> object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reset.\n</a>" "%thisRigidShape.reset();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/class/structshapebasedata/">ShapeBaseData</a>" )
IMPLEMENT_CALLBACK(RigidShape , onEnterLiquid , void , (const char *objId, F32 waterCoverage, const char *liquidType) , (objId, waterCoverage, liquidType) , "@brief Called whenever this <a href="/coding/class/classrigidshape/">RigidShape</a> object enters <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">liquid.\n\n</a>" "@param objId The ID of the rigidShape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param waterCoverage Amount of water coverage the <a href="/coding/class/classrigidshape/">RigidShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">has.\n</a>" "@param liquidType Type of liquid that was <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">entered.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// The <a href="/coding/class/classrigidshape/">RigidShape</a> object falls in a body of liquid, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "RigidShape::onEnterLiquid(%this,%objId,%waterCoverage,%liquidType)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run whenever this callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs.\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBase\n\n</a>" )
IMPLEMENT_CALLBACK(RigidShape , onLeaveLiquid , void , (const char *objId, const char *liquidType) , (objId, liquidType) , "@brief Called whenever the <a href="/coding/class/classrigidshape/">RigidShape</a> object exits <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">liquid.\n\n</a>" "@param objId The ID of the <a href="/coding/class/classrigidshape/">RigidShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param liquidType Type <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> liquid that was <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">exited.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// The <a href="/coding/class/classrigidshape/">RigidShape</a> object exits in a body of liquid, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "RigidShape::onLeaveLiquid(%this,%objId,%liquidType)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run whenever this callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs.\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBase\n\n</a>" )
IMPLEMENT_CO_DATABLOCK_V1(RigidShapeData )
IMPLEMENT_CO_NETOBJECT_V1(RigidShape )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "T3D/rigidShape.h" 26 27#include "app/game.h" 28#include "math/mMath.h" 29#include "console/simBase.h" 30#include "console/console.h" 31#include "console/consoleTypes.h" 32#include "collision/clippedPolyList.h" 33#include "collision/planeExtractor.h" 34#include "T3D/gameBase/moveManager.h" 35#include "core/stream/bitStream.h" 36#include "core/dnet.h" 37#include "T3D/gameBase/gameConnection.h" 38#include "ts/tsShapeInstance.h" 39#include "math/mathIO.h" 40#include "scene/sceneRenderState.h" 41#include "scene/sceneManager.h" 42#include "T3D/fx/cameraFXMgr.h" 43#include "T3D/trigger.h" 44#include "T3D/item.h" 45#include "gfx/primBuilder.h" 46#include "gfx/gfxDrawUtil.h" 47#include "sfx/sfxTypes.h" 48#include "sfx/sfxSystem.h" 49#include "T3D/fx/particleEmitter.h" 50#include "console/engineAPI.h" 51 52 53IMPLEMENT_CO_DATABLOCK_V1(RigidShapeData); 54 55ConsoleDocClass( RigidShapeData, 56 "@brief Defines the physics properties for an individual RigidShapeData physics object.\n\n" 57 58 "@tsexample\n" 59 " datablock RigidShapeData( BouncingBoulder )\n" 60 " {\n" 61 " category = \"RigidShape\";\n" 62 "\n" 63 " shapeFile = \"~/data/shapes/boulder/boulder.dts\";\n" 64 " emap = true;\n" 65 "\n" 66 " // Rigid Body\n" 67 " mass = 500;\n" 68 " massCenter = \"0 0 0\"; // Center of mass for rigid body\n" 69 " massBox = \"0 0 0\"; // Size of box used for moment of inertia,\n" 70 " // if zero it defaults to object bounding box\n" 71 " drag = 0.2; // Drag coefficient\n" 72 " bodyFriction = 0.2;\n" 73 " bodyRestitution = 0.1;\n" 74 " minImpactSpeed = 5; // Impacts over this invoke the script callback\n" 75 " softImpactSpeed = 5; // Play SoftImpact Sound\n" 76 " hardImpactSpeed = 15; // Play HardImpact Sound\n" 77 " integration = 4; // Physics integration: TickSec/Rate\n" 78 " collisionTol = 0.1; // Collision distance tolerance\n" 79 " contactTol = 0.1; // Contact velocity tolerance\n" 80 "\n" 81 " minRollSpeed = 10;\n" 82 "\n" 83 " maxDrag = 0.5;\n" 84 " minDrag = 0.01;\n" 85 "\n" 86 " dustHeight = 10;\n" 87 "\n" 88 " dragForce = 0.05;\n" 89 " vertFactor = 0.05;\n" 90 " };\n" 91 "@endtsexample\n\n" 92 93 "@see RigidShape\n" 94 "@see ShapeBase\n\n" 95 96 "@ingroup Physics\n" 97); 98 99 100IMPLEMENT_CO_NETOBJECT_V1(RigidShape); 101 102ConsoleDocClass( RigidShape, 103 "@brief The RigidShape class implements rigid-body physics for DTS objects in the world.\n\n" 104 105 "\"Rigid body physics\" refers to a system whereby objects are assumed to have a finite size,\n" 106 "equally distributed masses, and where deformations of the objects themselves are not accounted for.\n" 107 "Uses the RigidShape class to control its physics.\n\n" 108 109 "@tsexample\n" 110 " datablock RigidShapeData( BouncingBoulder )\n" 111 " {\n" 112 " category = \"RigidShape\";\n" 113 "\n" 114 " shapeFile = \"~/data/shapes/boulder/boulder.dts\";\n" 115 " emap = true;\n" 116 "\n" 117 " // Rigid Body\n" 118 " mass = 500;\n" 119 " massCenter = \"0 0 0\"; // Center of mass for rigid body\n" 120 " massBox = \"0 0 0\"; // Size of box used for moment of inertia,\n" 121 " // if zero it defaults to object bounding box\n" 122 " drag = 0.2; // Drag coefficient\n" 123 " bodyFriction = 0.2;\n" 124 " bodyRestitution = 0.1;\n" 125 " minImpactSpeed = 5; // Impacts over this invoke the script callback\n" 126 " softImpactSpeed = 5; // Play SoftImpact Sound\n" 127 " hardImpactSpeed = 15; // Play HardImpact Sound\n" 128 " integration = 4; // Physics integration: TickSec/Rate\n" 129 " collisionTol = 0.1; // Collision distance tolerance\n" 130 " contactTol = 0.1; // Contact velocity tolerance\n" 131 "\n" 132 " minRollSpeed = 10;\n" 133 "\n" 134 " maxDrag = 0.5;\n" 135 " minDrag = 0.01;\n" 136 "\n" 137 " dustHeight = 10;\n" 138 "\n" 139 " dragForce = 0.05;\n" 140 " vertFactor = 0.05;\n" 141 " };\n" 142 "\n" 143 " new RigidShape()\n" 144 " {\n" 145 " dataBlock = \"BouncingBoulder\";\n" 146 " parentGroup = EWCreatorWindow.objectGroup;\n" 147 " };\n" 148 "@endtsexample\n\n" 149 150 "@see RigidShapeData\n" 151 "@see ShapeBase\n\n" 152 153 "@ingroup Physics\n" 154); 155 156 157IMPLEMENT_CALLBACK( RigidShape, onEnterLiquid, void, ( const char* objId, F32 waterCoverage, const char* liquidType ), 158 ( objId, waterCoverage, liquidType ), 159 "@brief Called whenever this RigidShape object enters liquid.\n\n" 160 "@param objId The ID of the rigidShape object.\n" 161 "@param waterCoverage Amount of water coverage the RigidShape has.\n" 162 "@param liquidType Type of liquid that was entered.\n\n" 163 "@tsexample\n" 164 "// The RigidShape object falls in a body of liquid, causing the callback to occur.\n" 165 "RigidShape::onEnterLiquid(%this,%objId,%waterCoverage,%liquidType)\n" 166 " {\n" 167 " // Code to run whenever this callback occurs.\n" 168 " }\n" 169 "@endtsexample\n\n" 170 "@see ShapeBase\n\n" 171); 172 173IMPLEMENT_CALLBACK( RigidShape, onLeaveLiquid, void, ( const char* objId, const char* liquidType ),( objId, liquidType ), 174 "@brief Called whenever the RigidShape object exits liquid.\n\n" 175 "@param objId The ID of the RigidShape object.\n" 176 "@param liquidType Type if liquid that was exited.\n\n" 177 "@tsexample\n" 178 "// The RigidShape object exits in a body of liquid, causing the callback to occur.\n" 179 "RigidShape::onLeaveLiquid(%this,%objId,%liquidType)\n" 180 " {\n" 181 " // Code to run whenever this callback occurs.\n" 182 " }\n" 183 "@endtsexample\n\n" 184 "@see ShapeBase\n\n" 185); 186 187//---------------------------------------------------------------------------- 188 189namespace { 190 191 // Client prediction 192 const S32 sMaxWarpTicks = 3; // Max warp duration in ticks 193 const S32 sMaxPredictionTicks = 30; // Number of ticks to predict 194 const F32 sRigidShapeGravity = -20; 195 196 // Physics and collision constants 197 static F32 sRestTol = 0.5; // % of gravity energy to be at rest 198 static S32 sRestCount = 10; // Consecutive ticks before comming to rest 199 200 const U32 sCollisionMoveMask = ( TerrainObjectType | PlayerObjectType | 201 StaticShapeObjectType | VehicleObjectType | 202 VehicleBlockerObjectType ); 203 204 const U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType 205 const U32 sClientCollisionMask = sCollisionMoveMask; 206 207 void nonFilter(SceneObject* object,void *key) 208 { 209 SceneContainer::CallbackInfo* info = reinterpret_cast<SceneContainer::CallbackInfo*>(key); 210 object->buildPolyList(info->context,info->polyList,info->boundingBox,info->boundingSphere); 211 } 212 213} // namespace {} 214 215 216// Trigger objects that are not normally collided with. 217static U32 sTriggerMask = ItemObjectType | 218TriggerObjectType | 219CorpseObjectType; 220 221 222//---------------------------------------------------------------------------- 223 224RigidShapeData::RigidShapeData() 225{ 226 shadowEnable = true; 227 228 body.friction = 0; 229 body.restitution = 1; 230 231 minImpactSpeed = 25; 232 softImpactSpeed = 25; 233 hardImpactSpeed = 50; 234 minRollSpeed = 0; 235 236 cameraRoll = true; 237 cameraLag = 0; 238 cameraDecay = 0; 239 cameraOffset = 0; 240 241 minDrag = 0; 242 maxDrag = 0; 243 integration = 1; 244 collisionTol = 0.1f; 245 contactTol = 0.1f; 246 massCenter.set(0,0,0); 247 massBox.set(0,0,0); 248 249 drag = 0.7f; 250 density = 4; 251 252 for (S32 i = 0; i < Body::MaxSounds; i++) 253 body.sound[i] = 0; 254 255 dustEmitter = NULL; 256 dustID = 0; 257 dustHeight = 1.0; 258 259 dMemset( splashEmitterList, 0, sizeof( splashEmitterList ) ); 260 dMemset( splashEmitterIDList, 0, sizeof( splashEmitterIDList ) ); 261 262 splashFreqMod = 300.0; 263 splashVelEpsilon = 0.50; 264 exitSplashSoundVel = 2.0; 265 softSplashSoundVel = 1.0; 266 medSplashSoundVel = 2.0; 267 hardSplashSoundVel = 3.0; 268 269 dMemset(waterSound, 0, sizeof(waterSound)); 270 271 dragForce = 0; 272 vertFactor = 0.25; 273 274 dustTrailEmitter = NULL; 275 dustTrailID = 0; 276} 277 278RigidShapeData::~RigidShapeData() 279{ 280 281} 282 283//---------------------------------------------------------------------------- 284 285 286bool RigidShapeData::onAdd() 287{ 288 if(!Parent::onAdd()) 289 return false; 290 291 return true; 292} 293 294 295bool RigidShapeData::preload(bool server, String &errorStr) 296{ 297 if (!Parent::preload(server, errorStr)) 298 return false; 299 300 // RigidShape objects must define a collision detail 301 if (!collisionDetails.size() || collisionDetails[0] == -1) 302 { 303 Con::errorf("RigidShapeData::preload failed: Rigid shapes must define a collision-1 detail"); 304 errorStr = String::ToString("RigidShapeData: Couldn't load shape \"%s\"",shapeName); 305 return false; 306 } 307 308 // Resolve objects transmitted from server 309 if (!server) { 310 for (S32 i = 0; i < Body::MaxSounds; i++) 311 sfxResolve( &body.sound[ i ], errorStr ); 312 } 313 314 if( !dustEmitter && dustID != 0 ) 315 { 316 if( !Sim::findObject( dustID, dustEmitter ) ) 317 { 318 Con::errorf( ConsoleLogEntry::General, "RigidShapeData::preload Invalid packet, bad datablockId(dustEmitter): 0x%x", dustID ); 319 } 320 } 321 322 U32 i; 323 for( i=0; i<VC_NUM_SPLASH_EMITTERS; i++ ) 324 { 325 if( !splashEmitterList[i] && splashEmitterIDList[i] != 0 ) 326 { 327 if( !Sim::findObject( splashEmitterIDList[i], splashEmitterList[i] ) ) 328 { 329 Con::errorf( ConsoleLogEntry::General, "RigidShapeData::preload Invalid packet, bad datablockId(splashEmitter): 0x%x", splashEmitterIDList[i] ); 330 } 331 } 332 } 333 334 if (dragForce <= 0.01f) 335 { 336 Con::warnf("RigidShapeData::preload: dragForce must be at least 0.01"); 337 dragForce = 0.01f; 338 } 339 340 if (vertFactor < 0.0f || vertFactor > 1.0f) 341 { 342 Con::warnf("RigidShapeData::preload: vert factor must be [0, 1]"); 343 vertFactor = vertFactor < 0.0f ? 0.0f : 1.0f; 344 } 345 346 if( !dustTrailEmitter && dustTrailID != 0 ) 347 { 348 if( !Sim::findObject( dustTrailID, dustTrailEmitter ) ) 349 { 350 Con::errorf( ConsoleLogEntry::General, "RigidShapeData::preload Invalid packet, bad datablockId(dustTrailEmitter): 0x%x", dustTrailID ); 351 } 352 } 353 354 return true; 355} 356 357 358//---------------------------------------------------------------------------- 359 360void RigidShapeData::packData(BitStream* stream) 361{ 362 Parent::packData(stream); 363 364 stream->write(body.restitution); 365 stream->write(body.friction); 366 for( U32 i = 0; i < Body::MaxSounds; ++ i ) 367 sfxWrite( stream, body.sound[ i ] ); 368 369 stream->write(minImpactSpeed); 370 stream->write(softImpactSpeed); 371 stream->write(hardImpactSpeed); 372 stream->write(minRollSpeed); 373 374 stream->write(maxDrag); 375 stream->write(minDrag); 376 stream->write(integration); 377 stream->write(collisionTol); 378 stream->write(contactTol); 379 mathWrite(*stream,massCenter); 380 mathWrite(*stream,massBox); 381 382 stream->writeFlag(cameraRoll); 383 stream->write(cameraLag); 384 stream->write(cameraDecay); 385 stream->write(cameraOffset); 386 387 stream->write( dustHeight ); 388 389 stream->write(exitSplashSoundVel); 390 stream->write(softSplashSoundVel); 391 stream->write(medSplashSoundVel); 392 stream->write(hardSplashSoundVel); 393 394 // write the water sound profiles 395 for( U32 i = 0; i < MaxSounds; ++ i ) 396 sfxWrite( stream, waterSound[ i ] ); 397 398 if (stream->writeFlag( dustEmitter )) 399 stream->writeRangedU32( dustEmitter->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast ); 400 401 for( U32 i = 0; i < VC_NUM_SPLASH_EMITTERS; ++ i ) 402 { 403 if( stream->writeFlag( splashEmitterList[i] != NULL ) ) 404 stream->writeRangedU32( splashEmitterList[i]->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast ); 405 } 406 407 stream->write(splashFreqMod); 408 stream->write(splashVelEpsilon); 409 410 stream->write(dragForce); 411 stream->write(vertFactor); 412 413 if (stream->writeFlag( dustTrailEmitter )) 414 stream->writeRangedU32( dustTrailEmitter->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast ); 415} 416 417void RigidShapeData::unpackData(BitStream* stream) 418{ 419 Parent::unpackData(stream); 420 421 stream->read(&body.restitution); 422 stream->read(&body.friction); 423 424 for( U32 i = 0; i < Body::MaxSounds; i++) 425 sfxRead( stream, &body.sound[ i ] ); 426 427 stream->read(&minImpactSpeed); 428 stream->read(&softImpactSpeed); 429 stream->read(&hardImpactSpeed); 430 stream->read(&minRollSpeed); 431 432 stream->read(&maxDrag); 433 stream->read(&minDrag); 434 stream->read(&integration); 435 stream->read(&collisionTol); 436 stream->read(&contactTol); 437 mathRead(*stream,&massCenter); 438 mathRead(*stream,&massBox); 439 440 cameraRoll = stream->readFlag(); 441 stream->read(&cameraLag); 442 stream->read(&cameraDecay); 443 stream->read(&cameraOffset); 444 445 stream->read( &dustHeight ); 446 447 stream->read(&exitSplashSoundVel); 448 stream->read(&softSplashSoundVel); 449 stream->read(&medSplashSoundVel); 450 stream->read(&hardSplashSoundVel); 451 452 // write the water sound profiles 453 for( U32 i = 0; i < MaxSounds; ++ i ) 454 sfxRead( stream, &waterSound[ i ] ); 455 456 if( stream->readFlag() ) 457 dustID = (S32) stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); 458 459 for( U32 i = 0; i < VC_NUM_SPLASH_EMITTERS; ++ i ) 460 { 461 if( stream->readFlag() ) 462 splashEmitterIDList[i] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); 463 } 464 465 stream->read(&splashFreqMod); 466 stream->read(&splashVelEpsilon); 467 468 stream->read(&dragForce); 469 stream->read(&vertFactor); 470 471 if( stream->readFlag() ) 472 dustTrailID = (S32) stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); 473} 474 475 476//---------------------------------------------------------------------------- 477 478void RigidShapeData::initPersistFields() 479{ 480 addField("massCenter", TypePoint3F, Offset(massCenter, RigidShapeData), "Center of mass for rigid body."); 481 addField("massBox", TypePoint3F, Offset(massBox, RigidShapeData), "Size of inertial box."); 482 addField("bodyRestitution", TypeF32, Offset(body.restitution, RigidShapeData), "The percentage of kinetic energy kept by this object in a collision."); 483 addField("bodyFriction", TypeF32, Offset(body.friction, RigidShapeData), "How much friction this object has. Lower values will cause the object to appear to be more slippery."); 484 485 addField("minImpactSpeed", TypeF32, Offset(minImpactSpeed, RigidShapeData), 486 "Minimum collision speed to classify collision as impact (triggers onImpact on server object)." ); 487 addField("softImpactSpeed", TypeF32, Offset(softImpactSpeed, RigidShapeData), "Minimum speed at which this object must be travelling for the soft impact sound to be played."); 488 addField("hardImpactSpeed", TypeF32, Offset(hardImpactSpeed, RigidShapeData), "Minimum speed at which the object must be travelling for the hard impact sound to be played."); 489 addField("minRollSpeed", TypeF32, Offset(minRollSpeed, RigidShapeData)); 490 491 addField("maxDrag", TypeF32, Offset(maxDrag, RigidShapeData), "Maximum drag available to this object."); 492 addField("minDrag", TypeF32, Offset(minDrag, RigidShapeData), "Minimum drag available to this object."); 493 addField("integration", TypeS32, Offset(integration, RigidShapeData), "Number of physics steps to process per tick."); 494 addField("collisionTol", TypeF32, Offset(collisionTol, RigidShapeData), "Collision distance tolerance."); 495 addField("contactTol", TypeF32, Offset(contactTol, RigidShapeData), "Contact velocity tolerance."); 496 497 addGroup( "Forces" ); 498 499 addField("dragForce", TypeF32, Offset(dragForce, RigidShapeData), "Used to simulate the constant drag acting on the object"); 500 addField("vertFactor", TypeF32, Offset(vertFactor, RigidShapeData), "The scalar applied to the vertical portion of the velocity drag acting on a object."); 501 502 endGroup( "Forces" ); 503 504 addGroup( "Particle Effects" ); 505 506 addField("dustEmitter", TYPEID< ParticleEmitterData >(), Offset(dustEmitter, RigidShapeData), "Array of pointers to ParticleEmitterData datablocks which will be used to emit particles at object/terrain contact point.\n"); 507 addField("triggerDustHeight", TypeF32, Offset(triggerDustHeight, RigidShapeData), "Maximum height from the ground at which the object will generate dust.\n"); 508 addField("dustHeight", TypeF32, Offset(dustHeight, RigidShapeData), "Height of dust effects.\n"); 509 510 addField("dustTrailEmitter", TYPEID< ParticleEmitterData >(), Offset(dustTrailEmitter, RigidShapeData), "Particle emitter used to create a dust trail for the moving object.\n"); 511 512 addField("splashEmitter", TYPEID< ParticleEmitterData >(), Offset(splashEmitterList, RigidShapeData), VC_NUM_SPLASH_EMITTERS, "Array of pointers to ParticleEmitterData datablocks which will generate splash effects.\n"); 513 514 addField("splashFreqMod", TypeF32, Offset(splashFreqMod, RigidShapeData), "The simulated frequency modulation of a splash generated by this object. Multiplied along with speed and time elapsed when determining splash emition rate.\n"); 515 addField("splashVelEpsilon", TypeF32, Offset(splashVelEpsilon, RigidShapeData), "The threshold speed at which we consider the object's movement to have stopped when updating splash effects.\n"); 516 517 endGroup( "Particle Effects" ); 518 519 addGroup( "Sounds" ); 520 521 addField("softImpactSound", TypeSFXTrackName, Offset(body.sound[Body::SoftImpactSound], RigidShapeData), 522 "Sound to play when body impacts with at least softImageSpeed but less than hardImpactSpeed." ); 523 addField("hardImpactSound", TypeSFXTrackName, Offset(body.sound[Body::HardImpactSound], RigidShapeData), 524 "Sound to play when body impacts with at least hardImpactSpeed." ); 525 526 addField("exitSplashSoundVelocity", TypeF32, Offset(exitSplashSoundVel, RigidShapeData), "The minimum velocity at which the exit splash sound will be played when emerging from water.\n"); 527 addField("softSplashSoundVelocity", TypeF32, Offset(softSplashSoundVel, RigidShapeData),"The minimum velocity at which the soft splash sound will be played when impacting water.\n"); 528 addField("mediumSplashSoundVelocity", TypeF32, Offset(medSplashSoundVel, RigidShapeData), "The minimum velocity at which the medium splash sound will be played when impacting water.\n"); 529 addField("hardSplashSoundVelocity", TypeF32, Offset(hardSplashSoundVel, RigidShapeData), "The minimum velocity at which the hard splash sound will be played when impacting water.\n"); 530 addField("exitingWater", TypeSFXTrackName, Offset(waterSound[ExitWater], RigidShapeData), "The AudioProfile will be used to produce sounds when emerging from water.\n"); 531 addField("impactWaterEasy", TypeSFXTrackName, Offset(waterSound[ImpactSoft], RigidShapeData), "The AudioProfile will be used to produce sounds when a soft impact with water occurs.\n"); 532 addField("impactWaterMedium", TypeSFXTrackName, Offset(waterSound[ImpactMedium], RigidShapeData), "The AudioProfile will be used to produce sounds when a medium impact with water occurs.\n"); 533 addField("impactWaterHard", TypeSFXTrackName, Offset(waterSound[ImpactHard], RigidShapeData), "The AudioProfile will be used to produce sounds when a hard impact with water occurs.\n"); 534 addField("waterWakeSound", TypeSFXTrackName, Offset(waterSound[Wake], RigidShapeData), "The AudioProfile will be used to produce sounds when a water wake is displayed.\n"); 535 536 endGroup( "Sounds" ); 537 538 addGroup( "Camera" ); 539 540 addField("cameraRoll", TypeBool, Offset(cameraRoll, RigidShapeData), "Specifies whether the camera's rotation matrix, and the render eye transform are multiplied during camera updates.\n"); 541 addField("cameraLag", TypeF32, Offset(cameraLag, RigidShapeData), "Scalar amount by which the third person camera lags the object, relative to the object's linear velocity.\n"); 542 addField("cameraDecay", TypeF32, Offset(cameraDecay, RigidShapeData), "Scalar rate at which the third person camera offset decays, per tick.\n"); 543 addField("cameraOffset", TypeF32, Offset(cameraOffset, RigidShapeData), "The vertical offset of the object's camera.\n"); 544 545 endGroup( "Camera" ); 546 547 Parent::initPersistFields(); 548} 549 550 551//---------------------------------------------------------------------------- 552//---------------------------------------------------------------------------- 553 554//---------------------------------------------------------------------------- 555 556RigidShape::RigidShape() 557{ 558 559 mNetFlags.set(Ghostable); 560 561 mDustTrailEmitter = NULL; 562 563 mDataBlock = 0; 564 // [rene, 27-Apr-11] WTH is a RigidShape a vehicle??? 565 mTypeMask |= VehicleObjectType | DynamicShapeObjectType; 566 567 mDelta.pos = Point3F(0,0,0); 568 mDelta.posVec = Point3F(0,0,0); 569 mDelta.warpTicks = mDelta.warpCount = 0; 570 mDelta.dt = 1; 571 mDelta.move = NullMove; 572 mPredictionCount = 0; 573 mDelta.cameraOffset.set(0,0,0); 574 mDelta.cameraVec.set(0,0,0); 575 mDelta.cameraRot.set(0,0,0); 576 mDelta.cameraRotVec.set(0,0,0); 577 578 mRigid.linPosition.set(0, 0, 0); 579 mRigid.linVelocity.set(0, 0, 0); 580 mRigid.angPosition.identity(); 581 mRigid.angVelocity.set(0, 0, 0); 582 mRigid.linMomentum.set(0, 0, 0); 583 mRigid.angMomentum.set(0, 0, 0); 584 mContacts.clear(); 585 586 mCameraOffset.set(0,0,0); 587 588 dMemset( mDustEmitterList, 0, sizeof( mDustEmitterList ) ); 589 dMemset( mSplashEmitterList, 0, sizeof( mSplashEmitterList ) ); 590 591 mDisableMove = false; // start frozen by default 592 restCount = 0; 593 594 inLiquid = false; 595} 596 597RigidShape::~RigidShape() 598{ 599 // 600} 601 602U32 RigidShape::getCollisionMask() 603{ 604 if (isServerObject()) 605 return sServerCollisionMask; 606 else 607 return sClientCollisionMask; 608} 609 610Point3F RigidShape::getVelocity() const 611{ 612 return mRigid.linVelocity; 613} 614 615//---------------------------------------------------------------------------- 616 617bool RigidShape::onAdd() 618{ 619 if (!Parent::onAdd()) 620 return false; 621 622 // When loading from a mission script, the base SceneObject's transform 623 // will have been set and needs to be transfered to the rigid body. 624 mRigid.setTransform(mObjToWorld); 625 626 // Initialize interpolation vars. 627 mDelta.rot[1] = mDelta.rot[0] = mRigid.angPosition; 628 mDelta.pos = mRigid.linPosition; 629 mDelta.posVec = Point3F(0,0,0); 630 631 // Create Emitters on the client 632 if( isClientObject() ) 633 { 634 if( mDataBlock->dustEmitter ) 635 { 636 for( U32 i=0; i<RigidShapeData::VC_NUM_DUST_EMITTERS; i++ ) 637 { 638 mDustEmitterList[i] = new ParticleEmitter; 639 mDustEmitterList[i]->onNewDataBlock( mDataBlock->dustEmitter, false ); 640 if( !mDustEmitterList[i]->registerObject() ) 641 { 642 Con::warnf( ConsoleLogEntry::General, "Could not register dust emitter for class: %s", mDataBlock->getName() ); 643 delete mDustEmitterList[i]; 644 mDustEmitterList[i] = NULL; 645 } 646 } 647 } 648 649 for( U32 j=0; j<RigidShapeData::VC_NUM_SPLASH_EMITTERS; j++ ) 650 { 651 if( mDataBlock->splashEmitterList[j] ) 652 { 653 mSplashEmitterList[j] = new ParticleEmitter; 654 mSplashEmitterList[j]->onNewDataBlock( mDataBlock->splashEmitterList[j], false ); 655 if( !mSplashEmitterList[j]->registerObject() ) 656 { 657 Con::warnf( ConsoleLogEntry::General, "Could not register splash emitter for class: %s", mDataBlock->getName() ); 658 delete mSplashEmitterList[j]; 659 mSplashEmitterList[j] = NULL; 660 } 661 662 } 663 } 664 } 665 666 // Create a new convex. 667 AssertFatal(mDataBlock->collisionDetails[0] != -1, "Error, a rigid shape must have a collision-1 detail!"); 668 mConvex.mObject = this; 669 mConvex.pShapeBase = this; 670 mConvex.hullId = 0; 671 mConvex.box = mObjBox; 672 mConvex.box.minExtents.convolve(mObjScale); 673 mConvex.box.maxExtents.convolve(mObjScale); 674 mConvex.findNodeTransform(); 675 676 addToScene(); 677 678 679 if( !isServerObject() ) 680 { 681 if( mDataBlock->dustTrailEmitter ) 682 { 683 mDustTrailEmitter = new ParticleEmitter; 684 mDustTrailEmitter->onNewDataBlock( mDataBlock->dustTrailEmitter, false ); 685 if( !mDustTrailEmitter->registerObject() ) 686 { 687 Con::warnf( ConsoleLogEntry::General, "Could not register dust emitter for class: %s", mDataBlock->getName() ); 688 delete mDustTrailEmitter; 689 mDustTrailEmitter = NULL; 690 } 691 } 692 } 693 694 695 if (isServerObject()) 696 scriptOnAdd(); 697 698 return true; 699} 700 701void RigidShape::onRemove() 702{ 703 scriptOnRemove(); 704 removeFromScene(); 705 706 U32 i=0; 707 for( i=0; i<RigidShapeData::VC_NUM_DUST_EMITTERS; i++ ) 708 { 709 if( mDustEmitterList[i] ) 710 { 711 mDustEmitterList[i]->deleteWhenEmpty(); 712 mDustEmitterList[i] = NULL; 713 } 714 } 715 716 for( i=0; i<RigidShapeData::VC_NUM_SPLASH_EMITTERS; i++ ) 717 { 718 if( mSplashEmitterList[i] ) 719 { 720 mSplashEmitterList[i]->deleteWhenEmpty(); 721 mSplashEmitterList[i] = NULL; 722 } 723 } 724 725 Parent::onRemove(); 726} 727 728 729//---------------------------------------------------------------------------- 730 731void RigidShape::processTick(const Move* move) 732{ 733 Parent::processTick(move); 734 if ( isMounted() ) 735 return; 736 737 // Warp to catch up to server 738 if (mDelta.warpCount < mDelta.warpTicks) 739 { 740 mDelta.warpCount++; 741 742 // Set new pos. 743 mObjToWorld.getColumn(3,&mDelta.pos); 744 mDelta.pos += mDelta.warpOffset; 745 mDelta.rot[0] = mDelta.rot[1]; 746 mDelta.rot[1].interpolate(mDelta.warpRot[0],mDelta.warpRot[1],F32(mDelta.warpCount)/<a href="/coding/class/classrigidshape/#classrigidshape_1a4a7d0e60ba7dff122314e6ac9034e3bb">mDelta</a>.warpTicks); 747 setPosition(mDelta.pos,mDelta.rot[1]); 748 749 // Pos backstepping 750 mDelta.posVec.x = -mDelta.warpOffset.x; 751 mDelta.posVec.y = -mDelta.warpOffset.y; 752 mDelta.posVec.z = -mDelta.warpOffset.z; 753 } 754 else 755 { 756 if (!move) 757 { 758 if (isGhost()) 759 { 760 // If we haven't run out of prediction time, 761 // predict using the last known move. 762 if (mPredictionCount-- <= 0) 763 return; 764 move = &mDelta.move; 765 } 766 else 767 move = &NullMove; 768 } 769 770 // Process input move 771 updateMove(move); 772 773 // Save current rigid state interpolation 774 mDelta.posVec = mRigid.linPosition; 775 mDelta.rot[0] = mRigid.angPosition; 776 777 // Update the physics based on the integration rate 778 S32 count = mDataBlock->integration; 779 if (!mDisableMove) 780 updateWorkingCollisionSet(getCollisionMask()); 781 for (U32 i = 0; i < count; i++) 782 updatePos(TickSec / count); 783 784 // Wrap up interpolation info 785 mDelta.pos = mRigid.linPosition; 786 mDelta.posVec -= mRigid.linPosition; 787 mDelta.rot[1] = mRigid.angPosition; 788 789 // Update container database 790 setPosition(mRigid.linPosition, mRigid.angPosition); 791 setMaskBits(PositionMask); 792 updateContainer(); 793 } 794} 795 796void RigidShape::interpolateTick(F32 dt) 797{ 798 Parent::interpolateTick(dt); 799 if ( isMounted() ) 800 return; 801 802 if(dt == 0.0f) 803 setRenderPosition(mDelta.pos, mDelta.rot[1]); 804 else 805 { 806 QuatF rot; 807 rot.interpolate(mDelta.rot[1], mDelta.rot[0], dt); 808 Point3F pos = mDelta.pos + mDelta.posVec * dt; 809 setRenderPosition(pos,rot); 810 } 811 mDelta.dt = dt; 812} 813 814void RigidShape::advanceTime(F32 dt) 815{ 816 Parent::advanceTime(dt); 817 818 updateFroth(dt); 819 820 if ( isMounted() ) 821 return; 822 823 // Update 3rd person camera offset. Camera update is done 824 // here as it's a client side only animation. 825 mCameraOffset -= 826 (mCameraOffset * mDataBlock->cameraDecay + 827 mRigid.linVelocity * mDataBlock->cameraLag) * dt; 828} 829 830 831//---------------------------------------------------------------------------- 832 833bool RigidShape::onNewDataBlock(GameBaseData* dptr, bool reload) 834{ 835 mDataBlock = dynamic_cast<RigidShapeData*>(dptr); 836 if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload)) 837 return false; 838 839 // Update Rigid Info 840 mRigid.mass = mDataBlock->mass; 841 mRigid.oneOverMass = 1 / mRigid.mass; 842 mRigid.friction = mDataBlock->body.friction; 843 mRigid.restitution = mDataBlock->body.restitution; 844 mRigid.setCenterOfMass(mDataBlock->massCenter); 845 846 // Ignores massBox, just set sphere for now. Derived objects 847 // can set what they want. 848 mRigid.setObjectInertia(); 849 850 scriptOnNewDataBlock(); 851 852 return true; 853} 854 855 856//---------------------------------------------------------------------------- 857 858void RigidShape::getCameraParameters(F32 *min,F32* max,Point3F* off,MatrixF* rot) 859{ 860 *min = mDataBlock->cameraMinDist; 861 *max = mDataBlock->cameraMaxDist; 862 863 off->set(0,0,mDataBlock->cameraOffset); 864 rot->identity(); 865} 866 867 868//---------------------------------------------------------------------------- 869 870void RigidShape::getCameraTransform(F32* pos,MatrixF* mat) 871{ 872 // Returns camera to world space transform 873 // Handles first person / third person camera position 874 if (isServerObject() && mShapeInstance) 875 mShapeInstance->animateNodeSubtrees(true); 876 877 if (*pos == 0) 878 { 879 getRenderEyeTransform(mat); 880 return; 881 } 882 883 // Get the shape's camera parameters. 884 F32 min,max; 885 MatrixF rot; 886 Point3F offset; 887 getCameraParameters(&min,&max,&offset,&rot); 888 889 // Start with the current eye position 890 MatrixF eye; 891 getRenderEyeTransform(&eye); 892 893 // Build a transform that points along the eye axis 894 // but where the Z axis is always up. 895 if (mDataBlock->cameraRoll) 896 mat->mul(eye,rot); 897 else 898 { 899 MatrixF cam(1); 900 VectorF x,y,z(0,0,1); 901 eye.getColumn(1, &y); 902 903 mCross(y, z, &x); 904 x.normalize(); 905 mCross(x, y, &z); 906 z.normalize(); 907 908 cam.setColumn(0,x); 909 cam.setColumn(1,y); 910 cam.setColumn(2,z); 911 mat->mul(cam,rot); 912 } 913 914 // Camera is positioned straight back along the eye's -Y axis. 915 // A ray is cast to make sure the camera doesn't go through 916 // anything solid. 917 VectorF vp,vec; 918 vp.x = vp.z = 0; 919 vp.y = -(max - min) * *pos; 920 eye.mulV(vp,&vec); 921 922 // Use the camera node as the starting position if it exists. 923 Point3F osp,sp; 924 if (mDataBlock->cameraNode != -1) 925 { 926 mShapeInstance->mNodeTransforms[mDataBlock->cameraNode].getColumn(3,&osp); 927 getRenderTransform().mulP(osp,&sp); 928 } 929 else 930 eye.getColumn(3,&sp); 931 932 // Make sure we don't hit ourself... 933 disableCollision(); 934 if (isMounted()) 935 getObjectMount()->disableCollision(); 936 937 // Cast the ray into the container database to see if we're going 938 // to hit anything. 939 RayInfo collision; 940 Point3F ep = sp + vec + offset + mCameraOffset; 941 if (mContainer->castRay(sp, ep, 942 ~(WaterObjectType | GameBaseObjectType | DefaultObjectType), 943 &collision) == true) 944 { 945 946 // Shift the collision point back a little to try and 947 // avoid clipping against the front camera plane. 948 F32 t = collision.t - (-mDot(vec, collision.normal) / vec.len()) * 0.1; 949 if (t > 0.0f) 950 ep = sp + offset + mCameraOffset + (vec * t); 951 else 952 eye.getColumn(3,&ep); 953 } 954 mat->setColumn(3,ep); 955 956 // Re-enable our collision. 957 if (isMounted()) 958 getObjectMount()->enableCollision(); 959 enableCollision(); 960 961 // Apply Camera FX. 962 mat->mul( gCamFXMgr.getTrans() ); 963} 964 965 966//---------------------------------------------------------------------------- 967 968void RigidShape::getVelocity(const Point3F& r, Point3F* v) 969{ 970 mRigid.getVelocity(r, v); 971} 972 973void RigidShape::applyImpulse(const Point3F &pos, const Point3F &impulse) 974{ 975 Point3F r; 976 mRigid.getOriginVector(pos,&r); 977 mRigid.applyImpulse(r, impulse); 978} 979 980 981//---------------------------------------------------------------------------- 982 983void RigidShape::updateMove(const Move* move) 984{ 985 mDelta.move = *move; 986} 987 988//---------------------------------------------------------------------------- 989 990void RigidShape::setPosition(const Point3F& pos,const QuatF& rot) 991{ 992 MatrixF mat; 993 rot.setMatrix(&mat); 994 mat.setColumn(3,pos); 995 Parent::setTransform(mat); 996} 997 998void RigidShape::setRenderPosition(const Point3F& pos, const QuatF& rot) 999{ 1000 MatrixF mat; 1001 rot.setMatrix(&mat); 1002 mat.setColumn(3,pos); 1003 Parent::setRenderTransform(mat); 1004} 1005 1006void RigidShape::setTransform(const MatrixF& newMat) 1007{ 1008 mRigid.setTransform(newMat); 1009 Parent::setTransform(newMat); 1010 mRigid.atRest = false; 1011 mContacts.clear(); 1012} 1013 1014void RigidShape::forceClientTransform() 1015{ 1016 setMaskBits(ForceMoveMask); 1017} 1018 1019 1020//----------------------------------------------------------------------------- 1021 1022void RigidShape::disableCollision() 1023{ 1024 Parent::disableCollision(); 1025} 1026 1027void RigidShape::enableCollision() 1028{ 1029 Parent::enableCollision(); 1030} 1031 1032 1033//---------------------------------------------------------------------------- 1034/** Update the physics 1035*/ 1036 1037void RigidShape::updatePos(F32 dt) 1038{ 1039 Point3F origVelocity = mRigid.linVelocity; 1040 1041 // Update internal forces acting on the body. 1042 mRigid.clearForces(); 1043 updateForces(dt); 1044 1045 // Update collision information based on our current pos. 1046 bool collided = false; 1047 if (!mRigid.atRest && !mDisableMove) 1048 { 1049 collided = updateCollision(dt); 1050 1051 // Now that all the forces have been processed, lets 1052 // see if we're at rest. Basically, if the kinetic energy of 1053 // the shape is less than some percentage of the energy added 1054 // by gravity for a short period, we're considered at rest. 1055 // This should really be part of the rigid class... 1056 if (mCollisionList.getCount()) 1057 { 1058 F32 k = mRigid.getKineticEnergy(); 1059 F32 G = sRigidShapeGravity * dt; 1060 F32 Kg = 0.5 * mRigid.mass * G * G; 1061 if (k < sRestTol * Kg && ++restCount > sRestCount) 1062 mRigid.setAtRest(); 1063 } 1064 else 1065 restCount = 0; 1066 } 1067 1068 // Integrate forward 1069 if (!mRigid.atRest && !mDisableMove) 1070 mRigid.integrate(dt); 1071 1072 // Deal with client and server scripting, sounds, etc. 1073 if (isServerObject()) 1074 { 1075 1076 // Check triggers and other objects that we normally don't 1077 // collide with. This function must be called before notifyCollision 1078 // as it will queue collision. 1079 checkTriggers(); 1080 1081 // Invoke the onCollision notify callback for all the objects 1082 // we've just hit. 1083 notifyCollision(); 1084 1085 // Server side impact script callback 1086 if (collided) 1087 { 1088 VectorF collVec = mRigid.linVelocity - origVelocity; 1089 F32 collSpeed = collVec.len(); 1090 if (collSpeed > mDataBlock->minImpactSpeed) 1091 onImpact(collVec); 1092 } 1093 1094 // Water script callbacks 1095 if (!inLiquid && mWaterCoverage != 0.0f) 1096 { 1097 onEnterLiquid_callback(getIdString(), mWaterCoverage, mLiquidType.c_str() ); 1098 inLiquid = true; 1099 } 1100 else if (inLiquid && mWaterCoverage == 0.0f) 1101 { 1102 onLeaveLiquid_callback(getIdString(), mLiquidType.c_str() ); 1103 inLiquid = false; 1104 } 1105 1106 } 1107 else { 1108 1109 // Play impact sounds on the client. 1110 if (collided) { 1111 F32 collSpeed = (mRigid.linVelocity - origVelocity).len(); 1112 S32 impactSound = -1; 1113 if (collSpeed >= mDataBlock->hardImpactSpeed) 1114 impactSound = RigidShapeData::Body::HardImpactSound; 1115 else 1116 if (collSpeed >= mDataBlock->softImpactSpeed) 1117 impactSound = RigidShapeData::Body::SoftImpactSound; 1118 1119 if (impactSound != -1 && mDataBlock->body.sound[impactSound] != NULL) 1120 SFX->playOnce(mDataBlock->body.sound[impactSound], &getTransform()); 1121 } 1122 1123 // Water volume sounds 1124 F32 vSpeed = getVelocity().len(); 1125 if (!inLiquid && mWaterCoverage >= 0.8f) { 1126 if (vSpeed >= mDataBlock->hardSplashSoundVel) 1127 SFX->playOnce(mDataBlock->waterSound[RigidShapeData::ImpactHard], &getTransform()); 1128 else 1129 if (vSpeed >= mDataBlock->medSplashSoundVel) 1130 SFX->playOnce(mDataBlock->waterSound[RigidShapeData::ImpactMedium], &getTransform()); 1131 else 1132 if (vSpeed >= mDataBlock->softSplashSoundVel) 1133 SFX->playOnce(mDataBlock->waterSound[RigidShapeData::ImpactSoft], &getTransform()); 1134 inLiquid = true; 1135 } 1136 else 1137 if(inLiquid && mWaterCoverage < 0.8f) { 1138 if (vSpeed >= mDataBlock->exitSplashSoundVel) 1139 SFX->playOnce(mDataBlock->waterSound[RigidShapeData::ExitWater], &getTransform()); 1140 inLiquid = false; 1141 } 1142 } 1143} 1144 1145 1146//---------------------------------------------------------------------------- 1147 1148void RigidShape::updateForces(F32 /*dt*/) 1149{ 1150 if (mDisableMove) return; 1151 Point3F gravForce(0, 0, sRigidShapeGravity * mRigid.mass * mGravityMod); 1152 1153 MatrixF currTransform; 1154 mRigid.getTransform(&currTransform); 1155 1156 Point3F torque(0, 0, 0); 1157 Point3F force(0, 0, 0); 1158 1159 Point3F vel = mRigid.linVelocity; 1160 1161 // Gravity 1162 force += gravForce; 1163 1164 // Apply drag 1165 Point3F vDrag = mRigid.linVelocity; 1166 vDrag.convolve(Point3F(1, 1, mDataBlock->vertFactor)); 1167 force -= vDrag * mDataBlock->dragForce; 1168 1169 // Add in physical zone force 1170 force += mAppliedForce; 1171 1172 // Container buoyancy & drag 1173 force += Point3F(0, 0,-mBuoyancy * sRigidShapeGravity * mRigid.mass * mGravityMod); 1174 force -= mRigid.linVelocity * mDrag; 1175 torque -= mRigid.angMomentum * mDrag; 1176 1177 mRigid.force = force; 1178 mRigid.torque = torque; 1179} 1180 1181 1182//----------------------------------------------------------------------------- 1183/** Update collision information 1184Update the convex state and check for collisions. If the object is in 1185collision, impact and contact forces are generated. 1186*/ 1187 1188bool RigidShape::updateCollision(F32 dt) 1189{ 1190 // Update collision information 1191 MatrixF mat,cmat; 1192 mConvex.transform = &mat; 1193 mRigid.getTransform(&mat); 1194 cmat = mConvex.getTransform(); 1195 1196 mCollisionList.clear(); 1197 CollisionState *state = mConvex.findClosestState(cmat, getScale(), mDataBlock->collisionTol); 1198 if (state && state->dist <= mDataBlock->collisionTol) 1199 { 1200 //resolveDisplacement(ns,state,dt); 1201 mConvex.getCollisionInfo(cmat, getScale(), &mCollisionList, mDataBlock->collisionTol); 1202 } 1203 1204 // Resolve collisions 1205 bool collided = resolveCollision(mRigid,mCollisionList); 1206 resolveContacts(mRigid,mCollisionList,dt); 1207 return collided; 1208} 1209 1210 1211//---------------------------------------------------------------------------- 1212/** Resolve collision impacts 1213Handle collision impacts, as opposed to contacts. Impulses are calculated based 1214on standard collision resolution formulas. 1215*/ 1216bool RigidShape::resolveCollision(Rigid& ns,CollisionList& cList) 1217{ 1218 // Apply impulses to resolve collision 1219 bool colliding, collided = false; 1220 1221 do 1222 { 1223 colliding = false; 1224 for (S32 i = 0; i < cList.getCount(); i++) 1225 { 1226 Collision& c = cList[i]; 1227 if (c.distance < mDataBlock->collisionTol) 1228 { 1229 // Velocity into surface 1230 Point3F v,r; 1231 ns.getOriginVector(c.point,&r); 1232 ns.getVelocity(r,&v); 1233 F32 vn = mDot(v,c.normal); 1234 1235 // Only interested in velocities greater than sContactTol, 1236 // velocities less than that will be dealt with as contacts 1237 // "constraints". 1238 if (vn < -mDataBlock->contactTol) 1239 { 1240 1241 // Apply impulses to the rigid body to keep it from 1242 // penetrating the surface. 1243 ns.resolveCollision(cList[i].point, 1244 cList[i].normal); 1245 colliding = collided = true; 1246 1247 // Keep track of objects we collide with 1248 if (!isGhost() && c.object->getTypeMask() & ShapeBaseObjectType) 1249 { 1250 ShapeBase* col = static_cast<ShapeBase*>(c.object); 1251 queueCollision(col,v - col->getVelocity()); 1252 } 1253 } 1254 } 1255 } 1256 } while (colliding); 1257 1258 return collided; 1259} 1260 1261//---------------------------------------------------------------------------- 1262/** Resolve contact forces 1263Resolve contact forces using the "penalty" method. Forces are generated based 1264on the depth of penetration and the moment of inertia at the point of contact. 1265*/ 1266bool RigidShape::resolveContacts(Rigid& ns,CollisionList& cList,F32 dt) 1267{ 1268 // Use spring forces to manage contact constraints. 1269 bool collided = false; 1270 Point3F t,p(0,0,0),l(0,0,0); 1271 for (S32 i = 0; i < cList.getCount(); i++) 1272 { 1273 Collision& c = cList[i]; 1274 if (c.distance < mDataBlock->collisionTol) 1275 { 1276 1277 // Velocity into the surface 1278 Point3F v,r; 1279 ns.getOriginVector(c.point,&r); 1280 ns.getVelocity(r,&v); 1281 F32 vn = mDot(v,c.normal); 1282 1283 // Only interested in velocities less than mDataBlock->contactTol, 1284 // velocities greater than that are dealt with as collisions. 1285 if (mFabs(vn) < mDataBlock->contactTol) 1286 { 1287 collided = true; 1288 1289 // Penetration force. This is actually a spring which 1290 // will seperate the body from the collision surface. 1291 F32 zi = 2 * mFabs(mRigid.getZeroImpulse(r,c.normal)); 1292 F32 s = (mDataBlock->collisionTol - c.distance) * zi - ((vn / mDataBlock->contactTol) * zi); 1293 Point3F f = c.normal * s; 1294 1295 // Friction impulse, calculated as a function of the 1296 // amount of force it would take to stop the motion 1297 // perpendicular to the normal. 1298 Point3F uv = v - (c.normal * vn); 1299 F32 ul = uv.len(); 1300 if (s > 0 && ul) 1301 { 1302 uv /= -ul; 1303 F32 u = ul * ns.getZeroImpulse(r,uv); 1304 s *= mRigid.friction; 1305 if (u > s) 1306 u = s; 1307 f += uv * u; 1308 } 1309 1310 // Accumulate forces 1311 p += f; 1312 mCross(r,f,&t); 1313 l += t; 1314 } 1315 } 1316 } 1317 1318 // Contact constraint forces act over time... 1319 ns.linMomentum += p * dt; 1320 ns.angMomentum += l * dt; 1321 ns.updateVelocity(); 1322 return true; 1323} 1324 1325 1326//---------------------------------------------------------------------------- 1327 1328bool RigidShape::resolveDisplacement(Rigid& ns,CollisionState *state, F32 dt) 1329{ 1330 SceneObject* obj = (state->a->getObject() == this)? 1331 state->b->getObject(): state->a->getObject(); 1332 1333 if (obj->isDisplacable() && ((obj->getTypeMask() & ShapeBaseObjectType) != 0)) 1334 { 1335 // Try to displace the object by the amount we're trying to move 1336 Point3F objNewMom = ns.linVelocity * obj->getMass() * 1.1f; 1337 Point3F objOldMom = obj->getMomentum(); 1338 Point3F objNewVel = objNewMom / obj->getMass(); 1339 1340 Point3F myCenter; 1341 Point3F theirCenter; 1342 getWorldBox().getCenter(&myCenter); 1343 obj->getWorldBox().getCenter(&theirCenter); 1344 if (mDot(myCenter - theirCenter, objNewMom) >= 0.0f || objNewVel.len() < 0.01) 1345 { 1346 objNewMom = (theirCenter - myCenter); 1347 objNewMom.normalize(); 1348 objNewMom *= 1.0f * obj->getMass(); 1349 objNewVel = objNewMom / obj->getMass(); 1350 } 1351 1352 obj->setMomentum(objNewMom); 1353 if (obj->displaceObject(objNewVel * 1.1f * dt) == true) 1354 { 1355 // Queue collision and change in velocity 1356 VectorF dv = (objOldMom - objNewMom) / obj->getMass(); 1357 queueCollision(static_cast<ShapeBase*>(obj), dv); 1358 return true; 1359 } 1360 } 1361 1362 return false; 1363} 1364 1365 1366//---------------------------------------------------------------------------- 1367 1368void RigidShape::updateWorkingCollisionSet(const U32 mask) 1369{ 1370 Box3F convexBox = mConvex.getBoundingBox(getTransform(), getScale()); 1371 F32 len = (mRigid.linVelocity.len() + 50) * TickSec; 1372 F32 l = (len * 1.1) + 0.1; // fudge factor 1373 convexBox.minExtents -= Point3F(l, l, l); 1374 convexBox.maxExtents += Point3F(l, l, l); 1375 1376 disableCollision(); 1377 mConvex.updateWorkingList(convexBox, mask); 1378 enableCollision(); 1379} 1380 1381 1382//---------------------------------------------------------------------------- 1383/** Check collisions with trigger and items 1384Perform a container search using the current bounding box 1385of the main body, wheels are not included. This method should 1386only be called on the server. 1387*/ 1388void RigidShape::checkTriggers() 1389{ 1390 Box3F bbox = mConvex.getBoundingBox(getTransform(), getScale()); 1391 gServerContainer.findObjects(bbox,sTriggerMask,findCallback,this); 1392} 1393 1394/** The callback used in by the checkTriggers() method. 1395The checkTriggers method uses a container search which will 1396invoke this callback on each obj that matches. 1397*/ 1398void RigidShape::findCallback(SceneObject* obj,void *key) 1399{ 1400 RigidShape* shape = reinterpret_cast<RigidShape*>(key); 1401 U32 objectMask = obj->getTypeMask(); 1402 1403 // Check: triggers, corpses and items, basically the same things 1404 // that the player class checks for 1405 if (objectMask & TriggerObjectType) { 1406 Trigger* pTrigger = static_cast<Trigger*>(obj); 1407 pTrigger->potentialEnterObject(shape); 1408 } 1409 else if (objectMask & CorpseObjectType) { 1410 ShapeBase* col = static_cast<ShapeBase*>(obj); 1411 shape->queueCollision(col,shape->getVelocity() - col->getVelocity()); 1412 } 1413 else if (objectMask & ItemObjectType) { 1414 Item* item = static_cast<Item*>(obj); 1415 if (shape != item->getCollisionObject()) 1416 shape->queueCollision(item,shape->getVelocity() - item->getVelocity()); 1417 } 1418} 1419 1420 1421//---------------------------------------------------------------------------- 1422 1423void RigidShape::writePacketData(GameConnection *connection, BitStream *stream) 1424{ 1425 Parent::writePacketData(connection, stream); 1426 1427 mathWrite(*stream, mRigid.linPosition); 1428 mathWrite(*stream, mRigid.angPosition); 1429 mathWrite(*stream, mRigid.linMomentum); 1430 mathWrite(*stream, mRigid.angMomentum); 1431 stream->writeFlag(mRigid.atRest); 1432 stream->writeFlag(mContacts.getCount() == 0); 1433 1434 stream->writeFlag(mDisableMove); 1435 stream->setCompressionPoint(mRigid.linPosition); 1436} 1437 1438void RigidShape::readPacketData(GameConnection *connection, BitStream *stream) 1439{ 1440 Parent::readPacketData(connection, stream); 1441 1442 mathRead(*stream, &mRigid.linPosition); 1443 mathRead(*stream, &mRigid.angPosition); 1444 mathRead(*stream, &mRigid.linMomentum); 1445 mathRead(*stream, &mRigid.angMomentum); 1446 mRigid.atRest = stream->readFlag(); 1447 if (stream->readFlag()) 1448 mContacts.clear(); 1449 mRigid.updateInertialTensor(); 1450 mRigid.updateVelocity(); 1451 1452 mDisableMove = stream->readFlag(); 1453 stream->setCompressionPoint(mRigid.linPosition); 1454} 1455 1456 1457//---------------------------------------------------------------------------- 1458 1459U32 RigidShape::packUpdate(NetConnection *con, U32 mask, BitStream *stream) 1460{ 1461 U32 retMask = Parent::packUpdate(con, mask, stream); 1462 1463 // The rest of the data is part of the control object packet update. 1464 // If we're controlled by this client, we don't need to send it. 1465 if (stream->writeFlag(getControllingClient() == con && !(mask & InitialUpdateMask))) 1466 return retMask; 1467 1468 mDelta.move.pack(stream); 1469 1470 if (stream->writeFlag(mask & PositionMask)) 1471 { 1472 stream->writeFlag(mask & ForceMoveMask); 1473 1474 stream->writeCompressedPoint(mRigid.linPosition); 1475 mathWrite(*stream, mRigid.angPosition); 1476 mathWrite(*stream, mRigid.linMomentum); 1477 mathWrite(*stream, mRigid.angMomentum); 1478 stream->writeFlag(mRigid.atRest); 1479 } 1480 1481 if(stream->writeFlag(mask & FreezeMask)) 1482 stream->writeFlag(mDisableMove); 1483 1484 return retMask; 1485} 1486 1487void RigidShape::unpackUpdate(NetConnection *con, BitStream *stream) 1488{ 1489 Parent::unpackUpdate(con,stream); 1490 1491 if (stream->readFlag()) 1492 return; 1493 1494 mDelta.move.unpack(stream); 1495 1496 if (stream->readFlag()) 1497 { 1498 // Check if we need to jump to the given transform 1499 // rather than interpolate to it. 1500 bool forceUpdate = stream->readFlag(); 1501 1502 mPredictionCount = sMaxPredictionTicks; 1503 F32 speed = mRigid.linVelocity.len(); 1504 mDelta.warpRot[0] = mRigid.angPosition; 1505 1506 // Read in new position and momentum values 1507 stream->readCompressedPoint(&mRigid.linPosition); 1508 mathRead(*stream, &mRigid.angPosition); 1509 mathRead(*stream, &mRigid.linMomentum); 1510 mathRead(*stream, &mRigid.angMomentum); 1511 mRigid.atRest = stream->readFlag(); 1512 mRigid.updateVelocity(); 1513 1514 if (!forceUpdate && isProperlyAdded()) 1515 { 1516 // Determine number of ticks to warp based on the average 1517 // of the client and server velocities. 1518 Point3F cp = mDelta.pos + mDelta.posVec * mDelta.dt; 1519 mDelta.warpOffset = mRigid.linPosition - cp; 1520 1521 // Calc the distance covered in one tick as the average of 1522 // the old speed and the new speed from the server. 1523 F32 dt,as = (speed + mRigid.linVelocity.len()) * 0.5 * TickSec; 1524 1525 // Cal how many ticks it will take to cover the warp offset. 1526 // If it's less than what's left in the current tick, we'll just 1527 // warp in the remaining time. 1528 if (!as || (dt = mDelta.warpOffset.len() / as) > sMaxWarpTicks) 1529 dt = mDelta.dt + sMaxWarpTicks; 1530 else 1531 dt = (dt <= mDelta.dt)? mDelta.dt : mCeil(dt - mDelta.dt) + mDelta.dt; 1532 1533 // Adjust current frame interpolation 1534 if (mDelta.dt) 1535 { 1536 mDelta.pos = cp + (mDelta.warpOffset * (mDelta.dt / dt)); 1537 mDelta.posVec = (cp - mDelta.pos) / mDelta.dt; 1538 QuatF cr; 1539 cr.interpolate(mDelta.rot[1],mDelta.rot[0],mDelta.dt); 1540 mDelta.rot[1].interpolate(cr,mRigid.angPosition,mDelta.dt / dt); 1541 mDelta.rot[0].extrapolate(mDelta.rot[1],cr,mDelta.dt); 1542 } 1543 1544 // Calculated multi-tick warp 1545 mDelta.warpCount = 0; 1546 mDelta.warpTicks = (S32)(mFloor(dt)); 1547 if (mDelta.warpTicks) 1548 { 1549 mDelta.warpOffset = mRigid.linPosition - mDelta.pos; 1550 mDelta.warpOffset /= mDelta.warpTicks; 1551 mDelta.warpRot[0] = mDelta.rot[1]; 1552 mDelta.warpRot[1] = mRigid.angPosition; 1553 } 1554 } 1555 else 1556 { 1557 // Set the shape to the server position 1558 mDelta.dt = 0; 1559 mDelta.pos = mRigid.linPosition; 1560 mDelta.posVec.set(0,0,0); 1561 mDelta.rot[1] = mDelta.rot[0] = mRigid.angPosition; 1562 mDelta.warpCount = mDelta.warpTicks = 0; 1563 setPosition(mRigid.linPosition, mRigid.angPosition); 1564 } 1565 } 1566 1567 if(stream->readFlag()) 1568 mDisableMove = stream->readFlag(); 1569} 1570 1571 1572//---------------------------------------------------------------------------- 1573 1574void RigidShape::initPersistFields() 1575{ 1576 Parent::initPersistFields(); 1577} 1578 1579//---------------------------------------------------------------------------- 1580 1581void RigidShape::updateLiftoffDust( F32 dt ) 1582{ 1583 Point3F offset( 0.0, 0.0, mDataBlock->dustHeight ); 1584 emitDust( mDustEmitterList[ 0 ], mDataBlock->triggerDustHeight, offset, 1585 ( U32 )( dt * 1000 ) ); 1586} 1587 1588//-------------------------------------------------------------------------- 1589void RigidShape::updateFroth( F32 dt ) 1590{ 1591 // update bubbles 1592 Point3F moveDir = getVelocity(); 1593 1594 Point3F contactPoint; 1595 1596 F32 speed = moveDir.len(); 1597 if( speed < mDataBlock->splashVelEpsilon ) speed = 0.0; 1598 1599 U32 emitRate = (U32)(speed * mDataBlock->splashFreqMod * dt); 1600 1601 U32 i; 1602 for( i=0; i<RigidShapeData::VC_NUM_SPLASH_EMITTERS; i++ ) 1603 { 1604 if( mSplashEmitterList[i] ) 1605 { 1606 mSplashEmitterList[i]->emitParticles( contactPoint, contactPoint, Point3F( 0.0, 0.0, 1.0 ), 1607 moveDir, emitRate ); 1608 } 1609 } 1610 1611} 1612 1613//-------------------------------------------------------------------------- 1614// Returns true if shape is intersecting a water surface (roughly) 1615//-------------------------------------------------------------------------- 1616bool RigidShape::collidingWithWater( Point3F &waterHeight ) 1617{ 1618 Point3F curPos = getPosition(); 1619 1620 F32 height = mFabs( mObjBox.maxExtents.z - mObjBox.minExtents.z ); 1621 1622 RayInfo rInfo; 1623 if( gClientContainer.castRay( curPos + Point3F(0.0, 0.0, height), curPos, WaterObjectType, &rInfo) ) 1624 { 1625 waterHeight = rInfo.point; 1626 return true; 1627 } 1628 1629 return false; 1630} 1631 1632void RigidShape::setEnergyLevel(F32 energy) 1633{ 1634 Parent::setEnergyLevel(energy); 1635 setMaskBits(EnergyMask); 1636} 1637 1638void RigidShape::prepBatchRender( SceneRenderState *state, S32 mountedImageIndex ) 1639{ 1640 Parent::prepBatchRender( state, mountedImageIndex ); 1641 1642 if ( !gShowBoundingBox ) 1643 return; 1644 1645 ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 1646 ri->renderDelegate.bind( this, &RigidShape::_renderMassAndContacts ); 1647 ri->type = RenderPassManager::RIT_Editor; 1648 state->getRenderPass()->addInst( ri ); 1649} 1650 1651void RigidShape::_renderMassAndContacts( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) 1652{ 1653 // Box for the center of Mass 1654 GFXStateBlockDesc desc; 1655 desc.setBlend(false, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha); 1656 desc.setZReadWrite(false); 1657 desc.fillMode = GFXFillWireframe; 1658 1659 GFX->getDrawUtil()->drawCube( desc, Point3F(0.1f,0.1f,0.1f), mDataBlock->massCenter, ColorI(255, 255, 255), &mRenderObjToWorld ); 1660 1661 // Collision points... 1662 for (S32 i = 0; i < mCollisionList.getCount(); i++) 1663 { 1664 const Collision& collision = mCollisionList[i]; 1665 GFX->getDrawUtil()->drawCube( desc, Point3F(0.05f,0.05f,0.05f), collision.point, ColorI(0, 0, 255) ); 1666 } 1667 1668 // Render the normals as one big batch... 1669 PrimBuild::begin(GFXLineList, mCollisionList.getCount() * 2); 1670 for (S32 i = 0; i < mCollisionList.getCount(); i++) 1671 { 1672 1673 const Collision& collision = mCollisionList[i]; 1674 PrimBuild::color3f(1, 1, 1); 1675 PrimBuild::vertex3fv(collision.point); 1676 PrimBuild::vertex3fv(collision.point + collision.normal * 0.05f); 1677 } 1678 PrimBuild::end(); 1679 1680 // Build and render the collision polylist which is returned 1681 // in the server's world space. 1682 ClippedPolyList polyList; 1683 polyList.mPlaneList.setSize(6); 1684 polyList.mPlaneList[0].set(getWorldBox().minExtents,VectorF(-1,0,0)); 1685 polyList.mPlaneList[1].set(getWorldBox().minExtents,VectorF(0,-1,0)); 1686 polyList.mPlaneList[2].set(getWorldBox().minExtents,VectorF(0,0,-1)); 1687 polyList.mPlaneList[3].set(getWorldBox().maxExtents,VectorF(1,0,0)); 1688 polyList.mPlaneList[4].set(getWorldBox().maxExtents,VectorF(0,1,0)); 1689 polyList.mPlaneList[5].set(getWorldBox().maxExtents,VectorF(0,0,1)); 1690 Box3F dummyBox; 1691 SphereF dummySphere; 1692 buildPolyList(PLC_Collision, &polyList, dummyBox, dummySphere); 1693 //polyList.render(); 1694} 1695 1696void RigidShape::reset() 1697{ 1698 mRigid.clearForces(); 1699 mRigid.setAtRest(); 1700} 1701 1702void RigidShape::freezeSim(bool frozen) 1703{ 1704 mDisableMove = frozen; 1705 setMaskBits(FreezeMask); 1706} 1707 1708DefineEngineMethod( RigidShape, reset, void, (),, 1709 "@brief Clears physic forces from the shape and sets it at rest.\n\n" 1710 "@tsexample\n" 1711 "// Inform the RigidShape object to reset.\n" 1712 "%thisRigidShape.reset();\n" 1713 "@endtsexample\n\n" 1714 "@see ShapeBaseData") 1715{ 1716 object->reset(); 1717} 1718 1719DefineEngineMethod( RigidShape, freezeSim, void, (bool isFrozen),, 1720 "@brief Enables or disables the physics simulation on the RigidShape object.\n\n" 1721 "@param isFrozen Boolean frozen state to set the object.\n" 1722 "@tsexample\n" 1723 "// Define the frozen state.\n" 1724 "%isFrozen = \"true\";\n\n" 1725 "// Inform the object of the defined frozen state\n" 1726 "%thisRigidShape.freezeSim(%isFrozen);\n" 1727 "@endtsexample\n\n" 1728 "@see ShapeBaseData") 1729{ 1730 object->freezeSim(isFrozen); 1731} 1732 1733DefineEngineMethod( RigidShape, forceClientTransform, void, (),, 1734 "@brief Forces the client to jump to the RigidShape's transform rather then warp to it.\n\n") 1735{ 1736 if(object->isServerObject()) 1737 { 1738 object->forceClientTransform(); 1739 } 1740} 1741
