Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/physics/src/orxonox/objects/worldentities/WorldEntity.cc @ 2300

Last change on this file since 2300 was 2300, checked in by rgrieder, 15 years ago

Still getting physics and its implications straight:

  • Removed PositionableEntity —> StaticEntity is now the way to go. They cannot be translated in any way during physics simulation. The trick will be to remove them and add them again to Bullet. This however is not yet implemented.
  • Forgot a few consts in WorldEntity
  • Fixed a bug with infinite masses
  • WE throws exception if you try to apply physics when the SceneNode is not in the root space of the Scene.
  • Moved velocity_ to MovableEntity
  • Outside world reference of WE/ME are now always the non-physical values. getPosition() will always return node_→getPosition() and when setting it, both RigidBody and SceneNode are translated. This accounts for velocity, orientation and position.
  • Property svn:eol-style set to native
File size: 13.1 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 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "OrxonoxStableHeaders.h"
30#include "WorldEntity.h"
31
32#include <cassert>
33#include <OgreSceneManager.h>
34
35#include "BulletCollision/CollisionShapes/btSphereShape.h"
36
37#include "util/Exception.h"
38#include "util/Convert.h"
39#include "core/CoreIncludes.h"
40#include "core/XMLPort.h"
41
42#include "objects/Scene.h"
43
44namespace orxonox
45{
46    const Vector3 WorldEntity::FRONT = Vector3::NEGATIVE_UNIT_Z;
47    const Vector3 WorldEntity::BACK  = Vector3::UNIT_Z;
48    const Vector3 WorldEntity::LEFT  = Vector3::NEGATIVE_UNIT_X;
49    const Vector3 WorldEntity::RIGHT = Vector3::UNIT_X;
50    const Vector3 WorldEntity::DOWN  = Vector3::NEGATIVE_UNIT_Y;
51    const Vector3 WorldEntity::UP    = Vector3::UNIT_Y;
52
53    WorldEntity::WorldEntity(BaseObject* creator) : BaseObject(creator), network::Synchronisable(creator)
54    {
55        RegisterObject(WorldEntity);
56
57        assert(this->getScene());
58        assert(this->getScene()->getRootSceneNode());
59
60        this->node_ = this->getScene()->getRootSceneNode()->createChildSceneNode();
61
62        this->parent_ = 0;
63        this->parentID_ = (unsigned int)-1;
64
65        this->node_->setPosition(Vector3::ZERO);
66        this->node_->setOrientation(Quaternion::IDENTITY);
67
68        // Default behaviour does not include physics
69        this->physicalBody_ = 0;
70        updateCollisionType();
71
72        this->registerVariables();
73    }
74
75    WorldEntity::~WorldEntity()
76    {
77        if (this->isInitialized())
78        {
79            this->node_->detachAllObjects();
80            if (this->getScene()->getSceneManager())
81                this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
82
83            this->setCollisionType(None);
84        }
85    }
86
87    void WorldEntity::XMLPort(Element& xmlelement, XMLPort::Mode mode)
88    {
89        SUPER(WorldEntity, XMLPort, xmlelement, mode);
90
91        XMLPortParamTemplate(WorldEntity, "position", setPosition, getPosition, xmlelement, mode, const Vector3&);
92        XMLPortParamTemplate(WorldEntity, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&);
93        XMLPortParamLoadOnly(WorldEntity, "lookat", lookAt_xmlport, xmlelement, mode);
94        XMLPortParamLoadOnly(WorldEntity, "direction", setDirection_xmlport, xmlelement, mode);
95        XMLPortParamLoadOnly(WorldEntity, "yaw", yaw_xmlport, xmlelement, mode);
96        XMLPortParamLoadOnly(WorldEntity, "pitch", pitch_xmlport, xmlelement, mode);
97        XMLPortParamLoadOnly(WorldEntity, "roll", roll_xmlport, xmlelement, mode);
98        XMLPortParamTemplate(WorldEntity, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&);
99        XMLPortParam(WorldEntity, "scale", setScale, getScale, xmlelement, mode);
100
101        XMLPortParam(WorldEntity, "collisionType", setCollisionTypeStr, getCollisionTypeStr, xmlelement, mode);
102        XMLPortParam(WorldEntity, "collisionRadius", setCollisionRadius, getCollisionRadius, xmlelement, mode);
103        XMLPortParam(WorldEntity, "mass", setMass, getMass, xmlelement, mode);
104
105        XMLPortObject(WorldEntity, WorldEntity, "attached", attach, getAttachedObject, xmlelement, mode);
106
107        // Add the physical after loading because we cannot change its attributes without removing.
108        if (getCollisionType() != None)
109            this->getScene()->getPhysicalWorld()->addRigidBody(this->physicalBody_);
110    }
111
112    void WorldEntity::registerVariables()
113    {
114        REGISTERDATA(this->bActive_,  network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity));
115        REGISTERDATA(this->bVisible_, network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility));
116
117        REGISTERDATA(this->getScale3D().x, network::direction::toclient);
118        REGISTERDATA(this->getScale3D().y, network::direction::toclient);
119        REGISTERDATA(this->getScale3D().z, network::direction::toclient);
120
121        REGISTERDATA(this->parentID_, network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::updateParent));
122    }
123
124    void WorldEntity::updateParent()
125    {
126        WorldEntity* parent = dynamic_cast<WorldEntity*>(Synchronisable::getSynchronisable(this->parentID_));
127        if (parent)
128            this->attachToParent(parent);
129    }
130
131    void WorldEntity::attach(WorldEntity* object)
132    {
133        if (object->getParent())
134            object->detachFromParent();
135        else
136        {
137            Ogre::Node* parent = object->node_->getParent();
138            if (parent)
139                parent->removeChild(object->node_);
140        }
141
142        this->node_->addChild(object->node_);
143        this->children_.insert(object);
144        object->parent_ = this;
145        object->parentID_ = this->getObjectID();
146
147        // Do the physical connection if required
148        //this->attachPhysicalObject(object);
149    }
150
151    //void WorldEntity::attachPhysicalObject(WorldEntity* object)
152    //{
153    //    StaticEntity* staticObject = dynamic_cast<StaticEntity*>(object);
154    //    if (staticObject != 0 && this->hasPhysics())
155    //    {
156    //       btCompoundShape* compoundShape = dynamic_cast<btCompoundShape*>(this->physicalBody_->getCollisionShape());
157    //       if (compoundShape == 0)
158    //       {
159    //            // create a compound shape and add both
160    //            compoundShape = new btCompoundShape();
161    //            compoundShape->addChildShape(this->physicalBody_->getCollisionShape());
162    //            compoundShape->addChildShape(staticObject->getCollisionShape());
163    //            this->physicalBody_->setCollisionShape();
164    //       }
165    //       else
166    //       {
167    //           compoundShape -> addChildShape(staticObject->getCollisionShape());
168    //       }
169    //    }
170    //}
171
172    void WorldEntity::detach(WorldEntity* object)
173    {
174        this->node_->removeChild(object->node_);
175        this->children_.erase(object);
176        object->parent_ = 0;
177        object->parentID_ = (unsigned int)-1;
178
179//        this->getScene()->getRootSceneNode()->addChild(object->node_);
180    }
181
182    WorldEntity* WorldEntity::getAttachedObject(unsigned int index) const
183    {
184        unsigned int i = 0;
185        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
186        {
187            if (i == index)
188                return (*it);
189            ++i;
190        }
191        return 0;
192    }
193
194    float WorldEntity::getMass() const
195    {
196        if (!checkPhysics())
197            return 0.0f;
198
199        if (this->physicalBody_->getInvMass() == 0.0f)
200            return 0.0f;
201        else
202            return 1.0f/this->physicalBody_->getInvMass();
203    }
204
205    void WorldEntity::setMass(float mass)
206    {
207        if (!checkPhysics())
208            return;
209        else if (this->physicalBody_->isInWorld())
210        {
211            CCOUT(2) << "Cannot set the physical mass at run time." << std::endl;
212            assert(false);
213        }
214        else
215        {
216            this->physicalBody_->setMassProps(mass, btVector3(0,0,0));
217            updateCollisionType();
218        }
219    }
220
221    void WorldEntity::setCollisionType(CollisionType type)
222    {
223        // Check first whether we have to create or destroy.
224        if (type != None && this->collisionType_ == None)
225        {
226            // First, check whether our SceneNode is relative to the root space of the scene.
227            // TODO: Static and Kinematic objects don't always have to obey this rule.
228            if (this->node_->getParent() != this->getScene()->getRootSceneNode())
229                ThrowException(PhysicsViolation, "Cannot make WorldEntity physical that is not in the root space of the Scene.");
230
231            // Create new rigid body
232            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, 0, btVector3(0,0,0));
233            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
234            this->physicalBody_->setUserPointer(this);
235
236            // Adjust parameters according to the node
237            //btTransform nodeTransform;
238            //this->
239        }
240        else if (type == None && this->collisionType_ != None)
241        {
242            // Destroy rigid body
243            if (this->physicalBody_->isInWorld())
244                this->getScene()->getPhysicalWorld()->removeRigidBody(this->physicalBody_);
245            if (this->physicalBody_->getCollisionShape())
246                delete this->physicalBody_->getCollisionShape();
247            delete this->physicalBody_;
248            this->physicalBody_ = 0;
249            this->collisionType_ = None;
250            return;
251        }
252
253        // Check for type legality. Could be StaticEntity or MovableEntity
254        if (!this->isCollisionTypeLegal(type))
255            return; // exception gets issued anyway
256
257        // Change type
258        switch (type)
259        {
260        case Dynamic:
261            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
262            break;
263        case Kinematic:
264            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
265            break;
266        case Static:
267            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
268            break;
269        case None:
270            return; // this->collisionType_ was None too
271        }
272
273        // Mass non zero is a bad idea for kinematic and static objects
274        if ((type == Kinematic || type == Static) && getMass() != 0.0f)
275            this->setMass(0.0f);
276        // Mass zero is not such a good idea for dynamic objects
277        else if (type == Dynamic && getMass() == 0.0f)
278            this->setMass(1.0f);
279
280        // finally update our variable for faster checks
281        updateCollisionType();
282    }
283
284    void WorldEntity::updateCollisionType()
285    {
286        if (!this->physicalBody_)
287            this->collisionType_ = None;
288        else if (this->physicalBody_->isKinematicObject())
289            this->collisionType_ = Kinematic;
290        else if (this->physicalBody_->isStaticObject())
291            this->collisionType_ = Static;
292        else
293            this->collisionType_ = Dynamic;
294    }
295
296    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
297    {
298        std::string typeStrLower = getLowercase(typeStr);
299        CollisionType type;
300        if (typeStrLower == "dynamic")
301            type = Dynamic;
302        else if (typeStrLower == "static")
303            type = Static;
304        else if (typeStrLower == "kinematic")
305            type = Kinematic;
306        else if (typeStrLower == "none")
307            type = None;
308        else
309            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
310        this->setCollisionType(type);
311    }
312
313    std::string WorldEntity::getCollisionTypeStr() const
314    {
315        switch (this->getCollisionType())
316        {
317            case Dynamic:
318                return "dynamic";
319            case Kinematic:
320                return "kinematic";
321            case Static:
322                return "static";
323            case None:
324                return "none";
325            default:
326                assert(false);
327                return "";
328        }
329    }
330
331    void WorldEntity::setCollisionRadius(float radius)
332    {
333        if (!checkPhysics())
334            return;
335
336        // destroy old one first
337        btCollisionShape* oldShape = this->physicalBody_->getCollisionShape();
338        if (oldShape)
339            delete oldShape;
340
341        this->physicalBody_->setCollisionShape(new btSphereShape(btScalar(radius)));
342    }
343
344    float WorldEntity::getCollisionRadius() const
345    {
346        if (checkPhysics())
347        {
348            btSphereShape* sphere = dynamic_cast<btSphereShape*>(this->physicalBody_->getCollisionShape());
349            if (sphere)
350                return (float)sphere->getRadius();
351        }
352        return 0.0f;
353    }
354
355    bool WorldEntity::checkPhysics() const
356    {
357        if (!this->physicalBody_)
358        {
359            assert(this->getCollisionType() == None);
360            COUT(2) << "WorldEntity was not fitted with physics, cannot set phyiscal property." << std::endl;
361            return false;
362        }
363        else
364            return true;
365    }
366}
Note: See TracBrowser for help on using the repository browser.