Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2297 was 2292, checked in by rgrieder, 16 years ago

Finally managed to work out some physics. According to my tests, collisions with simple spheres should work with dynamic/kinematic/static objects. There are currently only a limited number of XML parameters, but we're surely going to extend that. Furthermore there is some more thinking to be done concerning changes of btRigidBody properties when it's already added to the world.

  • Property svn:eol-style set to native
File size: 11.0 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
44#include "StaticEntity.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), network::Synchronisable(creator)
56    {
57        RegisterObject(WorldEntity);
58
59        assert(this->getScene());
60        assert(this->getScene()->getRootSceneNode());
61
62        this->node_ = this->getScene()->getRootSceneNode()->createChildSceneNode();
63
64        this->parent_ = 0;
65        this->parentID_ = (unsigned int)-1;
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
73        this->registerVariables();
74    }
75
76    WorldEntity::~WorldEntity()
77    {
78        if (this->isInitialized())
79        {
80            this->node_->detachAllObjects();
81            if (this->getScene()->getSceneManager())
82                this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
83           
84            // Physics is not guaranteed, so check first
85            if (this->physicalBody_)
86            {
87                if (this->physicalBody_->isInWorld())
88                    this->getScene()->getPhysicalWorld()->removeRigidBody(this->physicalBody_);
89                if (this->physicalBody_->getCollisionShape())
90                    delete this->physicalBody_->getCollisionShape();
91                delete this->physicalBody_;
92            }
93        }
94    }
95
96    void WorldEntity::XMLPort(Element& xmlelement, XMLPort::Mode mode)
97    {
98        SUPER(WorldEntity, XMLPort, xmlelement, mode);
99
100        XMLPortParamTemplate(WorldEntity, "position", setPosition, getPosition, xmlelement, mode, const Vector3&);
101        XMLPortParamTemplate(WorldEntity, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&);
102        XMLPortParamLoadOnly(WorldEntity, "lookat", lookAt_xmlport, xmlelement, mode);
103        XMLPortParamLoadOnly(WorldEntity, "direction", setDirection_xmlport, xmlelement, mode);
104        XMLPortParamLoadOnly(WorldEntity, "yaw", yaw_xmlport, xmlelement, mode);
105        XMLPortParamLoadOnly(WorldEntity, "pitch", pitch_xmlport, xmlelement, mode);
106        XMLPortParamLoadOnly(WorldEntity, "roll", roll_xmlport, xmlelement, mode);
107        XMLPortParamTemplate(WorldEntity, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&);
108        XMLPortParam(WorldEntity, "scale", setScale, getScale, xmlelement, mode);
109
110        XMLPortParam(WorldEntity, "collisionRadius", setCollisionRadius, getCollisionRadius, xmlelement, mode);
111        XMLPortParam(WorldEntity, "collisionType", setCollisionTypeStr, getCollisionTypeStr, xmlelement, mode);
112        XMLPortParam(WorldEntity, "mass", setMass, getMass, xmlelement, mode);
113
114        if (this->physicalBody_)
115            this->getScene()->getPhysicalWorld()->addRigidBody(this->physicalBody_);
116
117        XMLPortObject(WorldEntity, WorldEntity, "attached", attach, getAttachedObject, xmlelement, mode);
118    }
119
120    void WorldEntity::registerVariables()
121    {
122        REGISTERDATA(this->bActive_,  network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity));
123        REGISTERDATA(this->bVisible_, network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility));
124
125        REGISTERDATA(this->getScale3D().x, network::direction::toclient);
126        REGISTERDATA(this->getScale3D().y, network::direction::toclient);
127        REGISTERDATA(this->getScale3D().z, network::direction::toclient);
128
129        REGISTERDATA(this->parentID_, network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::updateParent));
130    }
131
132    void WorldEntity::updateParent()
133    {
134        WorldEntity* parent = dynamic_cast<WorldEntity*>(Synchronisable::getSynchronisable(this->parentID_));
135        if (parent)
136            this->attachToParent(parent);
137    }
138
139    void WorldEntity::attach(WorldEntity* object)
140    {
141        if (object->getParent())
142            object->detachFromParent();
143        else
144        {
145            Ogre::Node* parent = object->node_->getParent();
146            if (parent)
147                parent->removeChild(object->node_);
148        }
149
150        this->node_->addChild(object->node_);
151        this->children_.insert(object);
152        object->parent_ = this;
153        object->parentID_ = this->getObjectID();
154
155        // Do the physical connection if required
156        //this->attachPhysicalObject(object);
157    }
158
159    //void WorldEntity::attachPhysicalObject(WorldEntity* object)
160    //{
161    //    StaticEntity* staticObject = dynamic_cast<StaticEntity*>(object);
162    //    if (staticObject != 0 && this->hasPhysics())
163    //    {
164    //       btCompoundShape* compoundShape = dynamic_cast<btCompoundShape*>(this->physicalBody_->getCollisionShape());
165    //       if (compoundShape == 0)
166    //       {
167    //            // create a compound shape and add both
168    //            compoundShape = new btCompoundShape();
169    //            compoundShape->addChildShape(this->physicalBody_->getCollisionShape());
170    //            compoundShape->addChildShape(staticObject->getCollisionShape());
171    //            this->physicalBody_->setCollisionShape();
172    //       }
173    //       else
174    //       {
175    //           compoundShape -> addChildShape(staticObject->getCollisionShape());
176    //       }
177    //    }
178    //}
179
180    void WorldEntity::detach(WorldEntity* object)
181    {
182        this->node_->removeChild(object->node_);
183        this->children_.erase(object);
184        object->parent_ = 0;
185        object->parentID_ = (unsigned int)-1;
186
187//        this->getScene()->getRootSceneNode()->addChild(object->node_);
188    }
189
190    WorldEntity* WorldEntity::getAttachedObject(unsigned int index) const
191    {
192        unsigned int i = 0;
193        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
194        {
195            if (i == index)
196                return (*it);
197            ++i;
198        }
199        return 0;
200    }
201
202    void WorldEntity::createPhysicalBody()
203    {
204        // Note: The motion state will be configured in a derived class.
205        btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, 0, btVector3(0,0,0));
206        this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
207    }
208
209    float WorldEntity::getMass()
210    {
211        if (!this->physicalBody_)
212            return 0.0f;
213
214        return 1.0f/this->physicalBody_->getInvMass();
215    }
216
217    void WorldEntity::setMass(float mass)
218    {
219        if (!this->physicalBody_)
220            this->createPhysicalBody();
221
222        this->physicalBody_->setMassProps(mass, btVector3(0,0,0));
223    }
224
225    void WorldEntity::setCollisionType(WorldEntity::CollisionType type)
226    {
227        if (!this->physicalBody_)
228            this->createPhysicalBody();
229
230        switch (type)
231        {
232        case Dynamic:
233            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
234            break;
235        case Kinematic:
236            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
237            break;
238        case Static:
239            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
240            break;
241        }
242    }
243
244    WorldEntity::CollisionType WorldEntity::getCollisionType()
245    {
246        if (!this->physicalBody_)
247            ThrowException(Argument, "Cannot retrieve collision type of a non physical object.");
248
249        int flags = this->physicalBody_->getCollisionFlags();
250        if (flags & btCollisionObject::CF_STATIC_OBJECT)
251            return Static;
252        else if (flags & btCollisionObject::CF_KINEMATIC_OBJECT)
253            return Kinematic;
254        else
255            return Dynamic;
256    }
257
258    void WorldEntity::setCollisionTypeStr(const std::string& type)
259    {
260        std::string lower = getLowercase(type);
261        if (lower == "dynamic")
262            setCollisionType(Dynamic);
263        else if (lower == "static")
264            setCollisionType(Static);
265        else if (lower == "kinematic")
266            setCollisionType(Kinematic);
267        else
268            ThrowException(Argument, std::string("Trying to set an unknown collision type: '") + type + "'.");
269    }
270
271    std::string WorldEntity::getCollisionTypeStr()
272    {
273        switch (this->getCollisionType())
274        {
275        case Dynamic:
276            return "dynamic";
277        case Kinematic:
278            return "kinematic";
279        case Static:
280            return "static";
281        default:
282            ThrowException(Argument, "Encountered unknown collision Type.");
283        }
284    }
285
286    void WorldEntity::setCollisionRadius(float radius)
287    {
288        if (!this->physicalBody_)
289            createPhysicalBody();
290
291        // destroy old one first
292        btCollisionShape* oldShape = this->physicalBody_->getCollisionShape();
293        if (oldShape)
294            delete oldShape;
295
296        this->physicalBody_->setCollisionShape(new btSphereShape(btScalar(radius)));
297    }
298
299    float WorldEntity::getCollisionRadius()
300    {
301        if (this->physicalBody_)
302        {
303            btSphereShape* sphere = dynamic_cast<btSphereShape*>(this->physicalBody_->getCollisionShape());
304            if (sphere)
305                return (float)sphere->getRadius();
306        }
307        return 0.0f;
308    }
309}
Note: See TracBrowser for help on using the repository browser.