Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2303 was 2303, checked in by rgrieder, 15 years ago
  • Added support for attaching physical WorldEntities to each other. Currently you can only add static objects to kinematic/dynamic/static other objects. Future plans involve attaching kinematic objects to static/kinematic ones. All other combinations don't make sense at all.
  • Added CollisionShape, SphereCollisionShape and CompoundCollisionShape

Usage for collision shapes (example):

<LinearEntity collisionType="kinematic">

<attached>

<Model position="0,0,0" scale=10 mesh="ast1.mesh" />
<StaticEntity position="0,10,0" collisionType="static"> # Everything else than "static" fails!

<collisionShapes>

<SphereCollisionShape radius=40 position="10,10,-10"/>
<CompoundCollisionShape position="4,4,4"> # You can also make compound shapes directly

<SphereCollisionShape radius=10/>

</CompoundCollisionShape>

</collisionShapes>

</StaticEntity>

</attached>

</LinearEntity>

  • Property svn:eol-style set to native
File size: 16.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 *   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/btCollisionShape.h"
36#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h"
37#include "BulletDynamics/Dynamics/btRigidBody.h"
38
39#include "util/Exception.h"
40#include "util/Convert.h"
41#include "core/CoreIncludes.h"
42#include "core/XMLPort.h"
43
44#include "objects/Scene.h"
45#include "objects/worldentities/collisionshapes/CollisionShape.h"
46#include "objects/worldentities/collisionshapes/CompoundCollisionShape.h"
47
48namespace orxonox
49{
50    const Vector3 WorldEntity::FRONT = Vector3::NEGATIVE_UNIT_Z;
51    const Vector3 WorldEntity::BACK  = Vector3::UNIT_Z;
52    const Vector3 WorldEntity::LEFT  = Vector3::NEGATIVE_UNIT_X;
53    const Vector3 WorldEntity::RIGHT = Vector3::UNIT_X;
54    const Vector3 WorldEntity::DOWN  = Vector3::NEGATIVE_UNIT_Y;
55    const Vector3 WorldEntity::UP    = Vector3::UNIT_Y;
56
57    WorldEntity::WorldEntity(BaseObject* creator) : BaseObject(creator), network::Synchronisable(creator)
58    {
59        RegisterObject(WorldEntity);
60
61        assert(this->getScene());
62        assert(this->getScene()->getRootSceneNode());
63
64        this->node_ = this->getScene()->getRootSceneNode()->createChildSceneNode();
65
66        this->parent_ = 0;
67        this->parentID_ = (unsigned int)-1;
68
69        this->node_->setPosition(Vector3::ZERO);
70        this->node_->setOrientation(Quaternion::IDENTITY);
71
72        // Default behaviour does not include physics
73        this->physicalBody_ = 0;
74        this->collisionShape_ = 0;
75        this->mass_ = 0;
76        updateCollisionType();
77
78        this->registerVariables();
79    }
80
81    WorldEntity::~WorldEntity()
82    {
83        if (this->isInitialized())
84        {
85            this->node_->detachAllObjects();
86            if (this->getScene()->getSceneManager())
87                this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
88
89            this->setCollisionType(None);
90        }
91    }
92
93    void WorldEntity::XMLPort(Element& xmlelement, XMLPort::Mode mode)
94    {
95        SUPER(WorldEntity, XMLPort, xmlelement, mode);
96
97        XMLPortParamTemplate(WorldEntity, "position", setPosition, getPosition, xmlelement, mode, const Vector3&);
98        XMLPortParamTemplate(WorldEntity, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&);
99        XMLPortParamLoadOnly(WorldEntity, "lookat", lookAt_xmlport, xmlelement, mode);
100        XMLPortParamLoadOnly(WorldEntity, "direction", setDirection_xmlport, xmlelement, mode);
101        XMLPortParamLoadOnly(WorldEntity, "yaw", yaw_xmlport, xmlelement, mode);
102        XMLPortParamLoadOnly(WorldEntity, "pitch", pitch_xmlport, xmlelement, mode);
103        XMLPortParamLoadOnly(WorldEntity, "roll", roll_xmlport, xmlelement, mode);
104        XMLPortParamTemplate(WorldEntity, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&);
105        XMLPortParam(WorldEntity, "scale", setScale, getScale, xmlelement, mode);
106
107        XMLPortParam(WorldEntity, "collisionType", setCollisionTypeStr, getCollisionTypeStr, xmlelement, mode);
108        //XMLPortParam(WorldEntity, "collisionRadius", setCollisionRadius, getCollisionRadius, xmlelement, mode);
109        XMLPortParam(WorldEntity, "mass", setMass, getMass, xmlelement, mode);
110
111        XMLPortObject(WorldEntity, WorldEntity, "attached", attach, getAttachedObject, xmlelement, mode);
112        XMLPortObject(WorldEntity, CollisionShape, "collisionShapes", attachCollisionShape, getAttachedCollisionShape, xmlelement, mode);
113    }
114
115    void WorldEntity::registerVariables()
116    {
117        REGISTERDATA(this->bActive_,  network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity));
118        REGISTERDATA(this->bVisible_, network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility));
119
120        REGISTERDATA(this->getScale3D().x, network::direction::toclient);
121        REGISTERDATA(this->getScale3D().y, network::direction::toclient);
122        REGISTERDATA(this->getScale3D().z, network::direction::toclient);
123
124        REGISTERDATA(this->parentID_, network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::updateParent));
125    }
126
127    void WorldEntity::updateParent()
128    {
129        WorldEntity* parent = dynamic_cast<WorldEntity*>(Synchronisable::getSynchronisable(this->parentID_));
130        if (parent)
131            this->attachToParent(parent);
132    }
133
134    void WorldEntity::attach(WorldEntity* object)
135    {
136        // check first whether attaching is even allowed
137        if (object->hasPhysics())
138        {
139            if (!this->hasPhysics())
140                ThrowException(PhysicsViolation, "Cannot attach a physical object to a non physical one.");
141            else if (object->isDynamic())
142                ThrowException(PhysicsViolation, "Cannot attach a dynamic object to a WorldEntity.");
143            else if (object->isKinematic() && this->isDynamic())
144                ThrowException(PhysicsViolation, "Cannot attach a kinematic object to a dynamic one.");
145            else if (object->isKinematic())
146                ThrowException(NotImplemented, "Cannot attach a kinematic object to a static or kinematic one: Not yet implemented.");
147            else if (object->physicalBody_->isInWorld() || this->physicalBody_->isInWorld())
148                ThrowException(PhysicsViolation, "Cannot attach a physical object at runtime.");
149            else
150            {
151                // static to static/kinematic/dynamic --> merge shapes
152                this->attachCollisionShape(object->getCollisionShape());
153                // Remove the btRigidBody from the child object.
154                // That also implies that cannot add a physics WE to the child afterwards.
155                object->setCollisionType(None);
156            }
157        }
158
159        if (object->getParent())
160            object->detachFromParent();
161        else
162        {
163            Ogre::Node* parent = object->node_->getParent();
164            if (parent)
165                parent->removeChild(object->node_);
166        }
167
168        this->node_->addChild(object->node_);
169        this->children_.insert(object);
170        object->parent_ = this;
171        object->parentID_ = this->getObjectID();
172    }
173
174    void WorldEntity::detach(WorldEntity* object)
175    {
176        this->node_->removeChild(object->node_);
177        this->children_.erase(object);
178        object->parent_ = 0;
179        object->parentID_ = (unsigned int)-1;
180
181//        this->getScene()->getRootSceneNode()->addChild(object->node_);
182    }
183
184    WorldEntity* WorldEntity::getAttachedObject(unsigned int index) const
185    {
186        unsigned int i = 0;
187        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
188        {
189            if (i == index)
190                return (*it);
191            ++i;
192        }
193        return 0;
194    }
195
196    void WorldEntity::mergeCollisionShape(CollisionShape* shape)
197    {
198        if (!this->collisionShape_)
199            this->collisionShape_ = new CompoundCollisionShape(this);
200        assert(this->collisionShape_->isCompoundShape());
201
202        // merge with transform
203        CompoundCollisionShape* compoundShape = static_cast<CompoundCollisionShape*>(this->collisionShape_);
204        assert(compoundShape);
205        compoundShape->addChildShape(shape);
206    }
207
208    void WorldEntity::attachCollisionShape(CollisionShape* shape)
209    {
210        this->attachedShapes_.push_back(shape);
211
212        if (!this->collisionShape_ && shape->hasNoTransform())
213        {
214            // Simply add the shape as is.
215            shape->getCollisionShape()->setLocalScaling(shape->getTotalScaling());
216            this->collisionShape_ = shape;
217        }
218        else
219        {
220            if (this->collisionShape_ && !this->collisionShape_->isCompoundShape())
221            {
222                // We have to create a new compound shape and add the old one first.
223                CollisionShape* thisShape = this->collisionShape_;
224                this->collisionShape_ = 0;
225                this->mergeCollisionShape(thisShape);
226            }
227            this->mergeCollisionShape(shape);
228        }
229
230        if (this->physicalBody_)
231        {
232            if (this->physicalBody_->isInWorld())
233                COUT(2) << "Warning: Cannot attach a physical object at runtime.";
234            else
235                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
236        }
237    }
238
239    CollisionShape* WorldEntity::getAttachedCollisionShape(unsigned int index) const
240    {
241        if (index < this->attachedShapes_.size())
242            return attachedShapes_[index];
243        else
244            return 0;
245    }
246
247    //BlinkingBillboard* WorldEntity::getAttachedAsdfObject(unsigned int index) const
248    //{
249    //    return 0;
250    //}
251
252    void WorldEntity::setScale3D(const Vector3& scale)
253    {
254        if (this->hasPhysics())
255            ThrowException(NotImplemented, "Cannot set the scale of a physical object: Not yet implemented.");
256
257        this->node_->setScale(scale);
258    }
259
260    void WorldEntity::scale3D(const Vector3& scale)
261    {
262        if (this->hasPhysics())
263            ThrowException(NotImplemented, "Cannot set the scale of a physical object: Not yet implemented.");
264
265        this->node_->scale(scale);
266    }
267
268    void WorldEntity::setMass(float mass)
269    {
270        this->mass_ = mass;
271        if (!hasPhysics())
272            COUT(2) << "Warning: Setting the mass of a WorldEntity with no physics has no effect." << std::endl;
273        else if (this->physicalBody_->isInWorld())
274            COUT(2) << "Warning: Cannot set the physical mass at run time. Storing temporarily." << std::endl;
275        else
276        {
277            if (this->collisionType_ != Dynamic)
278                COUT(2) << "Warning: Cannot set the physical mass of a static or kinematic object. Storing temporarily." << std::endl;
279            else if (mass == 0.0f)
280                COUT(2) << "Warning: Cannot set physical mass of a dynamic object to zero. Storing temporarily." << std::endl;
281            else
282                this->physicalBody_->setMassProps(mass, btVector3(0,0,0));
283        }
284    }
285
286    void WorldEntity::setCollisionType(CollisionType type)
287    {
288        // If we are already attached to a parent, this would be a bad idea..
289        if (this->parent_)
290            ThrowException(PhysicsViolation, "Cannot set the collision type of a WorldEntity with a parent");
291        else if (this->physicalBody_ && this->physicalBody_->isInWorld())
292            ThrowException(PhysicsViolation, "Warning: Cannot set the collision type at run time.");
293
294        // Check for type legality. Could be StaticEntity or MovableEntity
295        if (!this->isCollisionTypeLegal(type))
296            return; // exception gets issued anyway
297
298        // Check whether we have to create or destroy.
299        if (type != None && this->collisionType_ == None)
300        {
301            // Create new rigid body
302            btCollisionShape* temp = 0;
303            if (this->collisionShape_)
304                temp = this->collisionShape_->getCollisionShape();
305            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, temp, btVector3(0,0,0));
306            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
307            this->physicalBody_->setUserPointer(this);
308        }
309        else if (type == None && this->collisionType_ != None)
310        {
311            // Destroy rigid body
312            if (this->physicalBody_->isInWorld())
313                this->getScene()->getPhysicalWorld()->removeRigidBody(this->physicalBody_);
314            delete this->physicalBody_;
315            this->physicalBody_ = 0;
316            this->collisionType_ = None;
317            return;
318        }
319
320        // Change type
321        switch (type)
322        {
323        case Dynamic:
324            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
325            break;
326        case Kinematic:
327            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
328            break;
329        case Static:
330            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
331            break;
332        case None:
333            return; // this->collisionType_ was None too
334        }
335
336        // update our variable for faster checks
337        updateCollisionType();
338
339        // Mass non zero is a bad idea for kinematic and static objects
340        if ((type == Kinematic || type == Static) && this->mass_ != 0.0f)
341            this->setMass(0.0f);
342        // Mass zero is not such a good idea for dynamic objects
343        else if (type == Dynamic && this->mass_ == 0.0f)
344            this->setMass(1.0f);
345        else if (hasPhysics())
346            this->physicalBody_->setMassProps(this->mass_, btVector3(0,0,0));
347    }
348
349    void WorldEntity::updateCollisionType()
350    {
351        if (!this->physicalBody_)
352            this->collisionType_ = None;
353        else if (this->physicalBody_->isKinematicObject())
354            this->collisionType_ = Kinematic;
355        else if (this->physicalBody_->isStaticObject())
356            this->collisionType_ = Static;
357        else
358            this->collisionType_ = Dynamic;
359    }
360
361    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
362    {
363        std::string typeStrLower = getLowercase(typeStr);
364        CollisionType type;
365        if (typeStrLower == "dynamic")
366            type = Dynamic;
367        else if (typeStrLower == "static")
368            type = Static;
369        else if (typeStrLower == "kinematic")
370            type = Kinematic;
371        else if (typeStrLower == "none")
372            type = None;
373        else
374            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
375        this->setCollisionType(type);
376    }
377
378    std::string WorldEntity::getCollisionTypeStr() const
379    {
380        switch (this->getCollisionType())
381        {
382            case Dynamic:
383                return "dynamic";
384            case Kinematic:
385                return "kinematic";
386            case Static:
387                return "static";
388            case None:
389                return "none";
390            default:
391                assert(false);
392                return "";
393        }
394    }
395
396    //void WorldEntity::setCollisionRadius(float radius)
397    //{
398    //    if (!checkPhysics())
399    //        return;
400
401    //    // destroy old one first
402    //    btCollisionShape* oldShape = this->physicalBody_->getCollisionShape();
403    //    if (oldShape)
404    //        delete oldShape;
405
406    //    //if (this->getName() == "blubb")
407    //    //{
408    //    //    btCompoundShape* cShape = new btCompoundShape();
409    //    //    cShape->setLocalScaling(btVector3(1,1,1));
410    //    //    btTransform offset(btQuaternion(0, 0, 0), btVector3(0, 0, 0));
411    //    //    offset.setBasis(btMatrix3x3(3, 0, 0, 0, 3, 0, 0, 0, 3));
412    //    //    btSphereShape* sphere = new btSphereShape(radius);
413    //    //    sphere->setLocalScaling(btVector3(1,1,3));
414    //    //    cShape->addChildShape(offset, sphere);
415    //    //    this->physicalBody_->setCollisionShape(cShape);
416    //    //}
417    //    //else
418    //    this->physicalBody_->setCollisionShape(new btSphereShape(btScalar(radius)));
419    //}
420
421    //float WorldEntity::getCollisionRadius() const
422    //{
423    //    if (checkPhysics())
424    //    {
425    //        btSphereShape* sphere = dynamic_cast<btSphereShape*>(this->physicalBody_->getCollisionShape());
426    //        if (sphere)
427    //            return (float)sphere->getRadius();
428    //    }
429    //    return 0.0f;
430    //}
431
432    bool WorldEntity::checkPhysics() const
433    {
434        if (!this->physicalBody_)
435        {
436            assert(this->getCollisionType() == None);
437            COUT(2) << "WorldEntity was not fitted with physics, cannot set phyiscal property." << std::endl;
438            return false;
439        }
440        else
441            return true;
442    }
443}
Note: See TracBrowser for help on using the repository browser.