Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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