AnnGameObject.cpp
Go to the documentation of this file.
1 // This is an open source non-commercial project. Dear PVS-Studio, please check it.
2 // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3 
4 #include "AnnGameObject.hpp"
5 #include "AnnLogger.hpp"
6 #include "AnnGetter.hpp"
7 #include "AnnException.hpp"
8 
9 using namespace Annwvyn;
10 
12  sceneNode(nullptr),
13  model3D(nullptr),
14  currentAnimation(nullptr),
15  collisionShape(nullptr),
16  rigidBody(nullptr),
17  bodyMass(0),
18  audioSource(nullptr),
19  state(nullptr)
20 {
21 }
22 
24 {
25  for(auto script : scripts) script->unregisterAsListener();
26 
27  AnnDebug() << "Destructing game object " << getName() << " !";
28  //Clean OpenAL de-aloc
29  if(AnnGetAudioEngine())
30  AnnGetAudioEngine()->removeSource(audioSource);
31 
33  AnnGetPhysicsEngine()->removeRigidBody(rigidBody);
34 
35  if(rigidBody) delete rigidBody;
36  if(collisionShape)
37  {
38  if(collisionShape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
39  delete static_cast<btBvhTriangleMeshShape*>(collisionShape)->getMeshInterface();
40  delete collisionShape;
41  }
42  if(state) delete state;
43 
44  //Prevent dereferencing null pointer here. Parent can be something other than root scene node now.
45  if(sceneNode)
46  {
47  if(sceneNode->getParent())
48  sceneNode->getParent()->removeChild(sceneNode);
49  std::vector<Ogre::MovableObject*> attachedObject;
50  for(unsigned short i(0); i < sceneNode->numAttachedObjects(); ++i)
51  attachedObject.push_back(sceneNode->getAttachedObject(i));
52  sceneNode->detachAllObjects();
53  for(auto object : attachedObject)
54  AnnGetEngine()->getSceneManager()->destroyMovableObject(object);
55  AnnGetEngine()->getSceneManager()->destroySceneNode(sceneNode);
56  sceneNode = nullptr;
57  }
58 }
59 
60 void AnnGameObject::playSound(const std::string& path, bool loop, float volume) const
61 {
62  audioSource->changeSound(path);
63  audioSource->setLooping(loop);
64  audioSource->setVolume(volume);
65  audioSource->setPositon(getWorldPosition());
66  audioSource->play();
67 }
68 
70 {
71  audioSource->setPositon(getWorldPosition());
72 }
73 
75 {
76  for(auto script : scripts) script->update();
77 }
78 
79 void AnnGameObject::setPosition(float x, float y, float z)
80 {
81  setPosition(AnnVect3{ x, y, z });
82 }
83 
84 void AnnGameObject::translate(float x, float y, float z) const
85 {
86  //Ogre
87  sceneNode->translate(x, y, z);
88  //Bullet
89  if(rigidBody)
90  {
91  rigidBody->translate(btVector3(x, y, z));
92  rigidBody->activate();
93  }
94  //OpenAL
96 }
97 
99 {
100  if(rigidBody)
101  {
102  const auto currentPosition = sceneNode->getPosition();
103  rigidBody->translate(btVector3(pos.x - currentPosition.x,
104  pos.y - currentPosition.y,
105  pos.z - currentPosition.z));
106 
107  //Activate the body in the physics engine
108  rigidBody->activate();
109  }
110  //change OgrePosition
111  sceneNode->setPosition(pos);
112 
113  //change OpenAL Source Position
114  updateOpenAlPos();
115 }
116 
118 {
119  sceneNode->_setDerivedPosition(pos);
120  updateOpenAlPos();
121 }
122 
123 void AnnGameObject::setOrientation(float w, float x, float y, float z)
124 {
126 }
127 
129 {
130  //Ogre3D
131  sceneNode->setOrientation(static_cast<Ogre::Quaternion>(orient));
132 
133  //bullet
134  if(rigidBody)
135  {
136  auto t = rigidBody->getCenterOfMassTransform();
137  t.setRotation(orient.getBtQuaternion());
138  rigidBody->setCenterOfMassTransform(t);
139 
140  //activate the body
141  rigidBody->activate();
142  }
143 }
144 
146 {
147  sceneNode->_setDerivedOrientation(orient);
148 }
149 
150 void AnnGameObject::setScale(AnnVect3 scale, bool scaleMass) const
151 {
152  sceneNode->setScale(scale);
154  {
155  collisionShape->setLocalScaling(scale.getBtVector());
156 
157  auto world = AnnGetPhysicsEngine()->getWorld();
158  world->removeRigidBody(rigidBody);
159 
160  btVector3 inertia;
161  float scaleLenght;
162 
163  if(scaleMass)
164  scaleLenght = scale.length() / 3.0f;
165  else
166  scaleLenght = 1.0f;
167 
168  collisionShape->calculateLocalInertia(scaleLenght * bodyMass, inertia);
169  rigidBody->setMassProps(scaleLenght * bodyMass, inertia);
170 
171  world->addRigidBody(rigidBody, AnnPhysicsEngine::CollisionMasks::General, AnnPhysicsEngine::CollisionMasks::ColideWithAll);
172  rigidBody->activate();
173  }
174 }
175 
176 void AnnGameObject::setWorldOrientation(float w, float x, float y, float z) const
177 {
179 }
180 
181 void AnnGameObject::setScale(float x, float y, float z, bool mass) const
182 {
183  setScale(AnnVect3(x, y, z), mass);
184 }
185 
187 {
188  return sceneNode->getPosition();
189 }
190 
192 {
193  return sceneNode->getOrientation();
194 }
195 
197 {
198  return sceneNode->getScale();
199 }
200 
201 void AnnGameObject::setNode(Ogre::SceneNode* newNode)
202 {
203  sceneNode = newNode;
204 }
205 
206 void AnnGameObject::setupPhysics(float mass, phyShapeType type, bool colideWithPlayer)
207 {
208  //Some sanity checks
211  if(mass < 0) return;
212 
213  //Easy access to physics engine
214  auto physicsEngine = AnnGetPhysicsEngine();
215 
216  //Get the collision shape from the physics engine
217  collisionShape = physicsEngine->_getGameObjectShape(this, type);
218 
219  //Apply local scaling
220  AnnVect3 scale = getNode()->getScale();
221  collisionShape->setLocalScaling(scale.getBtVector());
222 
223  //Register the mass
224  bodyMass = mass;
225 
226  //Calculate inertia
227  btVector3 inertia{ 0, 0, 0 };
228  if(bodyMass > 0.0f)
229  collisionShape->calculateLocalInertia(bodyMass, inertia);
230 
231  //create rigidBody from shape
232  state = new BtOgre::RigidBodyState(sceneNode);
233  rigidBody = new btRigidBody(bodyMass, state, collisionShape, inertia);
234  rigidBody->setUserPointer(this);
235 
236  //Add body to the dynamics world while respecting collision masks settings
237  physicsEngine->getWorld()->addRigidBody(rigidBody,
238  AnnPhysicsEngine::CollisionMasks::General,
239  colideWithPlayer ? AnnPhysicsEngine::CollisionMasks::ColideWithAll : AnnPhysicsEngine::CollisionMasks::General);
240 }
241 
242 Ogre::SceneNode* AnnGameObject::getNode() const
243 {
244  return sceneNode;
245 }
246 
247 float AnnGameObject::getDistance(AnnGameObject* otherObject) const
248 {
249  return getWorldPosition().distance(otherObject->getWorldPosition());
250 }
251 
252 btRigidBody* AnnGameObject::getBody() const
253 {
254  return rigidBody;
255 }
256 
257 void AnnGameObject::setAnimation(const std::string& animationName)
258 {
259  //Check if the item has a skeleton
260  if(!getItem()->hasSkeleton())
261  {
262  AnnDebug() << "Attempting to set a skeleton animation on a skeleton-less object. (" << getName() << ") Check yo' programin' bro!";
263  return;
264  }
265 
266  //Attempt to get the animation
267  const auto selectedAnimation = getItem()->getSkeletonInstance()->getAnimation(animationName);
268  if(!selectedAnimation)
269  {
270  AnnDebug(Log::Important) << "Looks like " << getName() << " doesn't have an animation called " << animationName;
271  return;
272  }
273 
274  //If an animation was already playing, disable it
275  if(currentAnimation)
276  {
277  currentAnimation->setEnabled(false);
278  }
279 
280  //Set the current animation, but don't start playing it just yet.
281  currentAnimation = selectedAnimation;
282 }
283 
284 void AnnGameObject::playAnimation(bool play) const
285 {
286  if(currentAnimation) currentAnimation->setEnabled(play);
287 }
288 
289 void AnnGameObject::loopAnimation(bool loop) const
290 {
291  if(currentAnimation) currentAnimation->setLoop(loop);
292 }
293 
294 void AnnGameObject::addAnimationTime(double offset) const
295 {
296  if(currentAnimation) currentAnimation->addTime(float(offset));
297 }
298 
300 {
301  rigidBody->applyCentralImpulse(force.getBtVector());
302 }
303 
305 {
306  rigidBody->applyCentralForce(force.getBtVector());
307 }
308 
310 {
311  if(rigidBody)
312  rigidBody->setLinearVelocity(v.getBtVector());
313 }
314 
315 void AnnGameObject::setFrictionCoef(float coef) const
316 {
317  if(rigidBody)
318  rigidBody->setFriction(coef);
319 }
320 
322 {
323  getNode()->setVisible(true);
324 }
325 
327 {
328  getNode()->setVisible(false);
329 }
330 
332 {
333  return name;
334 }
335 
337 {
338  auto script = AnnGetScriptManager()->getBehaviorScript(scriptName, this);
339  if(script->isValid())
340  scripts.push_back(script);
341  script->registerAsListener();
342 }
343 
345 {
346  auto parentSceneNode = sceneNode->getParentSceneNode();
347 
348  if(reinterpret_cast<uint64_t>(parentSceneNode)
349  == reinterpret_cast<uint64_t>(AnnGetEngine()->getSceneManager()->getRootSceneNode()))
350  {
351  return false;
352  }
353 
354  if(parentSceneNode != nullptr)
355  return true;
356 
357  return false;
358 }
359 
361 {
362  return AnnGetGameObjectManager()->getFromNode(sceneNode->getParentSceneNode());
363 }
364 
366 {
367  //child->sceneNode has been detached from it's current parent(that was either a node or the root node)
368  child->sceneNode->getParentSceneNode()->removeChild(child->sceneNode);
369 
370  //Attach it to the node of this object.
371  sceneNode->addChild(child->sceneNode);
372 }
373 
375 {
376  sceneNode->getParentSceneNode()->removeChild(sceneNode);
377  AnnGetEngine()->getSceneManager()->getRootSceneNode()->addChild(sceneNode);
378 }
379 
381 {
382  return parentsHaveBody(this);
383 }
384 
386 {
387 #ifdef _DEBUG
388  if(sceneNode->isCachedTransformOutOfDate())
389  {
390  AnnDebug() << "cached transform was out of date when " << name << " wanted it's own world position";
391  return sceneNode->_getDerivedPositionUpdated();
392  }
393 #endif
394  return sceneNode->_getDerivedPosition();
395 }
396 
398 {
399 #ifdef _DEBUG
400  if(sceneNode->isCachedTransformOutOfDate())
401  {
402  AnnDebug() << "cached transofrm was out of date when " << name << " wanted it's own world orientaiton";
403  return sceneNode->_getDerivedOrientationUpdated();
404  }
405 #endif
406  return sceneNode->_getDerivedOrientation();
407 }
408 
410 {
411  if(!hasParent()) return false;
412  const auto addr = obj->getParent().get();
413  if(!addr) return false;
414  if(obj->getParent()->getBody()) return true;
415  return parentsHaveBody(addr);
416 }
417 
419 {
420  return childrenHaveBody(this);
421 }
422 
424 {
425  for(auto childNode : parentObj->sceneNode->getChildIterator())
426  {
427  const auto node = childNode;
428  const auto childSceneNode = dynamic_cast<Ogre::SceneNode*>(node);
429 
430  //Is an actual SceneNode
431  if(childSceneNode != nullptr)
432  {
433  auto obj = AnnGetGameObjectManager()->getFromNode(childSceneNode);
434  //found an object
435  if(obj != nullptr)
436  {
437  //Found a body
438  if(obj->getBody()) return true;
439 
440  //Do child recursion here.
441  return childrenHaveBody(obj.get());
442  }
443  }
444  }
445 
446  return false;
447 }
448 
449 void AnnGameObject::setWorldPosition(float x, float y, float z) const
450 {
451  setWorldPosition(AnnVect3{ x, y, z });
452 }
453 
454 void AnnGameObject::setItem(Ogre::Item* item)
455 {
456  model3D = item;
457 }
458 
459 Ogre::Item* AnnGameObject::getItem() const
460 {
461  return model3D;
462 }
void callUpdateOnScripts()
Call the update methods of all the script present in the scripts container.
void updateOpenAlPos() const
For engine : update OpenAL source position.
void applyForce(AnnVect3 force) const
BtOgre::RigidBodyState * state
RigidBodyState of this object.
void playAnimation(bool play=true) const
void translate(float x, float y, float z) const
AnnEngine * AnnGetEngine()
Get the current instance of AnnEngine.
Definition: AnnGetter.cpp:10
void attachScript(const std::string &scriptName)
AnnVect3 getPosition() override
Get Position.
AnnVect3 getScale() const
Get scale.
btQuaternion getBtQuaternion() const
get this quaternion as a bullet quaternion
std::string getName() const
Return the name of the object.
static bool childrenHaveBody(AnnGameObject *obj)
float bodyMass
Mass of the rigid body.
A 3D Vector.
Definition: AnnVect3.hpp:16
btRigidBody * rigidBody
Bullet rigid body.
std::vector< std::shared_ptr< AnnBehaviorScript > > scripts
list of script objects
AnnGameObject()
Class constructor.
std::shared_ptr< AnnGameObject > getParent() const
Get the parent Game Object.
Namespace containing the totality of Annwvyn components.
Definition: AnnGetter.cpp:8
btVector3 getBtVector() const
Return as bullet vector.
Definition: AnnVect3.cpp:44
Ogre::SceneNode * sceneNode
SceneNode. This also holds the position/orientation/scale of the object.
void setWorldPosition(AnnVect3 pos) const
An object that exist in the game. Graphically and Potentially Physically.
AnnGameObjectManagerPtr AnnGetGameObjectManager()
Get the game-object manager.
Definition: AnnGetter.cpp:22
phyShapeType
Definition: AnnTypes.h:43
void setupPhysics(float mass=0, phyShapeType type=staticShape, bool hasPlayerCollision=true)
Exception to throw when a physics enabled object will cause object coordinates reset.
bool checkForBodyInParent()
Recursively check if any parent has a body, if one is found, returns true.
btCollisionShape * collisionShape
Bullet shape.
T push_back(T... args)
void applyImpulse(AnnVect3 impulse) const
Create a ostream to the Ogre logger.
Ogre::SceneManager * getSceneManager() const
Get ogre scene manager.
Definition: AnnEngine.cpp:331
void playSound(const std::string &name, bool loop=false, float volume=1.0f) const
Ogre::SkeletonAnimation * currentAnimation
Currently selected animation.
bool hasParent() const
Return true if node is attached to the node owned by another AnnGameObject.
AnnVect3 getWorldPosition() const
Get the position in world.
std::shared_ptr< AnnAudioSource > audioSource
AnnAudioEngine audioSource;.
void detachFromParent() const
Make the node independent to any GameObject.
void setOrientation(float w, float x, float y, float z)
void attachChildObject(std::shared_ptr< AnnGameObject > child) const
AnnAudioEnginePtr AnnGetAudioEngine()
Get the audio engine.
Definition: AnnGetter.cpp:12
Represent a Quaternion.
Open an output stream to the engine log.
Definition: AnnLogger.hpp:24
std::string name
Name of the object.
AnnPhysicsEnginePtr AnnGetPhysicsEngine()
Get the physics engine.
Definition: AnnGetter.cpp:13
void loopAnimation(bool loop=true) const
Exception relating physics setup and parent/child objects.
void setWorldOrientation(AnnQuaternion orient) const
void addAnimationTime(double offsetTime) const
void setVisible() const
Make the object visible.
void setFrictionCoef(float coef) const
float getDistance(AnnGameObject *otherObject) const
void setLinearSpeed(AnnVect3 v) const
void setScale(float x, float y, float z, bool scaleMass=true) const
Game Object class.
void setAnimation(const std::string &name)
Ogre::Item * model3D
Entity.
AnnQuaternion getOrientation() override
Get Orientation.
bool parentsHaveBody(AnnGameObject *obj) const
void setPosition(float x, float y, float z)
void setInvisible() const
Make the object invisible.
virtual ~AnnGameObject()
Class Destructor. Virtual.
bool checkForBodyInChild()
Recursively check if any child has a body, if one is found, returns true.
AnnScriptManagerPtr AnnGetScriptManager()
Get the script manager.
Definition: AnnGetter.cpp:21
btRigidBody * getBody() const
Get Rigid rigidBody.
void setItem(Ogre::Item *item)
Ogre::Item * getItem() const
Get the item of this object.
AnnQuaternion getWorldOrientation() const
Get the world orientation.
void setNode(Ogre::SceneNode *node)
Ogre::SceneNode * getNode() const
Get Ogre Node.