Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2501 was 2501, checked in by landauf, 15 years ago
  • GlobalShader in dedicated mode works again
  • Shooting as a client works
  • Fixed problem with NotificationQueue
  • 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/*
548            // Check whether there was some scaling applied.
549            if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001))
550            {
551                CCOUT(2) << "Warning: Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << std::endl;
552                return;
553            }
554*/
555            // Create new rigid body
556            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape());
557            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
558            this->physicalBody_->setUserPointer(this);
559            this->physicalBody_->setActivationState(DISABLE_DEACTIVATION);
560        }
561        else if (type == None && this->collisionType_ != None)
562        {
563            // Destroy rigid body
564            assert(this->physicalBody_);
565            deactivatePhysics();
566            delete this->physicalBody_;
567            this->physicalBody_ = 0;
568            this->collisionType_ = None;
569            this->collisionTypeSynchronised_ = None;
570            return;
571        }
572
573        // Change type
574        switch (type)
575        {
576        case Dynamic:
577            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
578            break;
579        case Kinematic:
580            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
581            break;
582        case Static:
583            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
584            break;
585        case None:
586            return; // this->collisionType_ was None too
587        }
588
589        // Only sets this->collisionShape_
590        // However the assertion is to ensure that the internal bullet setting is right
591        updateCollisionType();
592        assert(this->collisionType_ == type);
593
594        // update mass and inertia tensor
595        recalculateMassProps();
596        resetPhysicsProps();
597        collisionCallbackActivityChanged();
598        activatePhysics();
599    }
600
601    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
602    {
603        std::string typeStrLower = getLowercase(typeStr);
604        CollisionType type;
605        if (typeStrLower == "dynamic")
606            type = Dynamic;
607        else if (typeStrLower == "static")
608            type = Static;
609        else if (typeStrLower == "kinematic")
610            type = Kinematic;
611        else if (typeStrLower == "none")
612            type = None;
613        else
614            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
615        this->setCollisionType(type);
616    }
617
618    std::string WorldEntity::getCollisionTypeStr() const
619    {
620        switch (this->getCollisionType())
621        {
622            case Dynamic:
623                return "dynamic";
624            case Kinematic:
625                return "kinematic";
626            case Static:
627                return "static";
628            case None:
629                return "none";
630            default:
631                assert(false);
632                return "";
633        }
634    }
635
636    void WorldEntity::updateCollisionType()
637    {
638        if (!this->physicalBody_)
639            this->collisionType_ = None;
640        else if (this->physicalBody_->isKinematicObject())
641            this->collisionType_ = Kinematic;
642        else if (this->physicalBody_->isStaticObject())
643            this->collisionType_ = Static;
644        else
645            this->collisionType_ = Dynamic;
646        this->collisionTypeSynchronised_ = this->collisionType_;
647    }
648
649    void WorldEntity::notifyChildMassChanged() // Called by a child WE
650    {
651        // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already
652        // Recalculate mass
653        this->childrenMass_ = 0.0f;
654        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
655            this->childrenMass_ += (*it)->getMass();
656        recalculateMassProps();
657        // Notify parent WE
658        if (this->parent_)
659            parent_->notifyChildMassChanged();
660    }
661
662    void WorldEntity::notifyCollisionShapeChanged() // called by this->collisionShape_
663    {
664        if (hasPhysics())
665        {
666            // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again
667            if (this->addedToPhysicalWorld())
668            {
669                this->deactivatePhysics();
670                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
671                this->activatePhysics();
672            }
673            else
674                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
675        }
676        recalculateMassProps();
677    }
678
679    void WorldEntity::recalculateMassProps()
680    {
681        // Store local inertia for faster access. Evaluates to (0,0,0) if there is no collision shape.
682        float totalMass = this->mass_ + this->childrenMass_;
683        this->collisionShape_->calculateLocalInertia(totalMass, this->localInertia_);
684        if (this->hasPhysics())
685        {
686            if (this->isStatic())
687            {
688                // Just set everything to zero
689                this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
690            }
691            else if ((this->mass_ + this->childrenMass_) == 0.0f)
692            {
693                // Use default values to avoid very large or very small values
694                CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0." << std::endl;
695                btVector3 inertia(0, 0, 0);
696                this->collisionShape_->calculateLocalInertia(1.0f, inertia);
697                this->physicalBody_->setMassProps(1.0f, inertia);
698            }
699            else
700            {
701                this->physicalBody_->setMassProps(totalMass, this->localInertia_);
702            }
703        }
704    }
705
706    void WorldEntity::resetPhysicsProps()
707    {
708        if (this->hasPhysics())
709        {
710            this->physicalBody_->setRestitution(this->restitution_);
711            this->physicalBody_->setAngularFactor(this->angularFactor_);
712            this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_);
713            this->physicalBody_->setFriction(this->friction_);
714        }
715    }
716}
Note: See TracBrowser for help on using the repository browser.