CmGameObject.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. #include "CmGameObject.h"
  2. #include "CmComponent.h"
  3. #include "CmSceneManager.h"
  4. #include "CmException.h"
  5. #include "CmDebug.h"
  6. namespace CamelotEngine
  7. {
  8. GameObject::GameObject(const String& name)
  9. :mName(name), mPosition(Vector3::ZERO), mRotation(Quaternion::IDENTITY), mScale(Vector3::UNIT_SCALE),
  10. mWorldPosition(Vector3::ZERO), mWorldRotation(Quaternion::IDENTITY), mWorldScale(Vector3::UNIT_SCALE),
  11. mCachedLocalTfrm(Matrix4::IDENTITY), mIsCachedLocalTfrmUpToDate(false),
  12. mCachedWorldTfrm(Matrix4::IDENTITY), mIsCachedWorldTfrmUpToDate(false),
  13. mCustomWorldTfrm(Matrix4::IDENTITY), mIsCustomTfrmModeActive(false),
  14. mIsDestroyed(false)
  15. { }
  16. GameObject::~GameObject()
  17. {
  18. if(!mIsDestroyed)
  19. destroy();
  20. }
  21. GameObjectPtr GameObject::create(const String& name)
  22. {
  23. GameObjectPtr newObject = createInternal(name);
  24. gSceneManager().registerNewGO(newObject);
  25. return newObject;
  26. }
  27. GameObjectPtr GameObject::createInternal(const String& name)
  28. {
  29. GameObjectPtr newObject = GameObjectPtr(new GameObject(name));
  30. newObject->mThis = newObject;
  31. return newObject;
  32. }
  33. void GameObject::destroy()
  34. {
  35. mIsDestroyed = true;
  36. for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
  37. (*iter)->destroy();
  38. mChildren.clear();
  39. for(auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
  40. (*iter)->destroy();
  41. mComponents.clear();
  42. // Parent is our owner, so when his reference to us is removed, delete might be called.
  43. // So make sure this is the last thing we do.
  44. if(!mParent.expired())
  45. {
  46. GameObjectPtr parentPtr = mParent.lock();
  47. if(!parentPtr->isDestroyed())
  48. parentPtr->removeChild(mThis.lock());
  49. }
  50. }
  51. /************************************************************************/
  52. /* Transform */
  53. /************************************************************************/
  54. void GameObject::setPosition(const Vector3& position)
  55. {
  56. mPosition = position;
  57. markTfrmDirty();
  58. }
  59. void GameObject::setRotation(const Quaternion& rotation)
  60. {
  61. mRotation = rotation;
  62. markTfrmDirty();
  63. }
  64. void GameObject::setScale(const Vector3& scale)
  65. {
  66. mScale = scale;
  67. markTfrmDirty();
  68. }
  69. const Vector3& GameObject::getWorldPosition() const
  70. {
  71. if(!mIsCachedWorldTfrmUpToDate)
  72. updateWorldTfrm();
  73. return mWorldPosition;
  74. }
  75. const Quaternion& GameObject::getWorldRotation() const
  76. {
  77. if(!mIsCachedWorldTfrmUpToDate)
  78. updateWorldTfrm();
  79. return mWorldRotation;
  80. }
  81. const Vector3& GameObject::getWorldScale() const
  82. {
  83. if(!mIsCachedWorldTfrmUpToDate)
  84. updateWorldTfrm();
  85. return mWorldScale;
  86. }
  87. void GameObject::lookAt(const Vector3& location, const Vector3& up)
  88. {
  89. Vector3 forward = location - mPosition;
  90. forward.normalise();
  91. Vector3 upCopy = up;
  92. upCopy.normalise();
  93. Vector3 right = forward.crossProduct(up);
  94. right.normalise();
  95. Quaternion newRotation;
  96. newRotation.FromAxes(right, upCopy, forward);
  97. setRotation(newRotation);
  98. }
  99. const Matrix4& GameObject::getWorldTfrm() const
  100. {
  101. if(!mIsCachedWorldTfrmUpToDate)
  102. updateWorldTfrm();
  103. return mCachedWorldTfrm;
  104. }
  105. const Matrix4& GameObject::getLocalTfrm() const
  106. {
  107. if(!mIsCachedLocalTfrmUpToDate)
  108. updateLocalTfrm();
  109. return mCachedLocalTfrm;
  110. }
  111. void GameObject::move(const Vector3& vec)
  112. {
  113. setPosition(mPosition + vec);
  114. }
  115. void GameObject::moveRelative(const Vector3& vec)
  116. {
  117. // Transform the axes of the relative vector by camera's local axes
  118. Vector3 trans = mRotation * vec;
  119. setPosition(mPosition + trans);
  120. }
  121. void GameObject::rotate(const Vector3& axis, const Radian& angle)
  122. {
  123. Quaternion q;
  124. q.FromAngleAxis(angle,axis);
  125. rotate(q);
  126. }
  127. void GameObject::rotate(const Quaternion& q)
  128. {
  129. // Note the order of the mult, i.e. q comes after
  130. // Normalize the quat to avoid cumulative problems with precision
  131. Quaternion qnorm = q;
  132. qnorm.normalise();
  133. setRotation(qnorm * mRotation);
  134. }
  135. void GameObject::roll(const Radian& angle)
  136. {
  137. // Rotate around local Z axis
  138. Vector3 zAxis = mRotation * Vector3::UNIT_Z;
  139. rotate(zAxis, angle);
  140. }
  141. void GameObject::yaw(const Radian& angle)
  142. {
  143. Vector3 yAxis = mRotation * Vector3::UNIT_Y;
  144. rotate(yAxis, angle);
  145. }
  146. void GameObject::pitch(const Radian& angle)
  147. {
  148. // Rotate around local X axis
  149. Vector3 xAxis = mRotation * Vector3::UNIT_X;
  150. rotate(xAxis, angle);
  151. }
  152. void GameObject::markTfrmDirty() const
  153. {
  154. mIsCachedLocalTfrmUpToDate = false;
  155. if(mIsCachedWorldTfrmUpToDate) // If it's already marked as dirty, no point is recursing the hierarchy again
  156. {
  157. mIsCachedWorldTfrmUpToDate = false;
  158. for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
  159. {
  160. (*iter)->markTfrmDirty();
  161. }
  162. }
  163. }
  164. void GameObject::updateWorldTfrm() const
  165. {
  166. if(!mParent.expired())
  167. {
  168. GameObjectPtr tempParentPtr = mParent.lock();
  169. mCachedWorldTfrm = getLocalTfrm() * tempParentPtr->getWorldTfrm();
  170. // Update orientation
  171. const Quaternion& parentOrientation = tempParentPtr->getWorldRotation();
  172. mWorldRotation = parentOrientation * mRotation;
  173. // Update scale
  174. const Vector3& parentScale = tempParentPtr->getWorldScale();
  175. // Scale own position by parent scale, NB just combine
  176. // as equivalent axes, no shearing
  177. mWorldScale = parentScale * mScale;
  178. // Change position vector based on parent's orientation & scale
  179. mWorldPosition = parentOrientation * (parentScale * mPosition);
  180. // Add altered position vector to parents
  181. mWorldPosition += tempParentPtr->getWorldPosition();
  182. }
  183. else
  184. {
  185. mCachedWorldTfrm = getLocalTfrm();
  186. mWorldRotation = mRotation;
  187. mWorldPosition = mPosition;
  188. mWorldScale = mScale;
  189. }
  190. mIsCachedWorldTfrmUpToDate = true;
  191. }
  192. void GameObject::updateLocalTfrm() const
  193. {
  194. mCachedLocalTfrm.makeTransform(mPosition, mScale, mRotation);
  195. mIsCachedLocalTfrmUpToDate = true;
  196. }
  197. /************************************************************************/
  198. /* Hierarchy */
  199. /************************************************************************/
  200. void GameObject::setParent(GameObjectPtr parent)
  201. {
  202. if(parent == nullptr || parent->isDestroyed())
  203. {
  204. CM_EXCEPT(InternalErrorException,
  205. "Parent is not allowed to be NULL or destroyed.");
  206. }
  207. if(mParent.expired() || mParent.lock() != parent)
  208. {
  209. if(!mParent.expired())
  210. mParent.lock()->removeChild(mThis.lock());
  211. if(parent != nullptr)
  212. parent->addChild(mThis.lock());
  213. mParent = parent;
  214. markTfrmDirty();
  215. }
  216. }
  217. GameObjectPtr GameObject::getChild(unsigned int idx) const
  218. {
  219. if(idx < 0 || idx >= mChildren.size())
  220. {
  221. CM_EXCEPT(InternalErrorException,
  222. "Child index out of range.");
  223. }
  224. return mChildren[idx];
  225. }
  226. int GameObject::indexOfChild(const GameObjectPtr child) const
  227. {
  228. for(int i = 0; i < (int)mChildren.size(); i++)
  229. {
  230. if(mChildren[i] == child)
  231. return i;
  232. }
  233. return -1;
  234. }
  235. void GameObject::addChild(GameObjectPtr object)
  236. {
  237. mChildren.push_back(object);
  238. }
  239. void GameObject::removeChild(GameObjectPtr object)
  240. {
  241. auto result = find(mChildren.begin(), mChildren.end(), object);
  242. if(result != mChildren.end())
  243. mChildren.erase(result);
  244. else
  245. {
  246. CM_EXCEPT(InternalErrorException,
  247. "Trying to remove a child but it's not a child of the transform.");
  248. }
  249. }
  250. ComponentPtr GameObject::getComponent(UINT32 typeId) const
  251. {
  252. for(auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
  253. {
  254. if((*iter)->getRTTI()->getRTTIId() == typeId)
  255. return *iter;
  256. }
  257. return nullptr;
  258. }
  259. void GameObject::destroyComponent(ComponentPtr component)
  260. {
  261. if(component == nullptr)
  262. {
  263. LOGDBG("Trying to remove a null component");
  264. return;
  265. }
  266. auto iter = std::find(mComponents.begin(), mComponents.end(), component);
  267. if(iter != mComponents.end())
  268. {
  269. (*iter)->destroy();
  270. mComponents.erase(iter);
  271. gSceneManager().notifyComponentRemoved((*iter));
  272. }
  273. else
  274. LOGDBG("Trying to remove a component that doesn't exist on this GameObject.");
  275. }
  276. }