Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2494 was 2494, checked in by landauf, 15 years ago

shooting, hitting and killing works

  • Property svn:eol-style set to native
File size: 26.9 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->getScene()->getSceneManager())
107                this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
108
109            // TODO: Detach from parent and detach all children.
110
111            if (this->physicalBody_)
112            {
113                this->deactivatePhysics();
114                delete this->physicalBody_;
115            }
116            delete this->collisionShape_;
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        // check first whether attaching is even allowed
256        if (object->hasPhysics())
257        {
258            if (!this->hasPhysics())
259            {
260                COUT(2) << "Warning: Cannot attach a physical object to a non physical one." << std::endl;
261                return;
262            }
263            else if (object->isDynamic())
264            {
265                COUT(2) << "Warning: Cannot attach a dynamic object to a WorldEntity." << std::endl;
266                return;
267            }
268            else if (object->isKinematic() && this->isDynamic())
269            {
270                COUT(2) << "Warning: Cannot attach a kinematic object to a dynamic one." << std::endl;
271                return;
272            }
273            else if (object->isKinematic())
274            {
275                COUT(2) << "Warning: Cannot attach a kinematic object to a static or kinematic one: Not yet implemented." << std::endl;
276                return;
277            }
278            else
279            {
280                object->deactivatePhysics();
281            }
282        }
283
284        if (object == this)
285        {
286            COUT(2) << "Warning: Can't attach a WorldEntity to itself." << std::endl;
287            return;
288        }
289
290        if (object->getParent())
291            object->detachFromParent();
292
293        this->attachNode(object->node_);
294
295        this->children_.insert(object);
296        object->parent_ = this;
297        object->parentID_ = this->getObjectID();
298
299        // collision shapes
300        this->attachCollisionShape(object->getCollisionShape());
301        // mass
302        this->childrenMass_ += object->getMass();
303        recalculateMassProps();
304    }
305
306    void WorldEntity::detach(WorldEntity* object)
307    {
308        // collision shapes
309        this->detachCollisionShape(object->getCollisionShape());
310        // mass
311        if (object->getMass() > 0.0f)
312        {
313            this->childrenMass_ -= object->getMass();
314            recalculateMassProps();
315        }
316
317        this->detachNode(object->node_);
318        this->children_.erase(object);
319        object->parent_ = 0;
320        object->parentID_ = OBJECTID_UNKNOWN;
321
322        // Note: It is possible that the object has physics but was disabled when attaching
323        object->activatePhysics();
324    }
325
326    WorldEntity* WorldEntity::getAttachedObject(unsigned int index) const
327    {
328        unsigned int i = 0;
329        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
330        {
331            if (i == index)
332                return (*it);
333            ++i;
334        }
335        return 0;
336    }
337
338    void WorldEntity::attachOgreObject(Ogre::MovableObject* object)
339    {
340        this->node_->attachObject(object);
341    }
342
343    void WorldEntity::detachOgreObject(Ogre::MovableObject* object)
344    {
345        this->node_->detachObject(object);
346    }
347
348    Ogre::MovableObject* WorldEntity::detachOgreObject(const Ogre::String& name)
349    {
350        return this->node_->detachObject(name);
351    }
352
353    void WorldEntity::attachCollisionShape(CollisionShape* shape)
354    {
355        this->collisionShape_->addChildShape(shape);
356        // Note: this->collisionShape_ already notifies us of any changes.
357    }
358
359    void WorldEntity::detachCollisionShape(CollisionShape* shape)
360    {
361        this->collisionShape_->removeChildShape(shape);
362        // Note: this->collisionShape_ already notifies us of any changes.
363    }
364
365    CollisionShape* WorldEntity::getAttachedCollisionShape(unsigned int index) const
366    {
367        return this->collisionShape_->getChildShape(index);
368    }
369
370    void WorldEntity::activatePhysics()
371    {
372        if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_)
373        {
374            this->getScene()->addPhysicalObject(this);
375            this->bPhysicsActive_ = true;
376        }
377    }
378
379    void WorldEntity::deactivatePhysics()
380    {
381        if (this->isPhysicsActive())
382        {
383            this->getScene()->removePhysicalObject(this);
384            this->bPhysicsActive_ = false;
385        }
386    }
387
388    bool WorldEntity::addedToPhysicalWorld() const
389    {
390        return this->physicalBody_ && this->physicalBody_->isInWorld();
391    }
392
393#ifndef _NDEBUG
394    const Vector3& WorldEntity::getPosition() const
395    {
396        return this->node_->getPosition();
397    }
398
399    const Quaternion& WorldEntity::getOrientation() const
400    {
401        return this->node_->getOrientation();
402    }
403
404    const Vector3& WorldEntity::getScale3D() const
405    {
406        return this->node_->getScale();
407    }
408#endif
409
410    const Vector3& WorldEntity::getWorldPosition() const
411    {
412        return this->node_->_getDerivedPosition();
413    }
414
415    const Quaternion& WorldEntity::getWorldOrientation() const
416    {
417        return this->node_->_getDerivedOrientation();
418    }
419
420    void WorldEntity::translate(const Vector3& distance, TransformSpace::Space relativeTo)
421    {
422        switch (relativeTo)
423        {
424        case TransformSpace::Local:
425            // position is relative to parent so transform downwards
426            this->setPosition(this->getPosition() + this->getOrientation() * distance);
427            break;
428        case TransformSpace::Parent:
429            this->setPosition(this->getPosition() + distance);
430            break;
431        case TransformSpace::World:
432            // position is relative to parent so transform upwards
433            if (this->node_->getParent())
434                setPosition(getPosition() + (node_->getParent()->_getDerivedOrientation().Inverse() * distance)
435                    / node_->getParent()->_getDerivedScale());
436            else
437                this->setPosition(this->getPosition() + distance);
438            break;
439        }
440    }
441
442    void WorldEntity::rotate(const Quaternion& rotation, TransformSpace::Space relativeTo)
443    {
444        switch(relativeTo)
445        {
446        case TransformSpace::Local:
447            this->setOrientation(this->getOrientation() * rotation);
448            break;
449        case TransformSpace::Parent:
450            // Rotations are normally relative to local axes, transform up
451            this->setOrientation(rotation * this->getOrientation());
452            break;
453        case TransformSpace::World:
454            // Rotations are normally relative to local axes, transform up
455            this->setOrientation(this->getOrientation() * this->getWorldOrientation().Inverse()
456                * rotation * this->getWorldOrientation());
457            break;
458        }
459    }
460
461    void WorldEntity::lookAt(const Vector3& target, TransformSpace::Space relativeTo, const Vector3& localDirectionVector)
462    {
463        Vector3 origin;
464        switch (relativeTo)
465        {
466        case TransformSpace::Local:
467            origin = Vector3::ZERO;
468            break;
469        case TransformSpace::Parent:
470            origin = this->getPosition();
471            break;
472        case TransformSpace::World:
473            origin = this->getWorldPosition();
474            break;
475        }
476        this->setDirection(target - origin, relativeTo, localDirectionVector);
477    }
478
479    void WorldEntity::setDirection(const Vector3& direction, TransformSpace::Space relativeTo, const Vector3& localDirectionVector)
480    {
481        Quaternion savedOrientation(this->getOrientation());
482        Ogre::Node::TransformSpace ogreRelativeTo;
483        switch (relativeTo)
484        {
485        case TransformSpace::Local:
486            ogreRelativeTo = Ogre::Node::TS_LOCAL; break;
487        case TransformSpace::Parent:
488            ogreRelativeTo = Ogre::Node::TS_PARENT; break;
489        case TransformSpace::World:
490            ogreRelativeTo = Ogre::Node::TS_WORLD; break;
491        }
492        this->node_->setDirection(direction, ogreRelativeTo, localDirectionVector);
493        Quaternion newOrientation(this->node_->getOrientation());
494        this->node_->setOrientation(savedOrientation);
495        this->setOrientation(newOrientation);
496    }
497
498    void WorldEntity::setScale3D(const Vector3& scale)
499    {
500/*
501        if (this->hasPhysics() && scale != Vector3::UNIT_SCALE)
502        {
503            CCOUT(2) << "Warning: Cannot set the scale of a physical object: Not yet implemented." << std::endl;
504            return;
505        }
506*/
507        this->node_->setScale(scale);
508
509        this->changedScale();
510    }
511
512    const Vector3& WorldEntity::getWorldScale3D() const
513    {
514        return this->node_->_getDerivedScale();
515    }
516
517    float WorldEntity::getWorldScale() const
518    {
519        Vector3 scale = this->getWorldScale3D();
520        return (scale.x == scale.y && scale.x == scale.z) ? scale.x : 1;
521    }
522
523    void WorldEntity::setCollisionType(CollisionType type)
524    {
525        // If we are already attached to a parent, this would be a bad idea..
526        if (this->parent_)
527        {
528            CCOUT(2) << "Warning: Cannot set the collision type of a WorldEntity with a parent." << std::endl;
529            return;
530        }
531        else if (this->addedToPhysicalWorld())
532        {
533            CCOUT(2) << "Warning: Cannot set the collision type at run time." << std::endl;
534            return;
535        }
536
537        // Check for type legality. Could be StaticEntity or MobileEntity
538        if (!this->isCollisionTypeLegal(type))
539            return;
540        if (type != None && !this->getScene()->hasPhysics())
541        {
542            CCOUT(2) << "Warning: Cannot have physical bodies in a non physical scene." << std::endl;
543            return;
544        }
545
546        // Check whether we have to create or destroy.
547        if (type != None && this->collisionType_ == None)
548        {
549            // Check whether there was some scaling applied.
550            if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001))
551            {
552                CCOUT(2) << "Warning: Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << std::endl;
553                return;
554            }
555
556            // Create new rigid body
557            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape());
558            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
559            this->physicalBody_->setUserPointer(this);
560            this->physicalBody_->setActivationState(DISABLE_DEACTIVATION);
561        }
562        else if (type == None && this->collisionType_ != None)
563        {
564            // Destroy rigid body
565            assert(this->physicalBody_);
566            deactivatePhysics();
567            delete this->physicalBody_;
568            this->physicalBody_ = 0;
569            this->collisionType_ = None;
570            this->collisionTypeSynchronised_ = None;
571            return;
572        }
573
574        // Change type
575        switch (type)
576        {
577        case Dynamic:
578            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
579            break;
580        case Kinematic:
581            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
582            break;
583        case Static:
584            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
585            break;
586        case None:
587            return; // this->collisionType_ was None too
588        }
589
590        // Only sets this->collisionShape_
591        // However the assertion is to ensure that the internal bullet setting is right
592        updateCollisionType();
593        assert(this->collisionType_ == type);
594
595        // update mass and inertia tensor
596        recalculateMassProps();
597        resetPhysicsProps();
598        collisionCallbackActivityChanged();
599        activatePhysics();
600    }
601
602    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
603    {
604        std::string typeStrLower = getLowercase(typeStr);
605        CollisionType type;
606        if (typeStrLower == "dynamic")
607            type = Dynamic;
608        else if (typeStrLower == "static")
609            type = Static;
610        else if (typeStrLower == "kinematic")
611            type = Kinematic;
612        else if (typeStrLower == "none")
613            type = None;
614        else
615            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
616        this->setCollisionType(type);
617    }
618
619    std::string WorldEntity::getCollisionTypeStr() const
620    {
621        switch (this->getCollisionType())
622        {
623            case Dynamic:
624                return "dynamic";
625            case Kinematic:
626                return "kinematic";
627            case Static:
628                return "static";
629            case None:
630                return "none";
631            default:
632                assert(false);
633                return "";
634        }
635    }
636
637    void WorldEntity::updateCollisionType()
638    {
639        if (!this->physicalBody_)
640            this->collisionType_ = None;
641        else if (this->physicalBody_->isKinematicObject())
642            this->collisionType_ = Kinematic;
643        else if (this->physicalBody_->isStaticObject())
644            this->collisionType_ = Static;
645        else
646            this->collisionType_ = Dynamic;
647        this->collisionTypeSynchronised_ = this->collisionType_;
648    }
649
650    void WorldEntity::notifyChildMassChanged() // Called by a child WE
651    {
652        // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already
653        // Recalculate mass
654        this->childrenMass_ = 0.0f;
655        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
656            this->childrenMass_ += (*it)->getMass();
657        recalculateMassProps();
658        // Notify parent WE
659        if (this->parent_)
660            parent_->notifyChildMassChanged();
661    }
662
663    void WorldEntity::notifyCollisionShapeChanged() // called by this->collisionShape_
664    {
665        if (hasPhysics())
666        {
667            // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again
668            if (this->addedToPhysicalWorld())
669            {
670                this->deactivatePhysics();
671                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
672                this->activatePhysics();
673            }
674            else
675                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
676        }
677        recalculateMassProps();
678    }
679
680    void WorldEntity::recalculateMassProps()
681    {
682        // Store local inertia for faster access. Evaluates to (0,0,0) if there is no collision shape.
683        float totalMass = this->mass_ + this->childrenMass_;
684        this->collisionShape_->calculateLocalInertia(totalMass, this->localInertia_);
685        if (this->hasPhysics())
686        {
687            if (this->isStatic())
688            {
689                // Just set everything to zero
690                this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
691            }
692            else if ((this->mass_ + this->childrenMass_) == 0.0f)
693            {
694                // Use default values to avoid very large or very small values
695                CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0." << std::endl;
696                btVector3 inertia(0, 0, 0);
697                this->collisionShape_->calculateLocalInertia(1.0f, inertia);
698                this->physicalBody_->setMassProps(1.0f, inertia);
699            }
700            else
701            {
702                this->physicalBody_->setMassProps(totalMass, this->localInertia_);
703            }
704        }
705    }
706
707    void WorldEntity::resetPhysicsProps()
708    {
709        if (this->hasPhysics())
710        {
711            this->physicalBody_->setRestitution(this->restitution_);
712            this->physicalBody_->setAngularFactor(this->angularFactor_);
713            this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_);
714            this->physicalBody_->setFriction(this->friction_);
715        }
716    }
717}
Note: See TracBrowser for help on using the repository browser.