Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/orxonox/worldentities/WorldEntity.h @ 10580

Last change on this file since 10580 was 10288, checked in by landauf, 9 years ago

added bullet settings for CCD (continuous collision detection) to WorldEntity. initially I thought we need this to avoid the tunneling effect of projectiles at low FPS, but now it turns out that this gets also fixed if projectiles use dynamic physics. I still add the new settings to WorldEntity because we may still need them for very fast objects.

  • Property svn:eol-style set to native
File size: 25.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 *      Reto Grieder (physics)
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30#ifndef _WorldEntity_H__
31#define _WorldEntity_H__
32
33#include "OrxonoxPrereqs.h"
34
35#ifdef ORXONOX_RELEASE
36#  include <OgreSceneNode.h>
37#endif
38#include <LinearMath/btMotionState.h>
39
40#include "util/Math.h"
41#include "util/OgreForwardRefs.h"
42#include "core/BaseObject.h"
43#include "network/synchronisable/Synchronisable.h"
44
45namespace orxonox
46{
47    /**
48    @brief
49        The WorldEntity represents everything that can be put in a Scene at a certain location.
50
51        It is supposed to be the base class of everything you would call an 'object' in a Scene.
52        The class itself is abstract which means you cannot use it directly. You may use StaticEntity
53        as the simplest derivative or (derived from MobileEntity) MovableEntity and ControllableEntity
54        as more advanced ones.
55
56        The basic task of the WorldEntity is provide a location, a direction and a scaling and the possibility
57        to create an entire hierarchy of derived objects.
58        It is also the basis for the physics interface to the Bullet physics engine.
59        Every WorldEntity can have a specific collision type: @see CollisionType
60        This would then imply that every scene object could have any collision type. To limit this, you can always
61        override this->isCollisionTypeLegal(CollisionType). Return false if the collision type is not supported
62        for a specific object.
63        There is also support for attaching WorldEntities with physics to each other. Currently, the collision shape
64        of both objects simply get merged into one larger shape (for static collision type).
65        The physical body that is internally stored and administrated has the following supported properties:
66        - Restitution, angular factor, linear damping, angular damping, friction, mass and collision shape.
67        You can get more information at the corresponding set function.
68
69        Collision shapes: These are controlled by the internal WorldEntityCollisionShape. @see WorldEntityCollisionShape.
70    */
71    class _OrxonoxExport WorldEntity : public BaseObject, public Synchronisable, public btMotionState
72    {
73        friend class Scene;
74
75        public:
76            // Define our own transform space enum to avoid Ogre includes here
77            /**
78            @brief
79                Enumeration denoting the spaces which a transform can be relative to.
80            */
81            enum TransformSpace
82            {
83                //! Transform is relative to the local space
84                Local,
85                //! Transform is relative to the space of the parent node
86                Parent,
87                //! Transform is relative to world space
88                World
89            };
90
91        public:
92            WorldEntity(Context* context);
93            virtual ~WorldEntity();
94
95            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
96
97            inline const Ogre::SceneNode* getNode() const
98                { return this->node_; }
99
100            static const Vector3 FRONT;
101            static const Vector3 BACK;
102            static const Vector3 LEFT;
103            static const Vector3 RIGHT;
104            static const Vector3 DOWN;
105            static const Vector3 UP;
106
107            virtual void changedActivity(void);
108            virtual void changedVisibility(void);
109
110            virtual void setPosition(const Vector3& position) = 0;
111            inline void setPosition(float x, float y, float z)
112                { this->setPosition(Vector3(x, y, z)); }
113            const Vector3& getPosition() const;
114            const Vector3& getWorldPosition() const;
115
116            void translate(const Vector3& distance, TransformSpace relativeTo = WorldEntity::Parent);
117            inline void translate(float x, float y, float z, TransformSpace relativeTo = WorldEntity::Parent)
118                { this->translate(Vector3(x, y, z), relativeTo); }
119
120            virtual inline const Vector3& getVelocity() const
121                { return Vector3::ZERO; }
122
123            virtual void setOrientation(const Quaternion& orientation) = 0;
124            inline void setOrientation(float w, float x, float y, float z)
125                { this->setOrientation(Quaternion(w, x, y, z)); }
126            inline void setOrientation(const Vector3& axis, const Radian& angle)
127                { this->setOrientation(Quaternion(angle, axis)); }
128            inline void setOrientation(const Vector3& axis, const Degree& angle)
129                { this->setOrientation(Quaternion(angle, axis)); }
130            const Quaternion& getOrientation() const;
131            const Quaternion& getWorldOrientation() const;
132
133            void rotate(const Quaternion& rotation, TransformSpace relativeTo = WorldEntity::Local);
134            inline void rotate(const Vector3& axis, const Degree& angle, TransformSpace relativeTo = WorldEntity::Local)
135                { this->rotate(Quaternion(angle, axis), relativeTo); }
136
137            inline void yaw(const Degree& angle, TransformSpace relativeTo = WorldEntity::Local)
138                { this->rotate(Quaternion(angle, Vector3::UNIT_Y), relativeTo); }
139            inline void pitch(const Degree& angle, TransformSpace relativeTo = WorldEntity::Local)
140                { this->rotate(Quaternion(angle, Vector3::UNIT_X), relativeTo); }
141            inline void roll(const Degree& angle, TransformSpace relativeTo = WorldEntity::Local)
142                { this->rotate(Quaternion(angle, Vector3::UNIT_Z), relativeTo); }
143
144            void lookAt(const Vector3& target, TransformSpace relativeTo = WorldEntity::Parent, const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z);
145            void setDirection(const Vector3& direction, TransformSpace relativeTo = WorldEntity::Local, const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z);
146            inline void setDirection(float x, float y, float z, TransformSpace relativeTo = WorldEntity::Local, const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z)
147                { this->setDirection(Vector3(x, y, z), relativeTo, localDirectionVector); }
148
149            virtual void setScale3D(const Vector3& scale);
150            inline void setScale3D(float x, float y, float z)
151                { this->setScale3D(Vector3(x, y, z)); }
152            const Vector3& getScale3D() const;
153            const Vector3& getWorldScale3D() const;
154
155            inline void setScale(float scale)
156                { this->setScale3D(scale, scale, scale); }
157            inline float getScale() const
158                { Vector3 scale = this->getScale3D(); return (scale.x == scale.y && scale.x == scale.z) ? scale.x : 1; }
159            float getWorldScale() const;
160
161            inline void scale3D(const Vector3& scale)
162                { this->setScale3D(this->getScale3D() * scale); }
163            inline void scale3D(float x, float y, float z)
164                { this->scale3D(Vector3(x, y, z)); }
165            inline void scale(float scale)
166                { this->scale3D(scale, scale, scale); }
167
168            virtual void changedScale() {}
169
170            void attach(WorldEntity* object);
171            void detach(WorldEntity* object);
172            WorldEntity* getAttachedObject(unsigned int index);
173            inline const std::set<WorldEntity*>& getAttachedObjects() const
174                { return this->children_; }
175
176            void attachOgreObject(Ogre::MovableObject*  object);
177            void attachOgreObject(Ogre::BillboardSet*   object);
178            void attachOgreObject(Ogre::Camera*         object);
179            void attachOgreObject(Ogre::Entity*         object);
180            void attachOgreObject(Ogre::ParticleSystem* object);
181
182            void detachOgreObject(Ogre::MovableObject*  object);
183            void detachOgreObject(Ogre::BillboardSet*   object);
184            void detachOgreObject(Ogre::Camera*         object);
185            void detachOgreObject(Ogre::Entity*         object);
186            void detachOgreObject(Ogre::ParticleSystem* object);
187
188            Ogre::MovableObject* detachOgreObject(const Ogre::String& name);
189
190            inline void attachToParent(WorldEntity* parent)
191                { parent->attach(this); }
192            inline void detachFromParent()
193                { if (this->parent_) { this->parent_->detach(this); } }
194            inline WorldEntity* getParent() const
195                { return this->parent_; }
196
197            void attachNode(Ogre::SceneNode* node);
198            void detachNode(Ogre::SceneNode* node);
199            void attachToNode(Ogre::SceneNode* node);
200            void detachFromNode(Ogre::SceneNode* node);
201
202            inline void setDeleteWithParent(bool value)
203                { this->bDeleteWithParent_ = value; }
204            inline bool getDeleteWithParent() const
205                { return this->bDeleteWithParent_; }
206
207            void notifyChildPropsChanged();
208
209        protected:
210            virtual void parentChanged() {}
211
212            Ogre::SceneNode* node_;
213
214        private:
215            void registerVariables();
216
217            inline void lookAt_xmlport(const Vector3& target)
218                { this->lookAt(target); }
219            inline void setDirection_xmlport(const Vector3& direction)
220                { this->setDirection(direction); }
221            inline void yaw_xmlport(const Degree& angle)
222                { this->yaw(angle); }
223            inline void pitch_xmlport(const Degree& angle)
224                { this->pitch(angle); }
225            inline void roll_xmlport(const Degree& angle)
226                { this->roll(angle); }
227
228            // network callbacks
229            void networkcallback_parentChanged();
230            inline void scaleChanged()
231                { this->setScale3D(this->getScale3D()); }
232
233            WorldEntity* parent_;
234            unsigned int parentID_;
235            std::set<WorldEntity*> children_;
236            bool bDeleteWithParent_;
237
238            bool bActiveMem_;
239            bool bVisibleMem_;
240
241
242        /////////////
243        // Physics //
244        /////////////
245
246        public:
247            /**
248            @brief
249                Denotes the possible types of physical objects in a Scene.
250
251                Dynamic:   The object is influenced by its physical environment, like for instance little ball.
252                Kinematic: The object can only influence other dynamic objects. It's movement is coordinated by your own saying.
253                Static:    Like kinematic but the object is not allowed to move during the simulation.
254                None:      The object has no physics at all.
255            */
256            enum CollisionType
257            {
258                Dynamic,
259                Kinematic,
260                Static,
261                None
262            };
263
264            //! Tells whether the object has any connection to the Bullet physics engine. If hasPhysics() is false, the object may still have a velocity.
265            bool hasPhysics()       const { return getCollisionType() != None     ; }
266            //! @see CollisionType
267            bool isStatic()         const { return getCollisionType() == Static   ; }
268            //! @see CollisionType
269            bool isKinematic()      const { return getCollisionType() == Kinematic; }
270            //! @see CollisionType
271            bool isDynamic()        const { return getCollisionType() == Dynamic  ; }
272            //! Tells whether physics has been activated (you can temporarily deactivate it)
273            bool isPhysicsActive()  const { return this->bPhysicsActive_; }
274            bool addedToPhysicalWorld() const;
275
276            void activatePhysics();
277            void deactivatePhysics();
278
279            //! Returns the CollisionType. @see CollisionType.
280            inline CollisionType getCollisionType() const
281                { return this->collisionType_; }
282            void setCollisionType(CollisionType type);
283
284            void setCollisionTypeStr(const std::string& type);
285            std::string getCollisionTypeStr() const;
286
287            //! Sets the mass of this object. Note that the total mass may be influenced by attached objects!
288            inline void setMass(float mass)
289                { this->mass_ = mass; recalculateMassProps(); }
290            //! Returns the mass of this object without its children.
291            inline float getMass() const
292                { return this->mass_; }
293
294            //! Returns the total mass of this object with all its attached children.
295            inline float getTotalMass() const
296                { return this->mass_ + this->childrenMass_; }
297
298            /**
299            @brief
300                Returns the diagonal elements of the inertia tensor when calculated in local coordinates.
301            @note
302                The local inertia tensor cannot be set, but is calculated by Bullet according to the collisionShape.
303                With compound collision shapes, an approximation is used.
304            */
305            inline const btVector3& getLocalInertia() const
306                { return this->localInertia_; }
307
308            /**
309            @brief
310                Sets how much reaction is applied in a collision.
311
312                Consider two equal spheres colliding with equal velocities:
313                Restitution 1 means that both spheres simply reverse their velocity (no loss of energy)
314                Restitution 0 means that both spheres will immediately stop moving
315                (maximum loss of energy without violating of the preservation of momentum)
316            */
317            inline void setRestitution(float restitution)
318                { this->restitution_ = restitution; internalSetPhysicsProps(); }
319            //! Returns the restitution parameter. @see setRestitution.
320            inline float getRestitution() const
321                { return this->restitution_; }
322
323            /**
324            @brief
325                Sets an artificial parameter that tells how much torque is applied when you apply a non-central force.
326
327                Normally the angular factor is 1, which means it's physically 'correct'. However if you have a player
328                character that should not rotate when hit sideways, you can set the angular factor to 0.
329            */
330            inline void setAngularFactor(float angularFactor)
331                { this->angularFactor_ = angularFactor; internalSetPhysicsProps(); }
332            //! Returns the angular factor. @see setAngularFactor.
333            inline float getAngularFactor() const
334                { return this->angularFactor_; }
335
336            //! Applies a mass independent damping. Velocities will simply diminish exponentially.
337            inline void setLinearDamping(float linearDamping)
338                { this->linearDamping_ = linearDamping; internalSetPhysicsProps(); }
339            //! Returns the linear damping. @see setLinearDamping.
340            inline float getLinearDamping() const
341                { return this->linearDamping_; }
342
343            //! Applies a tensor independent rotation damping. Angular velocities will simply diminish exponentially.
344            inline void setAngularDamping(float angularDamping)
345                { this->angularDamping_ = angularDamping; internalSetPhysicsProps(); }
346            //! Returns the angular damping. @see setAngularDamping.
347            inline float getAngularDamping() const
348                { return this->angularDamping_; }
349
350            //! Applies friction to the object. Friction occurs when two objects collide.
351            inline void setFriction(float friction)
352                { this->friction_ = friction; internalSetPhysicsProps(); }
353            //! Returns the amount of friction applied to the object.
354            inline float getFriction() const
355                { return this->friction_; }
356
357            /**
358             * Sets the motion threshold for continuous collision detection (CCD). This should be activated if an object moves further in one tick than its own
359             * size. This means that in one tick the object may be in front of a wall and in the next tick it will be behind the wall without ever triggering a
360             * collision. CCD ensures that collisions are still detected. By default it is deactivated (threshold = 0) which is fine for slow or static
361             * objects, but it should be set to a real value for fast moving objects (e.g. projectiles).
362             *
363             * A good value for the threshold is (diameter^2).
364             *
365             * @param ccdMotionThreshold CCD is enabled if the squared velocity of the object is > ccdMotionThreshold (default 0.0). 0.0 means deactivated.
366             */
367            inline void setCcdMotionThreshold(float ccdMotionThreshold)
368                { this->ccdMotionThreshold_ = ccdMotionThreshold; internalSetPhysicsProps(); }
369            //! Returns the currently used motion threshold for CCD (0 means CCD is deactivated).
370            inline float getCcdMotionThreshold() const
371                { return this->ccdMotionThreshold_; }
372
373            /**
374             * Sets the radius of the sphere which is used for continuous collision detection (CCD). The sphere should be embedded inside the objects collision
375             * shape, preferably smaller. @see setCcdMotionThreshold for more information about CCD.
376             *
377             * A good value for the radius is (diameter/5).
378             *
379             * @param ccdSweptSphereRadius The diameter of the sphere which is used for CCD (default 0.0).
380             */
381            inline void setCcdSweptSphereRadius(float ccdSweptSphereRadius)
382                { this->ccdSweptSphereRadius_ = ccdSweptSphereRadius; internalSetPhysicsProps(); }
383            //! Returns the currently used radius of the sphere for CCD.
384            inline float getCcdSweptSphereRadius() const
385                { return this->ccdSweptSphereRadius_; }
386
387            void attachCollisionShape(CollisionShape* shape);
388            void detachCollisionShape(CollisionShape* shape);
389            CollisionShape* getAttachedCollisionShape(unsigned int index);
390
391            void notifyCollisionShapeChanged();
392            void notifyChildMassChanged();
393
394            /**
395            @brief
396                Virtual function that gets called when this object collides with another.
397            @param otherObject
398                The object this one has collided into.
399            @param contactPoint
400                Contact point provided by Bullet. Holds more information and can me modified. See return value.
401            @return
402                Returning false means that no modification to the contactPoint has been made. Return true otherwise!
403            @note
404                Condition is that enableCollisionCallback() was called.
405            */
406            virtual inline bool collidesAgainst(WorldEntity* otherObject, const btCollisionShape* ownCollisionShape, btManifoldPoint& contactPoint)
407                { return false; } /* With false, Bullet assumes no modification to the collision objects. */
408
409            //! Enables the collidesAgainst(.) function. The object doesn't respond to collision otherwise!
410            inline void enableCollisionCallback()
411                { this->bCollisionCallbackActive_ = true; this->collisionCallbackActivityChanged(); }
412            //! Disables the collidesAgainst(.) function. @see enableCollisionCallback()
413            inline void disableCollisionCallback()
414                { this->bCollisionCallbackActive_ = false; this->collisionCallbackActivityChanged(); }
415            //! Tells whether there could be a collision callback via collidesAgainst(.)
416            inline bool isCollisionCallbackActive() const
417                { return this->bCollisionCallbackActive_; }
418
419            //! Enables or disables collision response (default is of course on)
420            inline void setCollisionResponse(bool value)
421                { this->bCollisionResponseActive_ = value; this->collisionResponseActivityChanged(); }
422            //! Tells whether there could be a collision response
423            inline bool hasCollisionResponse()
424                { return this->bCollisionResponseActive_; }
425
426        protected:
427            /**
428            @brief
429                Function checks whether the requested collision type is legal to this object.
430
431                You can override this function in a derived class to constrain the collision to e.g. None or Dynamic.
432                A projectile may not prove very useful if there is no physical body. Simply set the CollisionType
433                in its constructor and override this method. But be careful that a derived class's virtual functions
434                don't yet exist in the constructor if a base class.
435            */
436            virtual bool isCollisionTypeLegal(CollisionType type) const = 0;
437
438            btRigidBody*  physicalBody_; //!< Bullet rigid body. Everything physical is applied to this instance.
439
440        private:
441            void recalculateMassProps();
442            void internalSetPhysicsProps();
443
444            bool notifyBeingAttached(WorldEntity* newParent);
445            void notifyDetached();
446
447            // network callbacks
448            void collisionTypeChanged();
449            void physicsActivityChanged();
450            void collisionCallbackActivityChanged();
451            void collisionResponseActivityChanged();
452            //! Network callback workaround to call a function when the value changes.
453            inline void massChanged()
454                { this->setMass(this->mass_); }
455            //! Network callback workaround to call a function when the value changes.
456            inline void restitutionChanged()
457                { this->setRestitution(this->restitution_); }
458            //! Network callback workaround to call a function when the value changes.
459            inline void angularFactorChanged()
460                { this->setAngularFactor(this->angularFactor_); }
461            //! Network callback workaround to call a function when the value changes.
462            inline void linearDampingChanged()
463                { this->setLinearDamping(this->linearDamping_); }
464            //! Network callback workaround to call a function when the value changes.
465            inline void angularDampingChanged()
466                { this->setAngularDamping(this->angularDamping_); }
467            //! Network callback workaround to call a function when the value changes.
468            inline void frictionChanged()
469                { this->setFriction(this->friction_); }
470            //! Network callback workaround to call a function when the value changes.
471            inline void ccdMotionThresholdChanged()
472                { this->setCcdMotionThreshold(this->ccdMotionThreshold_); }
473            //! Network callback workaround to call a function when the value changes.
474            inline void ccdSweptSphereRadiusChanged()
475                { this->setCcdSweptSphereRadius(this->ccdSweptSphereRadius_); }
476
477            CollisionType                collisionType_;                 //!< @see setCollisionType
478            CollisionType                collisionTypeSynchronised_;     //!< Network synchronised variable for collisionType_
479            bool                         bPhysicsActive_;                //!< @see isPhysicsActive
480            bool                         bPhysicsActiveSynchronised_;    //!< Network synchronised variable for bPhysicsActive_
481            //! When attaching objects hierarchically this variable tells this object (as child) whether physics was activated before attaching (because the deactivate physics while being attached).
482            bool                         bPhysicsActiveBeforeAttaching_;
483            WorldEntityCollisionShape*   collisionShape_;                //!< Attached collision shapes go here
484            btScalar                     mass_;                          //!< @see setMass
485            btVector3                    localInertia_;                  //!< @see getLocalInertia
486            btScalar                     restitution_;                   //!< @see setRestitution
487            btScalar                     angularFactor_;                 //!< @see setAngularFactor
488            btScalar                     linearDamping_;                 //!< @see setLinearDamping
489            btScalar                     angularDamping_;                //!< @see setAngularDamping
490            btScalar                     friction_;                      //!< @see setFriction
491            btScalar                     childrenMass_;                  //!< Sum of all the children's masses
492            btScalar                     ccdMotionThreshold_;            //!< @see setCcdMotionThreshold
493            btScalar                     ccdSweptSphereRadius_;          //!< @see setCcdSweptSphereRadius
494            bool                         bCollisionCallbackActive_;      //!< @see enableCollisionCallback
495            bool                         bCollisionResponseActive_;      //!< Tells whether the object should respond to collisions
496    };
497
498    // Inline heavily used functions for release builds. In debug, we better avoid including OgreSceneNode here.
499#ifdef ORXONOX_RELEASE
500    inline const Vector3& WorldEntity::getPosition() const
501        { return this->node_->getPosition(); }
502    inline const Quaternion& WorldEntity::getOrientation() const
503        { return this->node_->getOrientation(); }
504    inline const Vector3& WorldEntity::getScale3D() const
505        { return this->node_->getScale(); }
506#endif
507
508    SUPER_FUNCTION(5, WorldEntity, changedScale, false);
509}
510
511#endif /* _WorldEntity_H__ */
Note: See TracBrowser for help on using the repository browser.