1 module unecht.core.components.physics.dynamic; 2 3 import derelict.ode.ode; 4 import derelict.util.system; 5 6 import unecht.core.component; 7 import unecht.core.defaultInspector; 8 import unecht.core.components.physics.system; 9 10 import gl3n.linalg; 11 12 /// 13 @UEDefaultInspector!UEPhysicsBody 14 final class UEPhysicsBody : UEComponent 15 { 16 mixin(UERegisterObject!()); 17 18 void addForce(vec3 _v) 19 { 20 dBodyAddForce(Body, _v.x, _v.y, _v.z); 21 } 22 23 void setDamping(float _v) 24 { 25 dBodySetLinearDamping(Body, _v); 26 } 27 28 vec3 getVelocity() { 29 auto vel = dBodyGetLinearVel(Body); 30 return vec3(vel[0..2]); 31 } 32 33 void setVelocity(vec3 _v) { 34 dBodySetLinearVel(Body, _v.x,_v.y,_v.z); 35 } 36 37 override void onCreate() { 38 super.onCreate; 39 40 // This brings us to the end of the world settings, now we have to initialize the objects themselves. 41 // Create a new body for our object in the world and get its ID. 42 Body = dBodyCreate(UEPhysicsSystem.world); 43 44 auto pos = sceneNode.position; 45 dBodySetPosition(Body, pos.x, pos.y, pos.z); 46 auto rot = sceneNode.rotation; 47 dBodySetQuaternion(Body, rot.quaternion); 48 49 // Here I have set the initial linear velocity to stationary and let gravity do the work, but you can experiment 50 // with the velocity vector to change the starting behaviour. You can also set the rotational velocity for the new 51 // body using dBodySetAngularVel which takes the same parameters. 52 dBodySetLinearVel(Body, 0,0,0); 53 54 dBodySetData(Body, cast(void*)this); 55 56 // Now we need to create a box mass to go with our geom. First we create a new dMass structure (the internals 57 // of which aren't important at the moment) then create an array of 3 float (dReal) values and set them 58 // to the side lengths of our box along the x, y and z axes. We then pass the both of these to dMassSetBox with a 59 // pre-defined DENSITY value of 0.5 in this case. 60 dMass m; 61 62 dReal[3] sides; 63 sides[0] = 2.0; 64 sides[1] = 2.0; 65 sides[2] = 2.0; 66 static immutable DENSITY = 1.0f; 67 dMassSetBox(&m, DENSITY, sides[0], sides[1], sides[2]); 68 69 // We can then apply this mass to our objects body. 70 dBodySetMass(Body, &m); 71 } 72 73 override void onDestroy() { 74 super.onDestroy; 75 76 //reactivate connected bodies 77 auto n = dBodyGetNumJoints(Body); 78 79 foreach(i; 0..n) 80 { 81 auto joint = dBodyGetJoint(Body, i); 82 auto body0 = dJointGetBody(joint,0); 83 auto body1 = dJointGetBody(joint,1); 84 if(body0) 85 dBodyEnable(body0); 86 if(body1) 87 dBodyEnable(body1); 88 } 89 90 dBodyDestroy(Body); 91 Body = null; 92 } 93 94 /// 95 override void onUpdate() { 96 auto doEnable = lastPos != sceneNode.position || 97 lastAngles != sceneNode.angles; 98 99 if(doEnable) 100 dBodyEnable(Body); 101 102 if(lastPos != sceneNode.position) 103 dBodySetPosition(Body, sceneNode.position.x,sceneNode.position.y,sceneNode.position.z); 104 105 if(lastAngles != sceneNode.angles) 106 dBodySetQuaternion(Body, sceneNode.rotation.quaternion); 107 108 //TODO: use CopyPosition to save mem traffic 109 auto pos = dBodyGetPosition(Body); 110 quat rot; 111 dBodyCopyQuaternion(Body, rot.quaternion); 112 113 this.sceneNode.position = lastPos = vec3(pos[0..3]); 114 this.sceneNode.rotation = rot; 115 116 lastAngles = sceneNode.angles; 117 } 118 119 private: 120 vec3 lastPos; 121 vec3 lastAngles; 122 123 package dBodyID Body; // the dynamics body 124 }