- Timestamp:
- Feb 14, 2009, 10:17:35 PM (16 years ago)
- Location:
- code/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/trunk
- Property svn:mergeinfo changed
-
code/trunk/src/orxonox/objects/worldentities/WorldEntity.cc
r2171 r2662 22 22 * Author: 23 23 * Fabian 'x3n' Landau 24 * Reto Grieder (physics) 24 25 * Co-authors: 25 26 * ... … … 31 32 32 33 #include <cassert> 34 #include <OgreSceneNode.h> 33 35 #include <OgreSceneManager.h> 34 36 #include "BulletDynamics/Dynamics/btRigidBody.h" 37 38 #include "util/Exception.h" 39 #include "util/Convert.h" 35 40 #include "core/CoreIncludes.h" 36 41 #include "core/XMLPort.h" 37 #include "util/Convert.h"38 #include "util/Exception.h"39 42 40 43 #include "objects/Scene.h" 44 #include "objects/collisionshapes/WorldEntityCollisionShape.h" 41 45 42 46 namespace orxonox … … 49 53 const Vector3 WorldEntity::UP = Vector3::UNIT_Y; 50 54 55 /** 56 @brief 57 Creates a new WorldEntity that may immediately be used. 58 All the default values are being set here. 59 */ 51 60 WorldEntity::WorldEntity(BaseObject* creator) : BaseObject(creator), Synchronisable(creator) 52 61 { … … 64 73 this->node_->setOrientation(Quaternion::IDENTITY); 65 74 75 76 // Default behaviour does not include physics 77 this->physicalBody_ = 0; 78 this->bPhysicsActive_ = false; 79 this->bPhysicsActiveSynchronised_ = false; 80 this->bPhysicsActiveBeforeAttaching_ = false; 81 this->collisionShape_ = new WorldEntityCollisionShape(this); 82 this->collisionType_ = None; 83 this->collisionTypeSynchronised_ = None; 84 this->mass_ = 0; 85 this->childrenMass_ = 0; 86 // Using bullet default values 87 this->restitution_ = 0; 88 this->angularFactor_ = 1; 89 this->linearDamping_ = 0; 90 this->angularDamping_ = 0; 91 this->friction_ = 0.5; 92 this->bCollisionCallbackActive_ = false; 93 this->bCollisionResponseActive_ = true; 94 66 95 this->registerVariables(); 67 96 } 68 97 98 /** 99 @brief 100 Destroys the WorldEntity AND ALL its children with it. 101 */ 69 102 WorldEntity::~WorldEntity() 70 103 { 71 104 if (this->isInitialized()) 72 105 { 106 if (this->parent_) 107 this->detachFromParent(); 108 109 for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ) 110 delete (*(it++)); 111 112 if (this->physicalBody_) 113 { 114 this->deactivatePhysics(); 115 delete this->physicalBody_; 116 } 117 delete this->collisionShape_; 118 73 119 this->node_->detachAllObjects(); 74 if (this->getScene()->getSceneManager()) 75 this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName()); 120 this->node_->removeAllChildren(); 121 122 OrxAssert(this->getScene()->getSceneManager(), "No SceneManager defined in a WorldEntity."); 123 this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName()); 76 124 } 77 125 } … … 81 129 SUPER(WorldEntity, XMLPort, xmlelement, mode); 82 130 83 XMLPortParamTemplate(WorldEntity, "position", setPosition, getPosition,xmlelement, mode, const Vector3&);131 XMLPortParamTemplate(WorldEntity, "position", setPosition, getPosition, xmlelement, mode, const Vector3&); 84 132 XMLPortParamTemplate(WorldEntity, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&); 85 XMLPortParamLoadOnly(WorldEntity, "lookat", lookAt_xmlport, xmlelement, mode); 86 XMLPortParamLoadOnly(WorldEntity, "direction", setDirection_xmlport, xmlelement, mode); 87 XMLPortParamLoadOnly(WorldEntity, "yaw", yaw_xmlport, xmlelement, mode); 88 XMLPortParamLoadOnly(WorldEntity, "pitch", pitch_xmlport, xmlelement, mode); 89 XMLPortParamLoadOnly(WorldEntity, "roll", roll_xmlport, xmlelement, mode); 90 XMLPortParamTemplate(WorldEntity, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&); 91 XMLPortParam(WorldEntity, "scale", setScale, getScale, xmlelement, mode); 92 133 XMLPortParamTemplate(WorldEntity, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&); 134 XMLPortParam (WorldEntity, "scale", setScale, getScale, xmlelement, mode); 135 XMLPortParamLoadOnly(WorldEntity, "lookat", lookAt_xmlport, xmlelement, mode); 136 XMLPortParamLoadOnly(WorldEntity, "direction", setDirection_xmlport, xmlelement, mode); 137 XMLPortParamLoadOnly(WorldEntity, "yaw", yaw_xmlport, xmlelement, mode); 138 XMLPortParamLoadOnly(WorldEntity, "pitch", pitch_xmlport, xmlelement, mode); 139 XMLPortParamLoadOnly(WorldEntity, "roll", roll_xmlport, xmlelement, mode); 140 141 // Physics 142 XMLPortParam(WorldEntity, "collisionType", setCollisionTypeStr, getCollisionTypeStr, xmlelement, mode); 143 XMLPortParam(WorldEntity, "collisionResponse", setCollisionResponse, hasCollisionResponse, xmlelement, mode); 144 XMLPortParam(WorldEntity, "mass", setMass, getMass, xmlelement, mode); 145 XMLPortParam(WorldEntity, "restitution", setRestitution, getRestitution, xmlelement, mode); 146 XMLPortParam(WorldEntity, "angularFactor", setAngularFactor, getAngularFactor, xmlelement, mode); 147 XMLPortParam(WorldEntity, "linearDamping", setLinearDamping, getLinearDamping, xmlelement, mode); 148 XMLPortParam(WorldEntity, "angularDamping", setAngularDamping, getAngularDamping, xmlelement, mode); 149 XMLPortParam(WorldEntity, "friction", setFriction, getFriction, xmlelement, mode); 150 151 // Other attached WorldEntities 93 152 XMLPortObject(WorldEntity, WorldEntity, "attached", attach, getAttachedObject, xmlelement, mode); 153 // Attached collision shapes 154 XMLPortObject(WorldEntity, CollisionShape, "collisionShapes", attachCollisionShape, getAttachedCollisionShape, xmlelement, mode); 94 155 } 95 156 96 157 void WorldEntity::registerVariables() 97 158 { 98 REGISTERDATA(this->bActive_, direction::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity)); 99 REGISTERDATA(this->bVisible_, direction::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility)); 100 101 REGISTERDATA(this->getScale3D().x, direction::toclient); 102 REGISTERDATA(this->getScale3D().y, direction::toclient); 103 REGISTERDATA(this->getScale3D().z, direction::toclient); 104 105 REGISTERDATA(this->parentID_, direction::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::updateParent)); 106 } 107 108 void WorldEntity::updateParent() 159 registerVariable(this->mainStateName_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedMainState)); 160 161 registerVariable(this->bActive_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity)); 162 registerVariable(this->bVisible_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility)); 163 164 registerVariable(this->getScale3D(), variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::scaleChanged)); 165 166 // Physics stuff 167 registerVariable(this->mass_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::massChanged)); 168 registerVariable(this->restitution_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::restitutionChanged)); 169 registerVariable(this->angularFactor_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularFactorChanged)); 170 registerVariable(this->linearDamping_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::linearDampingChanged)); 171 registerVariable(this->angularDamping_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularDampingChanged)); 172 registerVariable(this->friction_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::frictionChanged)); 173 registerVariable(this->bCollisionCallbackActive_, 174 variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionCallbackActivityChanged)); 175 registerVariable(this->bCollisionResponseActive_, 176 variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionResponseActivityChanged)); 177 registerVariable((int&)this->collisionTypeSynchronised_, 178 variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionTypeChanged)); 179 registerVariable(this->bPhysicsActiveSynchronised_, 180 variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::physicsActivityChanged)); 181 182 // Attach to parent if necessary 183 registerVariable(this->parentID_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::parentChanged)); 184 } 185 186 /** 187 @brief 188 Network function that object this instance to its correct parent. 189 */ 190 void WorldEntity::parentChanged() 109 191 { 110 192 if (this->parentID_ != OBJECTID_UNKNOWN) … … 116 198 } 117 199 200 /** 201 @brief 202 Attaches this object to a parent SceneNode. 203 @Remarks 204 Only use this method if you know exactly what you're doing! 205 Normally, attaching works internally by attaching WE's. 206 */ 207 void WorldEntity::attachToNode(Ogre::SceneNode* node) 208 { 209 Ogre::Node* parent = this->node_->getParent(); 210 if (parent) 211 parent->removeChild(this->node_); 212 node->addChild(this->node_); 213 } 214 215 /** 216 @brief 217 Detaches this object from a parent SceneNode. 218 @Remarks 219 Only use this method if you know exactly what you're doing! 220 Normally, attaching works internally by attaching WE's. 221 */ 222 void WorldEntity::detachFromNode(Ogre::SceneNode* node) 223 { 224 node->removeChild(this->node_); 225 // this->getScene()->getRootSceneNode()->addChild(this->node_); 226 } 227 228 /** 229 @brief 230 Network callback for the collision type. Only change the type if it was valid. 231 */ 232 void WorldEntity::collisionTypeChanged() 233 { 234 if (this->collisionTypeSynchronised_ != Dynamic && 235 this->collisionTypeSynchronised_ != Kinematic && 236 this->collisionTypeSynchronised_ != Static && 237 this->collisionTypeSynchronised_ != None) 238 { 239 CCOUT(1) << "Error when collsion Type was received over network. Unknown enum value:" << this->collisionTypeSynchronised_ << std::endl; 240 } 241 else if (this->collisionTypeSynchronised_ != collisionType_) 242 { 243 if (this->parent_) 244 CCOUT(2) << "Warning: Network connection tried to set the collision type of an attached WE. Ignoring." << std::endl; 245 else 246 this->setCollisionType(this->collisionTypeSynchronised_); 247 } 248 } 249 250 //! Network callback for this->bPhysicsActive_ 251 void WorldEntity::physicsActivityChanged() 252 { 253 if (this->bPhysicsActiveSynchronised_) 254 this->activatePhysics(); 255 else 256 this->deactivatePhysics(); 257 } 258 259 //! Function sets whether Bullet should issue a callback on collisions 260 void WorldEntity::collisionCallbackActivityChanged() 261 { 262 if (this->hasPhysics()) 263 { 264 if (this->bCollisionCallbackActive_) 265 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() | 266 btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); 267 else 268 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & 269 ~btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); 270 } 271 } 272 273 //! Function sets whether Bullet should react itself to a collision 274 void WorldEntity::collisionResponseActivityChanged() 275 { 276 if (this->hasPhysics()) 277 { 278 if (this->bCollisionResponseActive_) 279 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & 280 ~btCollisionObject::CF_NO_CONTACT_RESPONSE); 281 else 282 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() | 283 btCollisionObject::CF_NO_CONTACT_RESPONSE); 284 } 285 } 286 287 /** 288 @brief 289 Attaches a child WorldEntity to this object. This calls notifyBeingAttached() 290 of the child WE. 291 @Note 292 The collision shape of the child object gets attached nevertheless. That also means 293 that you can change the collision shape of the child and it correctly cascadeds the changes to this instance. 294 Be aware of this implication: When implementing attaching of kinematic objects to others, you have to change 295 this behaviour because you then might not want to merge the collision shapes. 296 */ 118 297 void WorldEntity::attach(WorldEntity* object) 119 298 { 120 if (object ->getParent())121 object->detachFromParent();122 else123 {124 Ogre::Node* parent = object->node_->getParent();125 if (parent) 126 parent->removeChild(object->node_);127 }128 129 this-> node_->addChild(object->node_);299 if (object == this) 300 { 301 COUT(2) << "Warning: Can't attach a WorldEntity to itself." << std::endl; 302 return; 303 } 304 305 if (!object->notifyBeingAttached(this)) 306 return; 307 308 this->attachNode(object->node_); 130 309 this->children_.insert(object); 131 object->parent_ = this; 132 object->parentID_ = this->getObjectID(); 133 } 134 310 311 this->attachCollisionShape(object->collisionShape_); 312 // mass 313 this->childrenMass_ += object->getMass(); 314 recalculateMassProps(); 315 } 316 317 /** 318 @brief 319 Function gets called when this object is being attached to a new parent. 320 321 This operation is only allowed if the collision types "like" each other. 322 - You cannot a attach a non physical object to a physical one. 323 - Dynamic object can NOT be attached at all. 324 - It is also not possible to attach a kinematic to a dynamic one. 325 - Attaching of kinematic objects otherwise is not yet supported. 326 */ 327 bool WorldEntity::notifyBeingAttached(WorldEntity* newParent) 328 { 329 // check first whether attaching is even allowed 330 if (this->hasPhysics()) 331 { 332 if (!newParent->hasPhysics()) 333 { 334 COUT(2) << "Warning: Cannot attach a physical object to a non physical one." << std::endl; 335 return false; 336 } 337 else if (this->isDynamic()) 338 { 339 COUT(2) << "Warning: Cannot attach a dynamic object to a WorldEntity." << std::endl; 340 return false; 341 } 342 else if (this->isKinematic() && newParent->isDynamic()) 343 { 344 COUT(2) << "Warning: Cannot attach a kinematic object to a dynamic one." << std::endl; 345 return false; 346 } 347 else if (this->isKinematic()) 348 { 349 COUT(2) << "Warning: Cannot attach a kinematic object to a static or kinematic one: Not yet implemented." << std::endl; 350 return false; 351 } 352 } 353 354 if (this->isPhysicsActive()) 355 this->bPhysicsActiveBeforeAttaching_ = true; 356 this->deactivatePhysics(); 357 358 if (this->parent_) 359 this->detachFromParent(); 360 361 this->parent_ = newParent; 362 this->parentID_ = newParent->getObjectID(); 363 364 // apply transform to collision shape 365 this->collisionShape_->setPosition(this->getPosition()); 366 this->collisionShape_->setOrientation(this->getOrientation()); 367 // TODO: Scale 368 369 return true; 370 } 371 372 /** 373 @brief 374 Detaches a child WorldEntity from this instance. 375 */ 135 376 void WorldEntity::detach(WorldEntity* object) 136 377 { 137 this->node_->removeChild(object->node_); 378 if (this->children_.find(object) == this->children_.end()) 379 { 380 CCOUT(2) << "Warning: Cannot detach an object that is not a child." << std::endl; 381 return; 382 } 383 384 // collision shapes 385 this->detachCollisionShape(object->collisionShape_); 386 387 // mass 388 if (object->getMass() > 0.0f) 389 { 390 this->childrenMass_ -= object->getMass(); 391 recalculateMassProps(); 392 } 393 394 this->detachNode(object->node_); 138 395 this->children_.erase(object); 139 object->parent_ = 0; 140 object->parentID_ = OBJECTID_UNKNOWN; 141 142 // this->getScene()->getRootSceneNode()->addChild(object->node_); 143 } 144 145 WorldEntity* WorldEntity::getAttachedObject(unsigned int index) const 396 397 object->notifyDetached(); 398 } 399 400 /** 401 @brief 402 Function gets called when the object has been detached from its parent. 403 */ 404 void WorldEntity::notifyDetached() 405 { 406 this->parent_ = 0; 407 this->parentID_ = OBJECTID_UNKNOWN; 408 409 // reset orientation of the collisionShape (cannot be set within a WE usually) 410 this->collisionShape_->setPosition(Vector3::ZERO); 411 this->collisionShape_->setOrientation(Quaternion::IDENTITY); 412 // TODO: Scale 413 414 if (this->bPhysicsActiveBeforeAttaching_) 415 { 416 this->activatePhysics(); 417 this->bPhysicsActiveBeforeAttaching_ = false; 418 } 419 } 420 421 //! Returns an attached object (merely for XMLPort). 422 WorldEntity* WorldEntity::getAttachedObject(unsigned int index) 146 423 { 147 424 unsigned int i = 0; … … 154 431 return 0; 155 432 } 433 434 //! Attaches an Ogre::SceneNode to this WorldEntity. 435 void WorldEntity::attachNode(Ogre::SceneNode* node) 436 { 437 Ogre::Node* parent = node->getParent(); 438 if (parent) 439 parent->removeChild(node); 440 this->node_->addChild(node); 441 } 442 443 //! Detaches an Ogre::SceneNode from this WorldEntity. 444 void WorldEntity::detachNode(Ogre::SceneNode* node) 445 { 446 this->node_->removeChild(node); 447 // this->getScene()->getRootSceneNode()->addChild(node); 448 } 449 450 //! Attaches an Ogre::MovableObject to this WorldEntity. 451 void WorldEntity::attachOgreObject(Ogre::MovableObject* object) 452 { 453 this->node_->attachObject(object); 454 } 455 456 //! Detaches an Ogre::MovableObject from this WorldEntity. 457 void WorldEntity::detachOgreObject(Ogre::MovableObject* object) 458 { 459 this->node_->detachObject(object); 460 } 461 462 //! Detaches an Ogre::MovableObject (by string) from this WorldEntity. 463 Ogre::MovableObject* WorldEntity::detachOgreObject(const Ogre::String& name) 464 { 465 return this->node_->detachObject(name); 466 } 467 468 //! Attaches a collision Shape to this object (delegated to the internal CompoundCollisionShape) 469 void WorldEntity::attachCollisionShape(CollisionShape* shape) 470 { 471 this->collisionShape_->attach(shape); 472 // Note: this->collisionShape_ already notifies us of any changes. 473 } 474 475 //! Detaches a collision Shape from this object (delegated to the internal CompoundCollisionShape) 476 void WorldEntity::detachCollisionShape(CollisionShape* shape) 477 { 478 // Note: The collision shapes may not be detached with this function! 479 this->collisionShape_->detach(shape); 480 // Note: this->collisionShape_ already notifies us of any changes. 481 } 482 483 //! Returns an attached collision Shape of this object (delegated to the internal CompoundCollisionShape) 484 CollisionShape* WorldEntity::getAttachedCollisionShape(unsigned int index) 485 { 486 return this->collisionShape_->getAttachedShape(index); 487 } 488 489 // Note: These functions are placed in WorldEntity.h as inline functions for the release build. 490 #ifndef _NDEBUG 491 const Vector3& WorldEntity::getPosition() const 492 { 493 return this->node_->getPosition(); 494 } 495 496 const Quaternion& WorldEntity::getOrientation() const 497 { 498 return this->node_->getOrientation(); 499 } 500 501 const Vector3& WorldEntity::getScale3D() const 502 { 503 return this->node_->getScale(); 504 } 505 #endif 506 507 //! Returns the position relative to the root space 508 const Vector3& WorldEntity::getWorldPosition() const 509 { 510 return this->node_->_getDerivedPosition(); 511 } 512 513 //! Returns the orientation relative to the root space 514 const Quaternion& WorldEntity::getWorldOrientation() const 515 { 516 return this->node_->_getDerivedOrientation(); 517 } 518 519 //! Returns the scaling applied relative to the root space in 3 coordinates 520 const Vector3& WorldEntity::getWorldScale3D() const 521 { 522 return this->node_->_getDerivedScale(); 523 } 524 525 /** 526 @brief 527 Returns the scaling applied relative to the root space in 3 coordinates 528 @return 529 Returns the scaling if it is uniform, 1.0f otherwise. 530 */ 531 float WorldEntity::getWorldScale() const 532 { 533 Vector3 scale = this->getWorldScale3D(); 534 return (scale.x == scale.y && scale.x == scale.z) ? scale.x : 1; 535 } 536 537 /** 538 @brief 539 Sets the three dimensional scaling of this object. 540 @Note 541 Scaling physical objects has not yet been implemented and is therefore forbidden. 542 */ 543 void WorldEntity::setScale3D(const Vector3& scale) 544 { 545 /* 546 HACK HACK HACK 547 if (bScalePhysics && this->hasPhysics() && scale != Vector3::UNIT_SCALE) 548 { 549 CCOUT(2) << "Warning: Cannot set the scale of a physical object: Not yet implemented. Ignoring scaling." << std::endl; 550 return; 551 } 552 HACK HACK HACK 553 */ 554 this->node_->setScale(scale); 555 556 this->changedScale(); 557 } 558 559 /** 560 @brief 561 Translates this WorldEntity by a vector. 562 @param relativeTo 563 @see TransformSpace::Enum 564 */ 565 void WorldEntity::translate(const Vector3& distance, TransformSpace::Enum relativeTo) 566 { 567 switch (relativeTo) 568 { 569 case TransformSpace::Local: 570 // position is relative to parent so transform downwards 571 this->setPosition(this->getPosition() + this->getOrientation() * distance); 572 break; 573 case TransformSpace::Parent: 574 this->setPosition(this->getPosition() + distance); 575 break; 576 case TransformSpace::World: 577 // position is relative to parent so transform upwards 578 if (this->node_->getParent()) 579 setPosition(getPosition() + (node_->getParent()->_getDerivedOrientation().Inverse() * distance) 580 / node_->getParent()->_getDerivedScale()); 581 else 582 this->setPosition(this->getPosition() + distance); 583 break; 584 } 585 } 586 587 /** 588 @brief 589 Rotates this WorldEntity by a quaternion. 590 @param relativeTo 591 @see TransformSpace::Enum 592 */ 593 void WorldEntity::rotate(const Quaternion& rotation, TransformSpace::Enum relativeTo) 594 { 595 switch(relativeTo) 596 { 597 case TransformSpace::Local: 598 this->setOrientation(this->getOrientation() * rotation); 599 break; 600 case TransformSpace::Parent: 601 // Rotations are normally relative to local axes, transform up 602 this->setOrientation(rotation * this->getOrientation()); 603 break; 604 case TransformSpace::World: 605 // Rotations are normally relative to local axes, transform up 606 this->setOrientation(this->getOrientation() * this->getWorldOrientation().Inverse() 607 * rotation * this->getWorldOrientation()); 608 break; 609 } 610 } 611 612 /** 613 @brief 614 Makes this WorldEntity look a specific target location. 615 @param relativeTo 616 @see TransformSpace::Enum 617 @param localDirectionVector 618 The vector which normally describes the natural direction of the object, usually -Z. 619 */ 620 void WorldEntity::lookAt(const Vector3& target, TransformSpace::Enum relativeTo, const Vector3& localDirectionVector) 621 { 622 Vector3 origin; 623 switch (relativeTo) 624 { 625 case TransformSpace::Local: 626 origin = Vector3::ZERO; 627 break; 628 case TransformSpace::Parent: 629 origin = this->getPosition(); 630 break; 631 case TransformSpace::World: 632 origin = this->getWorldPosition(); 633 break; 634 } 635 this->setDirection(target - origin, relativeTo, localDirectionVector); 636 } 637 638 /** 639 @brief 640 Makes this WorldEntity look in specific direction. 641 @param relativeTo 642 @see TransformSpace::Enum 643 @param localDirectionVector 644 The vector which normally describes the natural direction of the object, usually -Z. 645 */ 646 void WorldEntity::setDirection(const Vector3& direction, TransformSpace::Enum relativeTo, const Vector3& localDirectionVector) 647 { 648 Quaternion savedOrientation(this->getOrientation()); 649 Ogre::Node::TransformSpace ogreRelativeTo; 650 switch (relativeTo) 651 { 652 case TransformSpace::Local: 653 ogreRelativeTo = Ogre::Node::TS_LOCAL; break; 654 case TransformSpace::Parent: 655 ogreRelativeTo = Ogre::Node::TS_PARENT; break; 656 case TransformSpace::World: 657 ogreRelativeTo = Ogre::Node::TS_WORLD; break; 658 } 659 this->node_->setDirection(direction, ogreRelativeTo, localDirectionVector); 660 Quaternion newOrientation(this->node_->getOrientation()); 661 this->node_->setOrientation(savedOrientation); 662 this->setOrientation(newOrientation); 663 } 664 665 //! Activates physics if the CollisionType is not None. 666 void WorldEntity::activatePhysics() 667 { 668 if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_) 669 { 670 this->getScene()->addPhysicalObject(this); 671 this->bPhysicsActive_ = true; 672 this->bPhysicsActiveSynchronised_ = true; 673 } 674 } 675 676 //! Deactivates physics but the CollisionType does not change. 677 void WorldEntity::deactivatePhysics() 678 { 679 if (this->isPhysicsActive()) 680 { 681 this->getScene()->removePhysicalObject(this); 682 this->bPhysicsActive_ = false; 683 this->bPhysicsActiveSynchronised_ = false; 684 } 685 } 686 687 //! Tells whether the object has already been added to the Bullet physics World. 688 bool WorldEntity::addedToPhysicalWorld() const 689 { 690 return this->physicalBody_ && this->physicalBody_->isInWorld(); 691 } 692 693 /** 694 @brief 695 Sets the CollisionType. This alters the object significantly! @see CollisionType. 696 @Note 697 Operation does not work on attached WorldEntities. 698 */ 699 void WorldEntity::setCollisionType(CollisionType type) 700 { 701 if (this->collisionType_ == type) 702 return; 703 704 // If we are already attached to a parent, this would be a bad idea.. 705 if (this->parent_) 706 { 707 CCOUT(2) << "Warning: Cannot set the collision type of a WorldEntity with a parent." << std::endl; 708 return; 709 } 710 711 // Check for type legality. Could be StaticEntity or MobileEntity. 712 if (!this->isCollisionTypeLegal(type)) 713 return; 714 715 if (this->isPhysicsActive()) 716 this->deactivatePhysics(); 717 718 bool bReactivatePhysics = true; 719 if (this->hasPhysics() && !this->isPhysicsActive()) 720 bReactivatePhysics = false; 721 722 // Check whether we have to create or destroy. 723 if (type != None && this->collisionType_ == None) 724 { 725 /* 726 HACK HACK HACK 727 // Check whether there was some scaling applied. 728 if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001)) 729 { 730 CCOUT(2) << "Warning: Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << std::endl; 731 return; 732 } 733 HACK HACK HACK 734 */ 735 // Create new rigid body 736 btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape()); 737 this->physicalBody_ = new btRigidBody(bodyConstructionInfo); 738 this->physicalBody_->setUserPointer(this); 739 this->physicalBody_->setActivationState(DISABLE_DEACTIVATION); 740 } 741 else if (type == None && this->collisionType_ != None) 742 { 743 // Destroy rigid body 744 assert(this->physicalBody_); 745 deactivatePhysics(); 746 delete this->physicalBody_; 747 this->physicalBody_ = 0; 748 this->collisionType_ = None; 749 this->collisionTypeSynchronised_ = None; 750 return; 751 } 752 753 // Change type 754 switch (type) 755 { 756 case Dynamic: 757 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT)); 758 break; 759 case Kinematic: 760 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT); 761 break; 762 case Static: 763 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT); 764 break; 765 case None: 766 assert(false); // Doesn't happen 767 return; 768 } 769 this->collisionType_ = type; 770 this->collisionTypeSynchronised_ = type; 771 772 // update mass and inertia tensor 773 recalculateMassProps(); 774 internalSetPhysicsProps(); 775 collisionCallbackActivityChanged(); 776 collisionResponseActivityChanged(); 777 if (bReactivatePhysics) 778 activatePhysics(); 779 } 780 781 //! Sets the CollisionType by string (used for the XMLPort) 782 void WorldEntity::setCollisionTypeStr(const std::string& typeStr) 783 { 784 std::string typeStrLower = getLowercase(typeStr); 785 CollisionType type; 786 if (typeStrLower == "dynamic") 787 type = Dynamic; 788 else if (typeStrLower == "static") 789 type = Static; 790 else if (typeStrLower == "kinematic") 791 type = Kinematic; 792 else if (typeStrLower == "none") 793 type = None; 794 else 795 ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'."); 796 this->setCollisionType(type); 797 } 798 799 //! Gets the CollisionType by string (used for the XMLPort) 800 std::string WorldEntity::getCollisionTypeStr() const 801 { 802 switch (this->getCollisionType()) 803 { 804 case Dynamic: 805 return "dynamic"; 806 case Kinematic: 807 return "kinematic"; 808 case Static: 809 return "static"; 810 case None: 811 return "none"; 812 default: 813 assert(false); 814 return ""; 815 } 816 } 817 818 /** 819 @brief 820 Recalculates the accumulated child mass and calls recalculateMassProps() 821 and notifies the parent of the change. 822 @Note 823 Called by a child WE 824 */ 825 void WorldEntity::notifyChildMassChanged() 826 { 827 // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already 828 // Recalculate mass 829 this->childrenMass_ = 0.0f; 830 for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it) 831 this->childrenMass_ += (*it)->getMass(); 832 recalculateMassProps(); 833 // Notify parent WE 834 if (this->parent_) 835 parent_->notifyChildMassChanged(); 836 } 837 838 /** 839 @brief 840 Undertakes the necessary steps to change the collision shape in Bullet, even at runtime. 841 @Note 842 - called by this->collisionShape_ 843 - May have a REALLY big overhead when called continuously at runtime, because then we need 844 to remove the physical body from Bullet and add it again. 845 */ 846 void WorldEntity::notifyCollisionShapeChanged() 847 { 848 if (hasPhysics()) 849 { 850 // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again 851 if (this->addedToPhysicalWorld()) 852 { 853 this->deactivatePhysics(); 854 this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape()); 855 this->activatePhysics(); 856 } 857 else 858 this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape()); 859 } 860 recalculateMassProps(); 861 } 862 863 //! Updates all mass dependent parameters (mass, inertia tensor and child mass) 864 void WorldEntity::recalculateMassProps() 865 { 866 // Store local inertia for faster access. Evaluates to (0,0,0) if there is no collision shape. 867 float totalMass = this->mass_ + this->childrenMass_; 868 this->collisionShape_->calculateLocalInertia(totalMass, this->localInertia_); 869 if (this->hasPhysics()) 870 { 871 if (this->isStatic()) 872 { 873 // Just set everything to zero 874 this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0)); 875 } 876 else if ((this->mass_ + this->childrenMass_) == 0.0f) 877 { 878 // Use default values to avoid very large or very small values 879 CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0" << std::endl; 880 btVector3 inertia(0, 0, 0); 881 this->collisionShape_->calculateLocalInertia(1.0f, inertia); 882 this->physicalBody_->setMassProps(1.0f, inertia); 883 } 884 else 885 { 886 this->physicalBody_->setMassProps(totalMass, this->localInertia_); 887 } 888 } 889 } 890 891 //! Copies our own parameters for restitution, angular factor, dampings and friction to the bullet rigid body. 892 void WorldEntity::internalSetPhysicsProps() 893 { 894 if (this->hasPhysics()) 895 { 896 this->physicalBody_->setRestitution(this->restitution_); 897 this->physicalBody_->setAngularFactor(this->angularFactor_); 898 this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_); 899 this->physicalBody_->setFriction(this->friction_); 900 } 901 } 156 902 }
Note: See TracChangeset
for help on using the changeset viewer.