Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Clarified use of different physical bodies. The "collisionType" XML attribute of WE specifies the following:
"none": There is not physical body at all. Physics disabled.
"static": It is a StaticEntity with physics. Any other derived class of WE issues an exception by choosing this collision type.
"kinematic" or "dynamic": MovableEntity with physics. StaticEntity issues an exception when choosing one of these two.

Added two new Exceptions: ParseError and PhysicsViolation.

  • Property svn:eol-style set to native
File size: 12.6 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()
195    {
196        if (!checkPhysics())
197            return 0.0f;
198
199        return 1.0f/this->physicalBody_->getInvMass();
200    }
201
202    void WorldEntity::setMass(float mass)
203    {
204        if (!checkPhysics())
205            return;
206        else if (this->physicalBody_->isInWorld())
207        {
208            CCOUT(2) << "Cannot set the physical mass at run time." << std::endl;
209            assert(false);
210        }
211        else
212        {
213            this->physicalBody_->setMassProps(mass, btVector3(0,0,0));
214            updateCollisionType();
215        }
216    }
217
218    void WorldEntity::setCollisionType(CollisionType type)
219    {
220        // Check first whether we have to create or destroy.
221        if (type != None && this->collisionType_ == None)
222        {
223            // Create new rigid body
224            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, 0, btVector3(0,0,0));
225            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
226            this->physicalBody_->setUserPointer(this);
227
228            // Adjust parameters according to the node
229            btTransform nodeTransform;
230            //this->
231        }
232        else if (type == None && this->collisionType_ != None)
233        {
234            // Destroy rigid body
235            if (this->physicalBody_->isInWorld())
236                this->getScene()->getPhysicalWorld()->removeRigidBody(this->physicalBody_);
237            if (this->physicalBody_->getCollisionShape())
238                delete this->physicalBody_->getCollisionShape();
239            delete this->physicalBody_;
240            this->physicalBody_ = 0;
241            this->collisionType_ = None;
242            return;
243        }
244
245        // Check for type legality. Could be StaticEntity or MovableEntity
246        if (!this->isCollisionTypeLegal(type))
247            return; // exception gets issued anyway
248
249        // Change type
250        switch (type)
251        {
252        case Dynamic:
253            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT));
254            break;
255        case Kinematic:
256            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
257            break;
258        case Static:
259            this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
260            break;
261        case None:
262            return; // this->collisionType_ was None too
263        }
264
265        // Mass non zero is a bad idea for kinematic and static objects
266        if ((type == Kinematic || type == Static) && getMass() != 0.0f)
267            this->setMass(0.0f);
268        // Mass zero is not such a good idea for dynamic objects
269        else if (type == Dynamic && getMass() == 0.0f)
270            this->setMass(1.0f);
271
272        // finally update our variable for faster checks
273        updateCollisionType();
274    }
275
276    void WorldEntity::updateCollisionType()
277    {
278        if (!this->physicalBody_)
279            this->collisionType_ = None;
280        else if (this->physicalBody_->isKinematicObject())
281            this->collisionType_ = Kinematic;
282        else if (this->physicalBody_->isStaticObject())
283            this->collisionType_ = Static;
284        else
285            this->collisionType_ = Dynamic;
286    }
287
288    void WorldEntity::setCollisionTypeStr(const std::string& typeStr)
289    {
290        std::string typeStrLower = getLowercase(typeStr);
291        CollisionType type;
292        if (typeStrLower == "dynamic")
293            type = Dynamic;
294        else if (typeStrLower == "static")
295            type = Static;
296        else if (typeStrLower == "kinematic")
297            type = Kinematic;
298        else if (typeStrLower == "none")
299            type = None;
300        else
301            ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'.");
302        this->setCollisionType(type);
303    }
304
305    std::string WorldEntity::getCollisionTypeStr()
306    {
307        switch (this->getCollisionType())
308        {
309            case Dynamic:
310                return "dynamic";
311            case Kinematic:
312                return "kinematic";
313            case Static:
314                return "static";
315            case None:
316                return "none";
317            default:
318                assert(false);
319                return "";
320        }
321    }
322
323    void WorldEntity::setCollisionRadius(float radius)
324    {
325        if (!checkPhysics())
326            return;
327
328        // destroy old one first
329        btCollisionShape* oldShape = this->physicalBody_->getCollisionShape();
330        if (oldShape)
331            delete oldShape;
332
333        this->physicalBody_->setCollisionShape(new btSphereShape(btScalar(radius)));
334    }
335
336    float WorldEntity::getCollisionRadius()
337    {
338        if (checkPhysics())
339        {
340            btSphereShape* sphere = dynamic_cast<btSphereShape*>(this->physicalBody_->getCollisionShape());
341            if (sphere)
342                return (float)sphere->getRadius();
343        }
344        return 0.0f;
345    }
346
347    bool WorldEntity::checkPhysics()
348    {
349        if (!this->physicalBody_)
350        {
351            assert(this->getCollisionType() == None);
352            COUT(2) << "WorldEntity was not fitted with physics, cannot set phyiscal property." << std::endl;
353            return false;
354        }
355        else
356            return true;
357    }
358}
Note: See TracBrowser for help on using the repository browser.