CmGameObject.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. // TODO - I'm ignoring "up" direction
  92. setForward(forward);
  93. Quaternion upRot = getUp().getRotationTo(up);
  94. setRotation(getRotation() * upRot);
  95. }
  96. const Matrix4& GameObject::getWorldTfrm() const
  97. {
  98. if(!mIsCachedWorldTfrmUpToDate)
  99. updateWorldTfrm();
  100. return mCachedWorldTfrm;
  101. }
  102. const Matrix4& GameObject::getLocalTfrm() const
  103. {
  104. if(!mIsCachedLocalTfrmUpToDate)
  105. updateLocalTfrm();
  106. return mCachedLocalTfrm;
  107. }
  108. void GameObject::move(const Vector3& vec)
  109. {
  110. setPosition(mPosition + vec);
  111. }
  112. void GameObject::moveRelative(const Vector3& vec)
  113. {
  114. // Transform the axes of the relative vector by camera's local axes
  115. Vector3 trans = mRotation * vec;
  116. setPosition(mPosition + trans);
  117. }
  118. void GameObject::rotate(const Vector3& axis, const Radian& angle)
  119. {
  120. Quaternion q;
  121. q.FromAngleAxis(angle,axis);
  122. rotate(q);
  123. }
  124. void GameObject::rotate(const Quaternion& q)
  125. {
  126. // Note the order of the mult, i.e. q comes after
  127. // Normalize the quat to avoid cumulative problems with precision
  128. Quaternion qnorm = q;
  129. qnorm.normalise();
  130. setRotation(qnorm * mRotation);
  131. }
  132. void GameObject::roll(const Radian& angle)
  133. {
  134. // Rotate around local Z axis
  135. Vector3 zAxis = mRotation * Vector3::UNIT_Z;
  136. rotate(zAxis, angle);
  137. }
  138. void GameObject::yaw(const Radian& angle)
  139. {
  140. Vector3 yAxis = mRotation * Vector3::UNIT_Y;
  141. rotate(yAxis, angle);
  142. }
  143. void GameObject::pitch(const Radian& angle)
  144. {
  145. // Rotate around local X axis
  146. Vector3 xAxis = mRotation * Vector3::UNIT_X;
  147. rotate(xAxis, angle);
  148. }
  149. void GameObject::setForward(const Vector3& forwardDir)
  150. {
  151. if (forwardDir == Vector3::ZERO)
  152. return;
  153. Vector3 nrmForwardDir = forwardDir.normalisedCopy();
  154. Vector3 currentForwardDir = getForward();
  155. const Quaternion& currentRotation = getWorldRotation();
  156. Quaternion targetRotation;
  157. if ((nrmForwardDir+currentForwardDir).squaredLength() < 0.00005f)
  158. {
  159. // Oops, a 180 degree turn (infinite possible rotation axes)
  160. // Default to yaw i.e. use current UP
  161. targetRotation = Quaternion(-currentRotation.y, -currentRotation.z, currentRotation.w, currentRotation.x);
  162. }
  163. else
  164. {
  165. // Derive shortest arc to new direction
  166. Quaternion rotQuat = currentForwardDir.getRotationTo(nrmForwardDir);
  167. targetRotation = rotQuat * currentRotation;
  168. }
  169. setRotation(targetRotation);
  170. }
  171. void GameObject::markTfrmDirty() const
  172. {
  173. mIsCachedLocalTfrmUpToDate = false;
  174. if(mIsCachedWorldTfrmUpToDate) // If it's already marked as dirty, no point is recursing the hierarchy again
  175. {
  176. mIsCachedWorldTfrmUpToDate = false;
  177. for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
  178. {
  179. (*iter)->markTfrmDirty();
  180. }
  181. }
  182. }
  183. void GameObject::updateWorldTfrm() const
  184. {
  185. if(!mParent.expired())
  186. {
  187. GameObjectPtr tempParentPtr = mParent.lock();
  188. mCachedWorldTfrm = getLocalTfrm() * tempParentPtr->getWorldTfrm();
  189. // Update orientation
  190. const Quaternion& parentOrientation = tempParentPtr->getWorldRotation();
  191. mWorldRotation = parentOrientation * mRotation;
  192. // Update scale
  193. const Vector3& parentScale = tempParentPtr->getWorldScale();
  194. // Scale own position by parent scale, NB just combine
  195. // as equivalent axes, no shearing
  196. mWorldScale = parentScale * mScale;
  197. // Change position vector based on parent's orientation & scale
  198. mWorldPosition = parentOrientation * (parentScale * mPosition);
  199. // Add altered position vector to parents
  200. mWorldPosition += tempParentPtr->getWorldPosition();
  201. }
  202. else
  203. {
  204. mCachedWorldTfrm = getLocalTfrm();
  205. mWorldRotation = mRotation;
  206. mWorldPosition = mPosition;
  207. mWorldScale = mScale;
  208. }
  209. mIsCachedWorldTfrmUpToDate = true;
  210. }
  211. void GameObject::updateLocalTfrm() const
  212. {
  213. mCachedLocalTfrm.makeTransform(mPosition, mScale, mRotation);
  214. mIsCachedLocalTfrmUpToDate = true;
  215. }
  216. /************************************************************************/
  217. /* Hierarchy */
  218. /************************************************************************/
  219. void GameObject::setParent(GameObjectPtr parent)
  220. {
  221. if(parent == nullptr || parent->isDestroyed())
  222. {
  223. CM_EXCEPT(InternalErrorException,
  224. "Parent is not allowed to be NULL or destroyed.");
  225. }
  226. if(mParent.expired() || mParent.lock() != parent)
  227. {
  228. if(!mParent.expired())
  229. mParent.lock()->removeChild(mThis.lock());
  230. if(parent != nullptr)
  231. parent->addChild(mThis.lock());
  232. mParent = parent;
  233. markTfrmDirty();
  234. }
  235. }
  236. GameObjectPtr GameObject::getChild(unsigned int idx) const
  237. {
  238. if(idx < 0 || idx >= mChildren.size())
  239. {
  240. CM_EXCEPT(InternalErrorException,
  241. "Child index out of range.");
  242. }
  243. return mChildren[idx];
  244. }
  245. int GameObject::indexOfChild(const GameObjectPtr child) const
  246. {
  247. for(int i = 0; i < (int)mChildren.size(); i++)
  248. {
  249. if(mChildren[i] == child)
  250. return i;
  251. }
  252. return -1;
  253. }
  254. void GameObject::addChild(GameObjectPtr object)
  255. {
  256. mChildren.push_back(object);
  257. }
  258. void GameObject::removeChild(GameObjectPtr object)
  259. {
  260. auto result = find(mChildren.begin(), mChildren.end(), object);
  261. if(result != mChildren.end())
  262. mChildren.erase(result);
  263. else
  264. {
  265. CM_EXCEPT(InternalErrorException,
  266. "Trying to remove a child but it's not a child of the transform.");
  267. }
  268. }
  269. ComponentPtr GameObject::getComponent(UINT32 typeId) const
  270. {
  271. for(auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
  272. {
  273. if((*iter)->getRTTI()->getRTTIId() == typeId)
  274. return *iter;
  275. }
  276. return nullptr;
  277. }
  278. void GameObject::destroyComponent(ComponentPtr component)
  279. {
  280. if(component == nullptr)
  281. {
  282. LOGDBG("Trying to remove a null component");
  283. return;
  284. }
  285. auto iter = std::find(mComponents.begin(), mComponents.end(), component);
  286. if(iter != mComponents.end())
  287. {
  288. (*iter)->destroy();
  289. mComponents.erase(iter);
  290. gSceneManager().notifyComponentRemoved((*iter));
  291. }
  292. else
  293. LOGDBG("Trying to remove a component that doesn't exist on this GameObject.");
  294. }
  295. }