Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/orxonox/objects/worldentities/WorldEntity.cc @ 2527

Last change on this file since 2527 was 2527, checked in by rgrieder, 15 years ago
  • Forgot to account for collision shape position and orientation when attaching WEs
  • addChildShape —> attach in CompoundCollisionShape
  • Fixed an issue which allowed WE's to detach themselves from non-parents.
  • Fixed an issue that occurred when physics was not active before attaching
  • Added some forgotten const in WE (physics)
  • When attaching WE's the child doesn't get modified anymore. Alternative: notifyDetached() and notifyBeingAttached(this) —> the child does the work
  • Property svn:eol-style set to native
File size: 27.8 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *      Reto Grieder (physics)
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30#include "OrxonoxStableHeaders.h"
31#include "WorldEntity.h"
32
33#include <cassert>
34#include <OgreSceneNode.h>
35#include <OgreSceneManager.h>
36#include "BulletDynamics/Dynamics/btRigidBody.h"
37
38#include "util/Exception.h"
39#include "util/Convert.h"
40#include "core/CoreIncludes.h"
41#include "core/XMLPort.h"
42
43#include "objects/Scene.h"
44#include "objects/collisionshapes/CompoundCollisionShape.h"
45
46namespace orxonox
47{
48    const Vector3 WorldEntity::FRONT = Vector3::NEGATIVE_UNIT_Z;
49    const Vector3 WorldEntity::BACK  = Vector3::UNIT_Z;
50    const Vector3 WorldEntity::LEFT  = Vector3::NEGATIVE_UNIT_X;
51    const Vector3 WorldEntity::RIGHT = Vector3::UNIT_X;
52    const Vector3 WorldEntity::DOWN  = Vector3::NEGATIVE_UNIT_Y;
53    const Vector3 WorldEntity::UP    = Vector3::UNIT_Y;
54
55    WorldEntity::WorldEntity(BaseObject* creator) : BaseObject(creator), Synchronisable(creator)
56    {
57        RegisterObject(WorldEntity);
58
59        if (!this->getScene() || !this->getScene()->getRootSceneNode())
60            ThrowException(AbortLoading, "Can't create WorldEntity, no scene or no root-scenenode given.");
61
62        this->node_ = this->getScene()->getRootSceneNode()->createChildSceneNode();
63
64        this->parent_ = 0;
65        this->parentID_ = OBJECTID_UNKNOWN;
66
67        this->node_->setPosition(Vector3::ZERO);
68        this->node_->setOrientation(Quaternion::IDENTITY);
69
70        // Default behaviour does not include physics
71        this->physicalBody_ = 0;
72        this->bPhysicsActive_ = false;
73        this->bPhysicsActiveSynchronised_ = false;
74        this->bPhysicsActiveBeforeAttaching_ = false;
75        this->collisionShape_ = new CompoundCollisionShape(this);
76        // Note: CompoundCollisionShape is a Synchronisable, but must not be synchronised.
77        //       All objects will get attached on the client anyway, so we don't need synchronisation.
78        this->collisionShape_->setWorldEntityParent(this);
79        this->collisionType_ = None;
80        this->collisionTypeSynchronised_ = None;
81        this->mass_           = 0;
82        this->childrenMass_   = 0;
83        // Use bullet default values
84        this->restitution_    = 0;
85        this->angularFactor_  = 1;
86        this->linearDamping_  = 0;
87        this->angularDamping_ = 0;
88        this->friction_       = 0.5;
89        this->bCollisionCallbackActive_ = false;
90
91        this->registerVariables();
92    }
93
94    WorldEntity::~WorldEntity()
95    {
96        if (this->isInitialized())
97        {
98            this->node_->detachAllObjects();
99
100            for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); )
101                delete (*(it++));
102
103            if (this->parent_)
104                this->detachFromParent();
105
106            this->node_->removeAllChildren();
107
108            if (this->physicalBody_)
109            {
110                this->deactivatePhysics();
111                delete this->physicalBody_;
112            }
113            delete this->collisionShape_;
114
115            if (this->getScene()->getSceneManager())
116                this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
117        }
118    }
119
120    void WorldEntity::XMLPort(Element& xmlelement, XMLPort::Mode mode)
121    {
122        SUPER(WorldEntity, XMLPort, xmlelement, mode);
123
124        XMLPortParamTemplate(WorldEntity, "position",    setPosition,    getPosition,    xmlelement, mode, const Vector3&);
125        XMLPortParamTemplate(WorldEntity, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&);
126        XMLPortParamTemplate(WorldEntity, "scale3D",     setScale3D,     getScale3D,     xmlelement, mode, const Vector3&);
127        XMLPortParam        (WorldEntity, "scale",       setScale,       getScale,       xmlelement, mode);
128        XMLPortParamLoadOnly(WorldEntity, "lookat",      lookAt_xmlport,       xmlelement, mode);
129        XMLPortParamLoadOnly(WorldEntity, "direction",   setDirection_xmlport, xmlelement, mode);
130        XMLPortParamLoadOnly(WorldEntity, "yaw",         yaw_xmlport,          xmlelement, mode);
131        XMLPortParamLoadOnly(WorldEntity, "pitch",       pitch_xmlport,        xmlelement, mode);
132        XMLPortParamLoadOnly(WorldEntity, "roll",        roll_xmlport,         xmlelement, mode);
133
134        // Physics
135        XMLPortParam(WorldEntity, "collisionType",  setCollisionTypeStr, getCollisionTypeStr, xmlelement, mode);
136        XMLPortParam(WorldEntity, "mass",           setMass,             getMass,             xmlelement, mode);
137        XMLPortParam(WorldEntity, "restitution",    setRestitution,      getRestitution,      xmlelement, mode);
138        XMLPortParam(WorldEntity, "angularFactor",  setAngularFactor,    getAngularFactor,    xmlelement, mode);
139        XMLPortParam(WorldEntity, "linearDamping",  setLinearDamping,    getLinearDamping,    xmlelement, mode);
140        XMLPortParam(WorldEntity, "angularDamping", setAngularDamping,   getAngularDamping,   xmlelement, mode);
141        XMLPortParam(WorldEntity, "friction",       setFriction,         getFriction,         xmlelement, mode);
142
143        // Other attached WorldEntities
144        XMLPortObject(WorldEntity, WorldEntity, "attached", attach, getAttachedObject, xmlelement, mode);
145        // Attached collision shapes
146        XMLPortObject(WorldEntity, CollisionShape, "collisionShapes", attachCollisionShape, getAttachedCollisionShape, xmlelement, mode);
147    }
148
149    void WorldEntity::registerVariables()
150    {
151        registerVariable(this->mainStateName_,  variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedMainState));
152
153        registerVariable(this->bActive_,        variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity));
154        registerVariable(this->bVisible_,       variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility));
155
156        registerVariable(this->getScale3D(),    variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::scaleChanged));
157
158        // Physics stuff
159        registerVariable(this->mass_,           variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::massChanged));
160        registerVariable(this->restitution_,    variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::restitutionChanged));
161        registerVariable(this->angularFactor_,  variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularFactorChanged));
162        registerVariable(this->linearDamping_,  variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::linearDampingChanged));
163        registerVariable(this->angularDamping_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularDampingChanged));
164        registerVariable(this->friction_,       variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::frictionChanged));
165        registerVariable(this->bCollisionCallbackActive_,
166                                                variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionCallbackActivityChanged));
167        registerVariable((int&)this->collisionTypeSynchronised_,
168                                                variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionTypeChanged));
169        registerVariable(this->bPhysicsActiveSynchronised_,
170                                                variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::physicsActivityChanged));
171
172        // Attach to parent if necessary
173        registerVariable(this->parentID_,       variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::parentChanged));
174    }
175
176    void WorldEntity::parentChanged()
177    {
178        if (this->parentID_ != OBJECTID_UNKNOWN)
179        {
180            WorldEntity* parent = dynamic_cast<WorldEntity*>(Synchronisable::getSynchronisable(this->parentID_));
181            if (parent)
182                this->attachToParent(parent);
183        }
184    }
185
186    void WorldEntity::collisionTypeChanged()
187    {
188        if (this->collisionTypeSynchronised_ != Dynamic &&
189            this->collisionTypeSynchronised_ != Kinematic &&
190            this->collisionTypeSynchronised_ != Static &&
191            this->collisionTypeSynchronised_ != None)
192        {
193            CCOUT(1) << "Error when collsion Type was received over network. Unknown enum value:" << this->collisionTypeSynchronised_ << std::endl;
194        }
195        else if (this->collisionTypeSynchronised_ != collisionType_)
196        {
197            if (this->parent_)
198                CCOUT(2) << "Warning: Network connection tried to set the collision type of an attached WE. Ignoring." << std::endl;
199            else
200                this->setCollisionType(this->collisionTypeSynchronised_);
201        }
202    }
203
204    void WorldEntity::physicsActivityChanged()
205    {
206        if (this->bPhysicsActiveSynchronised_)
207            this->activatePhysics();
208        else
209            this->deactivatePhysics();
210    }
211
212    void WorldEntity::collisionCallbackActivityChanged()
213    {
214        if (this->hasPhysics())
215        {
216            if (bCollisionCallbackActive_)
217                this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() |
218                    btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
219            else
220                this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() &
221                    ~btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
222        }
223    }
224
225    void WorldEntity::attachNode(Ogre::SceneNode* node)
226    {
227        Ogre::Node* parent = node->getParent();
228        if (parent)
229            parent->removeChild(node);
230        this->node_->addChild(node);
231    }
232
233    void WorldEntity::detachNode(Ogre::SceneNode* node)
234    {
235        this->node_->removeChild(node);
236//        this->getScene()->getRootSceneNode()->addChild(node);
237    }
238
239    void WorldEntity::attachToNode(Ogre::SceneNode* node)
240    {
241        Ogre::Node* parent = this->node_->getParent();
242        if (parent)
243            parent->removeChild(this->node_);
244        node->addChild(this->node_);
245    }
246
247    void WorldEntity::detachFromNode(Ogre::SceneNode* node)
248    {
249        node->removeChild(this->node_);
250//        this->getScene()->getRootSceneNode()->addChild(this->node_);
251    }
252
253    void WorldEntity::attach(WorldEntity* object)
254    {
255        if (object == this)
256        {
257            COUT(2) << "Warning: Can't attach a WorldEntity to itself." << std::endl;
258            return;
259        }
260
261        if (!object->notifyBeingAttached(this))
262            return;
263
264        this->attachNode(object->node_);
265        this->children_.insert(object);
266
267        this->attachCollisionShape(object->getCollisionShape());
268        // mass
269        this->childrenMass_ += object->getMass();
270        recalculateMassProps();
271    }
272
273    bool WorldEntity::notifyBeingAttached(WorldEntity* newParent)
274    {
275        // check first whether attaching is even allowed
276        if (this->hasPhysics())
277        {
278            if (!newParent->hasPhysics())
279            {
280                COUT(2) << "Warning: Cannot attach a physical object to a non physical one." << std::endl;
281                return false;
282            }
283            else if (this->isDynamic())
284            {
285                COUT(2) << "Warning: Cannot attach a dynamic object to a WorldEntity." << std::endl;
286                return false;
287            }
288            else if (this->isKinematic() && newParent->isDynamic())
289            {
290                COUT(2) << "Warning: Cannot attach a kinematic object to a dynamic one." << std::endl;
291                return false;
292            }
293            else if (this->isKinematic())
294            {
295                COUT(2) << "Warning: Cannot attach a kinematic object to a static or kinematic one: Not yet implemented." << std::endl;
296                return false;
297            }
298        }
299
300        if (this->isPhysicsActive())
301            this->bPhysicsActiveBeforeAttaching_ = true;
302        this->deactivatePhysics();
303
304        if (this->parent_)
305            this->detachFromParent();
306
307        this->parent_ = newParent;
308        this->parentID_ = newParent->getObjectID();
309
310        // apply transform to collision shape
311        this->collisionShape_->setPosition(this->getPosition());
312        this->collisionShape_->setOrientation(this->getOrientation());
313        // TODO: Scale
314       
315        return true;
316    }
317
318    void WorldEntity::detach(WorldEntity* object)
319    {
320        if (this->children_.find(object) == this->children_.end())
321        {
322            CCOUT(2) << "Warning: Cannot detach an object that is not a child." << std::endl;
323            return;
324        }
325
326        // collision shapes
327        this->detachCollisionShape(object->getCollisionShape());
328
329        // mass
330        if (object->getMass() > 0.0f)
331        {
332            this->childrenMass_ -= object->getMass();
333            recalculateMassProps();
334        }
335
336        this->detachNode(object->node_);
337        this->children_.erase(object);
338
339        object->notifyDetached();
340    }
341
342    void WorldEntity::notifyDetached()
343    {
344        this->parent_ = 0;
345        this->parentID_ = OBJECTID_UNKNOWN;
346
347        // reset orientation of the collisionShape (cannot be set within a WE usually)
348        this->collisionShape_->setPosition(Vector3::ZERO);
349        this->collisionShape_->setOrientation(Quaternion::IDENTITY);
350        // TODO: Scale
351
352        if (this->bPhysicsActiveBeforeAttaching_)
353        {
354            this->activatePhysics();
355            this->bPhysicsActiveBeforeAttaching_ = false;
356        }
357    }
358
359    WorldEntity* WorldEntity::getAttachedObject(unsigned int index) const
360    {
361        unsigned int i = 0;
362        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
363        {
364            if (i == index)
365                return (*it);
366            ++i;
367        }
368        return 0;
369    }
370
371    void WorldEntity::attachOgreObject(Ogre::MovableObject* object)
372    {
373        this->node_->attachObject(object);
374    }
375
376    void WorldEntity::detachOgreObject(Ogre::MovableObject* object)
377    {
378        this->node_->detachObject(object);
379    }
380
381    Ogre::MovableObject* WorldEntity::detachOgreObject(const Ogre::String& name)
382    {
383        return this->node_->detachObject(name);
384    }
385
386    void WorldEntity::attachCollisionShape(CollisionShape* shape)
387    {
388        this->collisionShape_->attach(shape);
389        // Note: this->collisionShape_ already notifies us of any changes.
390    }
391
392    void WorldEntity::detachCollisionShape(CollisionShape* shape)
393    {
394        this->collisionShape_->detach(shape);
395        // Note: this->collisionShape_ already notifies us of any changes.
396    }
397
398    CollisionShape* WorldEntity::getAttachedCollisionShape(unsigned int index) const
399    {
400        return this->collisionShape_->getAttachedShape(index);
401    }
402
403    void WorldEntity::activatePhysics()
404    {
405        if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_)
406        {
407            this->getScene()->addPhysicalObject(this);
408            this->bPhysicsActive_ = true;
409        }
410    }
411
412    void WorldEntity::deactivatePhysics()
413    {
414        if (this->isPhysicsActive())
415        {
416            this->getScene()->removePhysicalObject(this);
417            this->bPhysicsActive_ = false;
418        }
419    }
420
421    bool WorldEntity::addedToPhysicalWorld() const
422    {
423        return this->physicalBody_ && this->physicalBody_->isInWorld();
424    }
425
426#ifndef _NDEBUG
427    const Vector3& WorldEntity::getPosition() const
428    {
429        return this->node_->getPosition();
430    }
431
432    const Quaternion& WorldEntity::getOrientation() const
433    {
434        return this->node_->getOrientation();
435    }
436
437    const Vector3& WorldEntity::getScale3D() const
438    {
439        return this->node_->getScale();
440    }
441#endif
442
443    const Vector3& WorldEntity::getWorldPosition() const
444    {
445        return this->node_->_getDerivedPosition();
446    }
447
448    const Quaternion& WorldEntity::getWorldOrientation() const
449    {
450        return this->node_->_getDerivedOrientation();
451    }
452
453    void WorldEntity::translate(const Vector3& distance, TransformSpace::Space relativeTo)
454    {
455        switch (relativeTo)
456        {
457        case TransformSpace::Local:
458            // position is relative to parent so transform downwards
459            this->setPosition(this->getPosition() + this->getOrientation() * distance);
460            break;
461        case TransformSpace::Parent:
462            this->setPosition(this->getPosition() + distance);
463            break;
464        case TransformSpace::World:
465            // position is relative to parent so transform upwards
466            if (this->node_->getParent())
467                setPosition(getPosition() + (node_->getParent()->_getDerivedOrientation().Inverse() * distance)
468                    / node_->getParent()->_getDerivedScale());
469            else
470                this->setPosition(this->getPosition() + distance);
471            break;
472        }
473    }
474
475    void WorldEntity::rotate(const Quaternion& rotation, TransformSpace::Space relativeTo)
476    {
477        switch(relativeTo)
478        {
479        case TransformSpace::Local:
480            this->setOrientation(this->getOrientation() * rotation);
481            break;
482        case TransformSpace::Parent:
483            // Rotations are normally relative to local axes, transform up
484            this->setOrientation(rotation * this->getOrientation());
485            break;
486        case TransformSpace::World:
487            // Rotations are normally relative to local axes, transform up
488            this->setOrientation(this->getOrientation() * this->getWorldOrientation().Inverse()
489                * rotation * this->getWorldOrientation());
490            break;
491        }
492    }
493
494    void WorldEntity::lookAt(const Vector3& target, TransformSpace::Space relativeTo, const Vector3& localDirectionVector)
495    {
496        Vector3 origin;
497        switch (relativeTo)
498        {
499        case TransformSpace::Local:
500            origin = Vector3::ZERO;
501            break;
502        case TransformSpace::Parent:
503            origin = this->getPosition();
504            break;
505        case TransformSpace::World:
506            origin = this->getWorldPosition();
507            break;
508        }
509        this->setDirection(target - origin, relativeTo, localDirectionVector);
510    }
511
512    void WorldEntity::setDirection(const Vector3& direction, TransformSpace::Space relativeTo, const Vector3& localDirectionVector)
513    {
514        Quaternion savedOrientation(this->getOrientation());
515        Ogre::Node::TransformSpace ogreRelativeTo;
516        switch (relativeTo)
517        {
518        case TransformSpace::Local:
519            ogreRelativeTo = Ogre::Node::TS_LOCAL; break;
520        case TransformSpace::Parent:
521            ogreRelativeTo = Ogre::Node::TS_PARENT; break;
522        case TransformSpace::World:
523            ogreRelativeTo = Ogre::Node::TS_WORLD; break;
524        }
525        this->node_->setDirection(direction, ogreRelativeTo, localDirectionVector);
526        Quaternion newOrientation(this->node_->getOrientation());
527        this->node_->setOrientation(savedOrientation);
528        this->setOrientation(newOrientation);
529    }
530
531    void WorldEntity::setScale3D(const Vector3& scale)
532    {
533/*
534        if (this->hasPhysics() && scale != Vector3::UNIT_SCALE)
535        {
536            CCOUT(2) << "Warning: Cannot set the scale of a physical object: Not yet implemented." << std::endl;
537            return;
538        }
539*/
540        this->node_->setScale(scale);
541
542        this->changedScale();
543    }
544
545    const Vector3& WorldEntity::getWorldScale3D() const
546    {
547        return this->node_->_getDerivedScale();
548    }
549
550    float WorldEntity::getWorldScale() const
551    {
552        Vector3 scale = this->getWorldScale3D();
553        return (scale.x == scale.y && scale.x == scale.z) ? scale.x : 1;
554    }
555
556    void WorldEntity::setCollisionType(CollisionType type)
557    {
558        // If we are already attached to a parent, this would be a bad idea..
559        if (this->parent_)
560        {
561            CCOUT(2) << "Warning: Cannot set the collision type of a WorldEntity with a parent." << std::endl;
562            return;
563        }
564        else if (this->addedToPhysicalWorld())
565        {
566            CCOUT(2) << "Warning: Cannot set the collision type at run time." << std::endl;
567            return;
568        }
569
570        // Check for type legality. Could be StaticEntity or MobileEntity
571        if (!this->isCollisionTypeLegal(type))
572            return;
573        if (type != None && !this->getScene()->hasPhysics())
574        {
575            CCOUT(2) << "Warning: Cannot have physical bodies in a non physical scene." << std::endl;
576            return;
577        }
578
579        // Check whether we have to create or destroy.
580        if (type != None && this->collisionType_ == None)
581        {
582/*
583            // Check whether there was some scaling applied.
584            if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001))
585            {
586                CCOUT(2) << "Warning: Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << std::endl;
587                return;
588            }
589*/
590            // Create new rigid body
591            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape());
592            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
593            this->physicalBody_->setUserPointer(this);
594            this->physicalBody_->setActivationState(DISABLE_DEACTIVATION);
595        }
596        else if (type == None && this->collisionType_ != None)
597        {
598            // Destroy rigid body
599            assert(this->physicalBody_);
600            deactivatePhysics();
601            delete this->physicalBody_;
602            this->physicalBody_ = 0;
603            this->collisionType_ = None;
604            this->collisionTypeSynchronised_ = None;
605            return;
606        }
607
608        // Change type
609        switch (type)
610        {
611        case Dynamic:
612            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
613            break;
614        case Kinematic:
615            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
616            break;
617        case Static:
618            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
619            break;
620        case None:
621            return; // this->collisionType_ was None too
622        }
623
624        // Only sets this->collisionShape_
625        // However the assertion is to ensure that the internal bullet setting is right
626        updateCollisionType();
627        assert(this->collisionType_ == type);
628
629        // update mass and inertia tensor
630        recalculateMassProps();
631        resetPhysicsProps();
632        collisionCallbackActivityChanged();
633        activatePhysics();
634    }
635
636    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
637    {
638        std::string typeStrLower = getLowercase(typeStr);
639        CollisionType type;
640        if (typeStrLower == "dynamic")
641            type = Dynamic;
642        else if (typeStrLower == "static")
643            type = Static;
644        else if (typeStrLower == "kinematic")
645            type = Kinematic;
646        else if (typeStrLower == "none")
647            type = None;
648        else
649            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
650        this->setCollisionType(type);
651    }
652
653    std::string WorldEntity::getCollisionTypeStr() const
654    {
655        switch (this->getCollisionType())
656        {
657            case Dynamic:
658                return "dynamic";
659            case Kinematic:
660                return "kinematic";
661            case Static:
662                return "static";
663            case None:
664                return "none";
665            default:
666                assert(false);
667                return "";
668        }
669    }
670
671    void WorldEntity::updateCollisionType()
672    {
673        if (!this->physicalBody_)
674            this->collisionType_ = None;
675        else if (this->physicalBody_->isKinematicObject())
676            this->collisionType_ = Kinematic;
677        else if (this->physicalBody_->isStaticObject())
678            this->collisionType_ = Static;
679        else
680            this->collisionType_ = Dynamic;
681        this->collisionTypeSynchronised_ = this->collisionType_;
682    }
683
684    void WorldEntity::notifyChildMassChanged() // Called by a child WE
685    {
686        // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already
687        // Recalculate mass
688        this->childrenMass_ = 0.0f;
689        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
690            this->childrenMass_ += (*it)->getMass();
691        recalculateMassProps();
692        // Notify parent WE
693        if (this->parent_)
694            parent_->notifyChildMassChanged();
695    }
696
697    void WorldEntity::notifyCollisionShapeChanged() // called by this->collisionShape_
698    {
699        if (hasPhysics())
700        {
701            // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again
702            if (this->addedToPhysicalWorld())
703            {
704                this->deactivatePhysics();
705                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
706                this->activatePhysics();
707            }
708            else
709                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
710        }
711        recalculateMassProps();
712    }
713
714    void WorldEntity::recalculateMassProps()
715    {
716        // Store local inertia for faster access. Evaluates to (0,0,0) if there is no collision shape.
717        float totalMass = this->mass_ + this->childrenMass_;
718        this->collisionShape_->calculateLocalInertia(totalMass, this->localInertia_);
719        if (this->hasPhysics())
720        {
721            if (this->isStatic())
722            {
723                // Just set everything to zero
724                this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
725            }
726            else if ((this->mass_ + this->childrenMass_) == 0.0f)
727            {
728                // Use default values to avoid very large or very small values
729                CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0." << std::endl;
730                btVector3 inertia(0, 0, 0);
731                this->collisionShape_->calculateLocalInertia(1.0f, inertia);
732                this->physicalBody_->setMassProps(1.0f, inertia);
733            }
734            else
735            {
736                this->physicalBody_->setMassProps(totalMass, this->localInertia_);
737            }
738        }
739    }
740
741    void WorldEntity::resetPhysicsProps()
742    {
743        if (this->hasPhysics())
744        {
745            this->physicalBody_->setRestitution(this->restitution_);
746            this->physicalBody_->setAngularFactor(this->angularFactor_);
747            this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_);
748            this->physicalBody_->setFriction(this->friction_);
749        }
750    }
751}
Note: See TracBrowser for help on using the repository browser.