Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ScriptableController_FS18/src/orxonox/worldentities/WorldEntity.h @ 12006

Last change on this file since 12006 was 11855, checked in by adamc, 7 years ago

merged HS17 into FS18

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