aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODECharacter.cs247
1 files changed, 181 insertions, 66 deletions
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
index 8e92171..b824cbe 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
@@ -34,6 +34,26 @@ using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.OdePlugin 35namespace OpenSim.Region.Physics.OdePlugin
36{ 36{
37 /// <summary>
38 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
39 /// </summary>
40
41 public enum dParam : int
42 {
43 LowStop = 0,
44 HiStop = 1,
45 Vel = 2,
46 FMax = 3,
47 FudgeFactor = 4,
48 Bounce = 5,
49 CFM = 6,
50 ERP = 7,
51 StopCFM = 8,
52 LoStop2 = 256,
53 HiStop2 = 257,
54 LoStop3 = 512,
55 HiStop3 = 513
56 }
37 public class OdeCharacter : PhysicsActor 57 public class OdeCharacter : PhysicsActor
38 { 58 {
39 private PhysicsVector _position; 59 private PhysicsVector _position;
@@ -45,7 +65,8 @@ namespace OpenSim.Region.Physics.OdePlugin
45 private PhysicsVector _target_velocity; 65 private PhysicsVector _target_velocity;
46 private PhysicsVector _acceleration; 66 private PhysicsVector _acceleration;
47 private PhysicsVector m_rotationalVelocity; 67 private PhysicsVector m_rotationalVelocity;
48 private float m_density = 50f; 68 private float m_mass = 80f;
69 private float m_density = 60f;
49 private bool m_pidControllerActive = true; 70 private bool m_pidControllerActive = true;
50 private static float PID_D = 3020.0f; 71 private static float PID_D = 3020.0f;
51 private static float PID_P = 7000.0f; 72 private static float PID_P = 7000.0f;
@@ -96,34 +117,7 @@ namespace OpenSim.Region.Physics.OdePlugin
96 117
97 lock (OdeScene.OdeLock) 118 lock (OdeScene.OdeLock)
98 { 119 {
99 int dAMotorEuler = 1; 120 AvatarGeomAndBodyCreation(pos.X, pos.Y, pos.Z);
100 Shell = d.CreateCapsule(parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
101 d.MassSetCapsule(out ShellMass, m_density, 3, CAPSULE_RADIUS, CAPSULE_LENGTH);
102 Body = d.BodyCreate(parent_scene.world);
103 d.BodySetMass(Body, ref ShellMass);
104 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
105 d.GeomSetBody(Shell, Body);
106
107
108 d.BodySetRotation(Body, ref m_StandUpRotation);
109
110
111 //Amotor = d.JointCreateAMotor(parent_scene.world, IntPtr.Zero);
112 //d.JointAttach(Amotor, Body, IntPtr.Zero);
113 //d.JointSetAMotorMode(Amotor, dAMotorEuler);
114 //d.JointSetAMotorNumAxes(Amotor, 3);
115 //d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0);
116 //d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0);
117 ///d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1);
118 //d.JointSetAMotorAngle(Amotor, 0, 0);
119 //d.JointSetAMotorAngle(Amotor, 1, 0);
120 //d.JointSetAMotorAngle(Amotor, 2, 0);
121 //d.JointSetAMotorParam(Amotor, 0, -0);
122 //d.JointSetAMotorParam(Amotor, 0x200, -0);
123 //d.JointSetAMotorParam(Amotor, 0x100, -0);
124 // d.JointSetAMotorParam(Amotor, 0, 0);
125 // d.JointSetAMotorParam(Amotor, 3, 0);
126 // d.JointSetAMotorParam(Amotor, 2, 0);
127 } 121 }
128 m_name = avName; 122 m_name = avName;
129 parent_scene.geom_name_map[Shell] = avName; 123 parent_scene.geom_name_map[Shell] = avName;
@@ -136,6 +130,9 @@ namespace OpenSim.Region.Physics.OdePlugin
136 set { return; } 130 set { return; }
137 } 131 }
138 132
133 /// <summary>
134 /// If this is set, the avatar will move faster
135 /// </summary>
139 public override bool SetAlwaysRun 136 public override bool SetAlwaysRun
140 { 137 {
141 get { return m_alwaysRun; } 138 get { return m_alwaysRun; }
@@ -160,6 +157,10 @@ namespace OpenSim.Region.Physics.OdePlugin
160 set { flying = value; } 157 set { flying = value; }
161 } 158 }
162 159
160 /// <summary>
161 /// Returns if the avatar is colliding in general.
162 /// This includes the ground and objects and avatar.
163 /// </summary>
163 public override bool IsColliding 164 public override bool IsColliding
164 { 165 {
165 get { return m_iscolliding; } 166 get { return m_iscolliding; }
@@ -208,11 +209,17 @@ namespace OpenSim.Region.Physics.OdePlugin
208 } 209 }
209 } 210 }
210 211
212 /// <summary>
213 /// Returns if an avatar is colliding with the ground
214 /// </summary>
211 public override bool CollidingGround 215 public override bool CollidingGround
212 { 216 {
213 get { return m_iscollidingGround; } 217 get { return m_iscollidingGround; }
214 set 218 set
215 { 219 {
220 // Collisions against the ground are not really reliable
221 // So, to get a consistant value we have to average the current result over time
222 // Currently we use 1 second = 10 calls to this.
216 int i; 223 int i;
217 int truecount = 0; 224 int truecount = 0;
218 int falsecount = 0; 225 int falsecount = 0;
@@ -256,6 +263,9 @@ namespace OpenSim.Region.Physics.OdePlugin
256 } 263 }
257 } 264 }
258 265
266 /// <summary>
267 /// Returns if the avatar is colliding with an object
268 /// </summary>
259 public override bool CollidingObj 269 public override bool CollidingObj
260 { 270 {
261 get { return m_iscollidingObj; } 271 get { return m_iscollidingObj; }
@@ -269,11 +279,21 @@ namespace OpenSim.Region.Physics.OdePlugin
269 } 279 }
270 } 280 }
271 281
282 /// <summary>
283 /// turn the PID controller on or off.
284 /// The PID Controller will turn on all by itself in many situations
285 /// </summary>
286 /// <param name="status"></param>
272 public void SetPidStatus(bool status) 287 public void SetPidStatus(bool status)
273 { 288 {
274 m_pidControllerActive = status; 289 m_pidControllerActive = status;
275 } 290 }
276 291
292 /// <summary>
293 /// This 'puts' an avatar somewhere in the physics space.
294 /// Not really a good choice unless you 'know' it's a good
295 /// spot otherwise you're likely to orbit the avatar.
296 /// </summary>
277 public override PhysicsVector Position 297 public override PhysicsVector Position
278 { 298 {
279 get { return _position; } 299 get { return _position; }
@@ -293,6 +313,10 @@ namespace OpenSim.Region.Physics.OdePlugin
293 set { m_rotationalVelocity = value; } 313 set { m_rotationalVelocity = value; }
294 } 314 }
295 315
316 /// <summary>
317 /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight
318 /// and use it to offset landings properly
319 /// </summary>
296 public override PhysicsVector Size 320 public override PhysicsVector Size
297 { 321 {
298 get { return new PhysicsVector(CAPSULE_RADIUS*2, CAPSULE_RADIUS*2, CAPSULE_LENGTH); } 322 get { return new PhysicsVector(CAPSULE_RADIUS*2, CAPSULE_RADIUS*2, CAPSULE_LENGTH); }
@@ -301,6 +325,7 @@ namespace OpenSim.Region.Physics.OdePlugin
301 m_pidControllerActive = true; 325 m_pidControllerActive = true;
302 lock (OdeScene.OdeLock) 326 lock (OdeScene.OdeLock)
303 { 327 {
328 d.JointDestroy(Amotor);
304 PhysicsVector SetSize = value; 329 PhysicsVector SetSize = value;
305 float prevCapsule = CAPSULE_LENGTH; 330 float prevCapsule = CAPSULE_LENGTH;
306 float capsuleradius = CAPSULE_RADIUS; 331 float capsuleradius = CAPSULE_RADIUS;
@@ -309,20 +334,91 @@ namespace OpenSim.Region.Physics.OdePlugin
309 CAPSULE_LENGTH = (SetSize.Z - ((SetSize.Z*0.43f))); // subtract 43% of the size 334 CAPSULE_LENGTH = (SetSize.Z - ((SetSize.Z*0.43f))); // subtract 43% of the size
310 d.BodyDestroy(Body); 335 d.BodyDestroy(Body);
311 d.GeomDestroy(Shell); 336 d.GeomDestroy(Shell);
312 //MainLog.Instance.Verbose("PHYSICS", "Set Avatar Height To: " + (CAPSULE_RADIUS + CAPSULE_LENGTH)); 337 AvatarGeomAndBodyCreation(_position.X, _position.Y,
313 Shell = d.CreateCapsule(_parent_scene.space, capsuleradius, CAPSULE_LENGTH); 338 _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule)*2));
314 d.MassSetCapsule(out ShellMass, m_density, 3, CAPSULE_RADIUS, CAPSULE_LENGTH); 339 Velocity = new PhysicsVector(0f, 0f, 0f);
315 Body = d.BodyCreate(_parent_scene.world); 340
316 d.BodySetMass(Body, ref ShellMass);
317 d.BodySetPosition(Body, _position.X, _position.Y,
318 _position.Z + Math.Abs(CAPSULE_LENGTH - prevCapsule));
319 d.GeomSetBody(Shell, Body);
320 } 341 }
321 _parent_scene.geom_name_map[Shell] = m_name; 342 _parent_scene.geom_name_map[Shell] = m_name;
322 _parent_scene.actor_name_map[Shell] = (PhysicsActor) this; 343 _parent_scene.actor_name_map[Shell] = (PhysicsActor) this;
323 } 344 }
324 } 345 }
346 /// <summary>
347 /// This creates the Avatar's physical Surrogate at the position supplied
348 /// </summary>
349 /// <param name="npositionX"></param>
350 /// <param name="npositionY"></param>
351 /// <param name="npositionZ"></param>
352 private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ)
353 {
354 int dAMotorEuler = 1;
355 Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
356 d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH);
357 Body = d.BodyCreate(_parent_scene.world);
358 d.BodySetPosition(Body, npositionX, npositionY, npositionZ);
359
360 d.BodySetMass(Body, ref ShellMass);
361
362 // 90 Stand up on the cap of the capped cyllinder
363 d.RFromAxisAndAngle(out m_StandUpRotation, 1, 0, 0, (float)(Math.PI / 2));
364
365
366 d.GeomSetRotation(Shell, ref m_StandUpRotation);
367 d.BodySetRotation(Body, ref m_StandUpRotation);
368
369 d.GeomSetBody(Shell, Body);
370
371
372 // The purpose of the AMotor here is to keep the avatar's physical
373 // surrogate from rotating while moving
374 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
375 d.JointAttach(Amotor, Body, IntPtr.Zero);
376 d.JointSetAMotorMode(Amotor, dAMotorEuler);
377 d.JointSetAMotorNumAxes(Amotor, 3);
378 d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0);
379 d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0);
380 d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1);
381 d.JointSetAMotorAngle(Amotor, 0, 0);
382 d.JointSetAMotorAngle(Amotor, 1, 0);
383 d.JointSetAMotorAngle(Amotor, 2, 0);
384
385 // These lowstops and high stops are effectively (no wiggle room)
386 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f);
387 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f);
388 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f);
389 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f);
390 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f);
391 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f);
392
393 // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the
394 // capped cyllinder will fall over
395 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
396 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, 3800000f);
397
398
399 // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air.
400 // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you
401 // change appearance and when you enter the simulator
402 // After this routine is done, the amotor stabilizes much quicker
403 d.Vector3 feet;
404 d.Vector3 head;
405 d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet);
406 d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head);
407 float posture = head.Z - feet.Z;
408
409 // restoring force proportional to lack of posture:
410 float servo = (2.5f - posture) * POSTURE_SERVO;
411 d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f);
412 d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f);
413
414
415 }
325 416
417 //
418 /// <summary>
419 /// Uses the capped cyllinder volume formula to calculate the avatar's mass.
420 /// This may be used in calculations in the scene/scenepresence
421 /// </summary>
326 public override float Mass 422 public override float Mass
327 { 423 {
328 get 424 get
@@ -385,6 +481,11 @@ namespace OpenSim.Region.Physics.OdePlugin
385 _acceleration = accel; 481 _acceleration = accel;
386 } 482 }
387 483
484 /// <summary>
485 /// Adds the force supplied to the Target Velocity
486 /// The PID controller takes this target velocity and tries to make it a reality
487 /// </summary>
488 /// <param name="force"></param>
388 public override void AddForce(PhysicsVector force) 489 public override void AddForce(PhysicsVector force)
389 { 490 {
390 m_pidControllerActive = true; 491 m_pidControllerActive = true;
@@ -395,29 +496,15 @@ namespace OpenSim.Region.Physics.OdePlugin
395 //m_lastUpdateSent = false; 496 //m_lastUpdateSent = false;
396 } 497 }
397 498
499 /// <summary>
500 /// After all of the forces add up with 'add force' we apply them with doForce
501 /// </summary>
502 /// <param name="force"></param>
398 public void doForce(PhysicsVector force) 503 public void doForce(PhysicsVector force)
399 { 504 {
400 if (!collidelock) 505 if (!collidelock)
401 { 506 {
402 d.BodyAddForce(Body, force.X, force.Y, force.Z); 507 d.BodyAddForce(Body, force.X, force.Y, force.Z);
403
404 // ok -- let's stand up straight!
405 //d.Matrix3 StandUpRotationalMatrix = new d.Matrix3(0.8184158f, -0.5744568f, -0.0139677f, 0.5744615f, 0.8185215f, -0.004074608f, 0.01377355f, -0.004689182f, 0.9998941f);
406 //d.BodySetRotation(Body, ref StandUpRotationalMatrix);
407 //d.BodySetRotation(Body, ref m_StandUpRotation);
408 // The above matrix was generated with the amazing standup routine below by danX0r *cheer*
409 d.Vector3 feet;
410 d.Vector3 head;
411 d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet);
412 d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head);
413 float posture = head.Z - feet.Z;
414
415 // restoring force proportional to lack of posture:
416 float servo = (2.5f - posture) * POSTURE_SERVO;
417 d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f);
418 d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f);
419
420 //m_lastUpdateSent = false;
421 } 508 }
422 } 509 }
423 510
@@ -425,9 +512,19 @@ namespace OpenSim.Region.Physics.OdePlugin
425 { 512 {
426 } 513 }
427 514
515
516 /// <summary>
517 /// Called from Simulate
518 /// This is the avatar's movement control + PID Controller
519 /// </summary>
520 /// <param name="timeStep"></param>
428 public void Move(float timeStep) 521 public void Move(float timeStep)
429 { 522 {
430 // no lock; for now it's only called from within Simulate() 523 // no lock; for now it's only called from within Simulate()
524
525 // If the PID Controller isn't active then we set our force
526 // calculating base velocity to the current position
527
431 if (m_pidControllerActive == false) 528 if (m_pidControllerActive == false)
432 { 529 {
433 _zeroPosition = d.BodyGetPosition(Body); 530 _zeroPosition = d.BodyGetPosition(Body);
@@ -458,6 +555,11 @@ namespace OpenSim.Region.Physics.OdePlugin
458 } 555 }
459 if (m_pidControllerActive) 556 if (m_pidControllerActive)
460 { 557 {
558 // We only want to deactivate the PID Controller if we think we want to have our surrogate
559 // react to the physics scene by moving it's position.
560 // Avatar to Avatar collisions
561 // Prim to avatar collisions
562
461 d.Vector3 pos = d.BodyGetPosition(Body); 563 d.Vector3 pos = d.BodyGetPosition(Body);
462 vec.X = (_target_velocity.X - vel.X)*PID_D + (_zeroPosition.X - pos.X)*PID_P; 564 vec.X = (_target_velocity.X - vel.X)*PID_D + (_zeroPosition.X - pos.X)*PID_P;
463 vec.Y = (_target_velocity.Y - vel.Y)*PID_D + (_zeroPosition.Y - pos.Y)*PID_P; 565 vec.Y = (_target_velocity.Y - vel.Y)*PID_D + (_zeroPosition.Y - pos.Y)*PID_P;
@@ -474,11 +576,14 @@ namespace OpenSim.Region.Physics.OdePlugin
474 _zeroFlag = false; 576 _zeroFlag = false;
475 if (m_iscolliding || flying) 577 if (m_iscolliding || flying)
476 { 578 {
579 // We're flying and colliding with something
477 vec.X = ((_target_velocity.X/movementdivisor) - vel.X)*PID_D; 580 vec.X = ((_target_velocity.X/movementdivisor) - vel.X)*PID_D;
478 vec.Y = ((_target_velocity.Y/movementdivisor) - vel.Y)*PID_D; 581 vec.Y = ((_target_velocity.Y/movementdivisor) - vel.Y)*PID_D;
479 } 582 }
480 if (m_iscolliding && !flying && _target_velocity.Z > 0.0f) 583 if (m_iscolliding && !flying && _target_velocity.Z > 0.0f)
481 { 584 {
585 // We're colliding with something and we're not flying but we're moving
586 // This means we're walking or running.
482 d.Vector3 pos = d.BodyGetPosition(Body); 587 d.Vector3 pos = d.BodyGetPosition(Body);
483 vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P; 588 vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P;
484 if (_target_velocity.X > 0) 589 if (_target_velocity.X > 0)
@@ -492,6 +597,8 @@ namespace OpenSim.Region.Physics.OdePlugin
492 } 597 }
493 else if (!m_iscolliding && !flying) 598 else if (!m_iscolliding && !flying)
494 { 599 {
600 // we're not colliding and we're not flying so that means we're falling!
601 // m_iscolliding includes collisions with the ground.
495 d.Vector3 pos = d.BodyGetPosition(Body); 602 d.Vector3 pos = d.BodyGetPosition(Body);
496 if (_target_velocity.X > 0) 603 if (_target_velocity.X > 0)
497 { 604 {
@@ -518,6 +625,9 @@ namespace OpenSim.Region.Physics.OdePlugin
518 doForce(vec); 625 doForce(vec);
519 } 626 }
520 627
628 /// <summary>
629 /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence.
630 /// </summary>
521 public void UpdatePositionAndVelocity() 631 public void UpdatePositionAndVelocity()
522 { 632 {
523 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! 633 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
@@ -533,25 +643,21 @@ namespace OpenSim.Region.Physics.OdePlugin
533 _position.Y = vec.Y; 643 _position.Y = vec.Y;
534 _position.Z = vec.Z; 644 _position.Z = vec.Z;
535 645
646 // Did we move last? = zeroflag
647 // This helps keep us from sliding all over
648
536 if (_zeroFlag) 649 if (_zeroFlag)
537 { 650 {
538 _velocity.X = 0.0f; 651 _velocity.X = 0.0f;
539 _velocity.Y = 0.0f; 652 _velocity.Y = 0.0f;
540 _velocity.Z = 0.0f; 653 _velocity.Z = 0.0f;
654
655 // Did we send out the 'stopped' message?
541 if (!m_lastUpdateSent) 656 if (!m_lastUpdateSent)
542 { 657 {
543 m_lastUpdateSent = true; 658 m_lastUpdateSent = true;
544 base.RequestPhysicsterseUpdate(); 659 base.RequestPhysicsterseUpdate();
545 //string primScenAvatarIn = _parent_scene.whichspaceamIin(_position); 660
546 //int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
547 //if (primScenAvatarIn == "0")
548 //{
549 //MainLog.Instance.Verbose("Physics", "Avatar " + m_name + " in space with no prim. Arr:':" + arrayitem[0].ToString() + "," + arrayitem[1].ToString());
550 //}
551 //else
552 //{
553 // MainLog.Instance.Verbose("Physics", "Avatar " + m_name + " in Prim space':" + primScenAvatarIn + ". Arr:" + arrayitem[0].ToString() + "," + arrayitem[1].ToString());
554 //}
555 } 661 }
556 } 662 }
557 else 663 else
@@ -564,6 +670,7 @@ namespace OpenSim.Region.Physics.OdePlugin
564 _velocity.Z = (vec.Z); 670 _velocity.Z = (vec.Z);
565 if (_velocity.Z < -6 && !m_hackSentFall) 671 if (_velocity.Z < -6 && !m_hackSentFall)
566 { 672 {
673 // Collisionupdates will be used in the future, right now the're not being used.
567 m_hackSentFall = true; 674 m_hackSentFall = true;
568 //base.SendCollisionUpdate(new CollisionEventUpdate()); 675 //base.SendCollisionUpdate(new CollisionEventUpdate());
569 m_pidControllerActive = false; 676 m_pidControllerActive = false;
@@ -581,13 +688,21 @@ namespace OpenSim.Region.Physics.OdePlugin
581 } 688 }
582 } 689 }
583 690
691 /// <summary>
692 /// Cleanup the things we use in the scene.
693 /// </summary>
584 public void Destroy() 694 public void Destroy()
585 { 695 {
586 lock (OdeScene.OdeLock) 696 lock (OdeScene.OdeLock)
587 { 697 {
588 // d.JointDestroy(Amotor); 698 // Kill the Amotor
699 d.JointDestroy(Amotor);
700
701 //kill the Geometry
589 d.GeomDestroy(Shell); 702 d.GeomDestroy(Shell);
590 _parent_scene.geom_name_map.Remove(Shell); 703 _parent_scene.geom_name_map.Remove(Shell);
704
705 //kill the body
591 d.BodyDestroy(Body); 706 d.BodyDestroy(Body);
592 } 707 }
593 } 708 }