Welt2D.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. #include "Welt2D.h"
  2. #include "Bild.h"
  3. using namespace Framework;
  4. Object2D::Object2D()
  5. : ReferenceCounter()
  6. {
  7. rSpeed = 0;
  8. rotation = 0;
  9. size = 1;
  10. collision = 1;
  11. }
  12. Object2D::~Object2D() {}
  13. // Übergibt einen Void Funktionspointer auf eine Aktion die einmalig vom
  14. // Hauptthread ausgeführt werden soll. (Passiert nach dem Tick)
  15. void Object2D::postAction(std::function<void()> action)
  16. {
  17. actions.push(action);
  18. }
  19. void Object2D::explosion(Vertex worldPos, float intensity)
  20. {
  21. intensity /= (position - worldPos).getLengthSq();
  22. speed += (position - worldPos) * intensity;
  23. }
  24. void Object2D::impuls(Vertex start, Vertex speed, float strength) {}
  25. void Object2D::setSpeed(Vertex speed)
  26. {
  27. this->speed = speed;
  28. }
  29. void Object2D::setSpeed(float x, float y)
  30. {
  31. speed.x = x, speed.y = y;
  32. }
  33. void Object2D::setPosition(Vertex pos)
  34. {
  35. position = pos;
  36. }
  37. void Object2D::setPosition(float x, float y)
  38. {
  39. position = Vertex(x, y);
  40. }
  41. void Object2D::setDrehungSpeed(float ds)
  42. {
  43. rSpeed = ds;
  44. }
  45. void Object2D::setDrehung(float drehung)
  46. {
  47. rotation = drehung;
  48. while (rotation > PI * 2)
  49. rotation -= (float)PI * 2;
  50. while (rotation < 0)
  51. rotation += (float)PI * 2;
  52. }
  53. void Object2D::addDrehung(float drehung)
  54. {
  55. rotation += drehung;
  56. while (rotation > PI * 2)
  57. rotation -= (float)PI * 2;
  58. while (rotation < 0)
  59. rotation += (float)PI * 2;
  60. }
  61. void Object2D::setSize(float size)
  62. {
  63. this->size = size;
  64. }
  65. void Object2D::addSize(float size)
  66. {
  67. this->size += size;
  68. }
  69. void Object2D::setCollision(bool handle)
  70. {
  71. collision = handle;
  72. }
  73. bool Object2D::handleCollision(Object2D* obj)
  74. {
  75. Vertex hp;
  76. if (istModelInnen(obj, &hp)) // hp wird auf den aufprallpunkt gesetzt
  77. {
  78. // Geschwindigkeit von diesem objekt mit rotation
  79. Vertex v1
  80. = getSpeed()
  81. + getWorldDir(getObjectPos(hp).rotation(rSpeed) - getObjectPos(hp));
  82. // Geschwindigkeit des anderen Objektes mit rotation
  83. Vertex v2
  84. = obj->getSpeed()
  85. + getWorldDir(obj->getObjectPos(hp).rotation(obj->getDrehungSpeed())
  86. - obj->getObjectPos(hp));
  87. if ((hp - obj->getPosition()).getLengthSq()
  88. > (hp + v1 * 0.03f - obj->getPosition()).getLengthSq()
  89. || (hp - getPosition()).getLengthSq()
  90. > (hp + v2 * 0.03f - getPosition()).getLengthSq())
  91. { // nur wenn sie sich aufeinander zu bewegen
  92. float m1 = getMasse() * v1.getLength(); // fläche von Objekt 1
  93. float m2 = obj->getMasse() * v2.getLength(); // fläche von Objekt 2
  94. if (m1 == 0 || m2 == 0)
  95. return 0; // falls ein objekt keine masse hat ignoriere die
  96. // kollision
  97. float nm1 = m1 / (m1 + m2); // koeffizient für objekt 2
  98. float nm2 = m2 / (m1 + m2); // koeffizient für Objekt 1
  99. // rSpeed *= nm1; // Drehgeschwindigkeit anpassen (objekt 1)
  100. // speed *= nm1; // Bewegungsgeschwindigkeit anpassen (objekt 1)
  101. // obj->setDrehungSpeed( obj->getDrehungSpeed() * nm2 ); //
  102. // Drehgeschwindigkeit anpassen (objekt 2) obj->setSpeed(
  103. // obj->getSpeed() * nm2 ); // Bewegungsgeschwindigkeit anpassen
  104. // (objekt 2)
  105. float speedSumLength
  106. = getSpeed().getLength() + obj->getSpeed().getLength();
  107. rSpeed = 0;
  108. speed = Vertex();
  109. obj->setDrehungSpeed(0);
  110. obj->setSpeed(Vertex());
  111. if (v2.x || v2.y) impuls(hp - v2, v2);
  112. if (getSpeed().getLength() > 0)
  113. setSpeed(getSpeed().normalize() * speedSumLength * nm2);
  114. if (v1.x || v1.y) obj->impuls(hp - v1, v1);
  115. if (obj->getSpeed().getLength() > 0)
  116. obj->setSpeed(
  117. obj->getSpeed().normalize() * speedSumLength * nm1);
  118. return 1;
  119. }
  120. }
  121. return 0;
  122. }
  123. bool Object2D::tick(const WeltInfo& info, double zeit)
  124. {
  125. while (!actions.empty())
  126. {
  127. actions.front()();
  128. actions.pop();
  129. }
  130. rotation += rSpeed * (float)zeit;
  131. while (rotation > PI * 2)
  132. rotation -= (float)PI * 2;
  133. while (rotation < 0)
  134. rotation += (float)PI * 2;
  135. position += speed * (float)zeit;
  136. while (zeit > 1)
  137. {
  138. rSpeed -= rSpeed
  139. - (rSpeed / (1 + info.airResistance * getLuftWiederstand()));
  140. speed -= speed
  141. - (speed / (1 + info.airResistance * getLuftWiederstand()));
  142. zeit -= 1;
  143. }
  144. rSpeed
  145. -= (rSpeed - (rSpeed / (1 + info.airResistance * getLuftWiederstand())))
  146. * (float)zeit;
  147. speed -= (speed - (speed / (1 + info.airResistance * getLuftWiederstand())))
  148. * (float)zeit;
  149. if (info.circular && info.hasSize && info.size.x && info.size.y)
  150. {
  151. while (position.x > (float)info.size.x)
  152. position.x -= (float)info.size.x;
  153. while (position.x < 0)
  154. position.x += (float)info.size.x;
  155. while (position.y > (float)info.size.y)
  156. position.y -= (float)info.size.y;
  157. while (position.y < 0)
  158. position.y += (float)info.size.y;
  159. }
  160. return rSpeed != 0 || speed != Vertex(0, 0);
  161. }
  162. bool Object2D::istPunktInnen(Vertex p, bool ignoreTransparent) const
  163. {
  164. return 0;
  165. }
  166. bool Object2D::istLinieInnen(Vertex a, Vertex b, bool ignoreTransparent) const
  167. {
  168. return 0;
  169. }
  170. bool Object2D::istModelInnen(
  171. const Object2D* zObj, Vertex* sp, bool end, bool ignoreTransparent) const
  172. {
  173. return 0;
  174. }
  175. Mat3<float> Object2D::getObjectMatrix() const
  176. {
  177. return Mat3<float>::translation(position) * Mat3<float>::rotation(rotation)
  178. * Mat3<float>::scaling(size);
  179. }
  180. Mat3<float> Object2D::getInverseObjectMatrix() const
  181. {
  182. return Mat3<float>::scaling(1 / size) * Mat3<float>::rotation(-rotation)
  183. * Mat3<float>::translation(-position);
  184. }
  185. Vertex Object2D::getObjectPos(Vertex worldPos) const
  186. {
  187. return (worldPos - position).rotation(-rotation) * (1 / size);
  188. }
  189. Vertex Object2D::getObjectDir(Vertex worldDir) const
  190. {
  191. return Vertex(worldDir.x, worldDir.y).rotation(-rotation) * (1 / size);
  192. }
  193. Vertex Object2D::getWorldPos(Vertex objectPos) const
  194. {
  195. return (Vertex(objectPos) * size).rotation(rotation) + position;
  196. }
  197. Vertex Object2D::getWorldDir(Vertex objectDir) const
  198. {
  199. return (Vertex(objectDir) * size).rotation(rotation);
  200. }
  201. Vertex Object2D::getSpeed() const
  202. {
  203. return speed;
  204. }
  205. Vertex Object2D::getPosition() const
  206. {
  207. return position;
  208. }
  209. float Object2D::getDrehungSpeed() const
  210. {
  211. return rSpeed;
  212. }
  213. float Object2D::getDrehung() const
  214. {
  215. return rotation;
  216. }
  217. float Object2D::getSize() const
  218. {
  219. return size;
  220. }
  221. bool Object2D::calcHitPoint(Vertex pos, Vertex dir, Vertex& hitpoint) const
  222. {
  223. return 0;
  224. }
  225. float Object2D::getLuftWiederstand() const
  226. {
  227. return 0;
  228. }
  229. float Object2D::getMasse() const
  230. {
  231. return 0;
  232. }
  233. bool Object2D::canCollide()
  234. {
  235. return collision;
  236. }
  237. Welt2D::Welt2D()
  238. : ReferenceCounter()
  239. {
  240. objects = new RCArray<Object2D>();
  241. memset(&info, 0, sizeof(WeltInfo));
  242. }
  243. Welt2D::~Welt2D()
  244. {
  245. objects->release();
  246. }
  247. void Welt2D::setAirResistance(float resistance)
  248. {
  249. info.airResistance = resistance;
  250. }
  251. void Welt2D::setSize(int width, int height)
  252. {
  253. info.size.x = width;
  254. info.size.y = height;
  255. }
  256. void Welt2D::setSize(bool hasSize)
  257. {
  258. info.hasSize = hasSize;
  259. }
  260. void Welt2D::setCircular(bool circular)
  261. {
  262. info.circular = circular;
  263. }
  264. Object2D* Welt2D::zObjectAt(int x, int y, bool ignoreTransparentFlag)
  265. {
  266. for (auto o : *objects)
  267. {
  268. if (o->istPunktInnen(Punkt(x, y), ignoreTransparentFlag)) return o;
  269. }
  270. return 0;
  271. }
  272. Object2D* Welt2D::getObjectAt(int x, int y, bool ignoreTransparentFlag)
  273. {
  274. Object2D* tmp = zObjectAt(x, y, ignoreTransparentFlag);
  275. return tmp ? dynamic_cast<Object2D*>(tmp->getThis()) : 0;
  276. }
  277. void Welt2D::addObject(Object2D* obj)
  278. {
  279. objects->add(obj);
  280. }
  281. void Welt2D::removeObject(Object2D* zObj)
  282. {
  283. int anz = objects->getEintragAnzahl();
  284. for (int i = 0; i < anz; i++)
  285. {
  286. if (objects->z(i) == zObj)
  287. {
  288. objects->remove(i);
  289. i--;
  290. }
  291. }
  292. }
  293. void Welt2D::removeAll()
  294. {
  295. objects->leeren();
  296. }
  297. void Welt2D::explosion(Vertex worldPos, float intensity, float maxRad)
  298. {
  299. maxRad = maxRad * maxRad;
  300. for (auto obj : *objects)
  301. {
  302. if (info.circular && info.hasSize && info.size.x && info.size.y)
  303. {
  304. Vertex offsets[] = {Vertex(0, 0),
  305. Vertex((float)info.size.x, 0),
  306. Vertex(0, (float)info.size.y),
  307. Vertex((float)info.size.x, (float)info.size.y),
  308. Vertex((float)-info.size.x, 0),
  309. Vertex(0, (float)-info.size.y),
  310. Vertex((float)-info.size.x, (float)-info.size.y),
  311. Vertex((float)-info.size.x, (float)info.size.y),
  312. Vertex((float)info.size.x, (float)-info.size.y)};
  313. Vertex offset;
  314. float minDist = INFINITY;
  315. for (Vertex p : offsets)
  316. {
  317. float dist
  318. = (obj->getPosition() - (worldPos - p)).getLengthSq();
  319. if (dist < minDist)
  320. {
  321. minDist = dist;
  322. offset = p;
  323. }
  324. }
  325. if ((obj->getPosition() - (worldPos - offset)).getLengthSq()
  326. < maxRad)
  327. obj->explosion(worldPos - offset, intensity);
  328. }
  329. else if ((obj->getPosition() - worldPos).getLengthSq() < maxRad)
  330. obj->explosion(worldPos, intensity);
  331. }
  332. }
  333. void Welt2D::impuls(Vertex worldPos, Vertex worldDir)
  334. {
  335. Vertex hitPoint;
  336. float dist = INFINITY;
  337. Object2D* o = 0;
  338. for (auto obj : *objects)
  339. {
  340. if (obj->calcHitPoint(worldPos, worldDir, hitPoint))
  341. {
  342. if ((hitPoint - worldPos).getLengthSq() < dist)
  343. {
  344. dist = (hitPoint - worldPos).getLengthSq();
  345. o = obj;
  346. }
  347. }
  348. }
  349. if (o) o->impuls(worldPos, worldDir);
  350. }
  351. bool Welt2D::tick(double zeit)
  352. {
  353. bool ret = 0;
  354. for (auto obj = objects->begin(); obj; obj++)
  355. {
  356. if (obj.hasNext() && obj->canCollide())
  357. {
  358. for (auto obj2 = obj.next(); obj2; obj2++)
  359. {
  360. if (obj2->canCollide()) obj->handleCollision(obj2);
  361. }
  362. }
  363. ret |= obj->tick(info, zeit);
  364. }
  365. return ret;
  366. }
  367. void Welt2D::render(Mat3<float>& kamMat,
  368. Punkt size,
  369. Bild& zRObj,
  370. int xOffset,
  371. int yOffset,
  372. const char* kamName)
  373. {
  374. for (auto obj : *objects)
  375. {
  376. Rect2<float> bnd = obj->getBoundingBox();
  377. Vertex topRight = Vertex(bnd.bottomRight.x, bnd.topLeft.y);
  378. Vertex bottomLeft = Vertex(bnd.topLeft.x, bnd.bottomRight.y);
  379. Mat3<float> km
  380. = kamMat
  381. * Mat3<float>::translation(Vertex((float)xOffset, (float)yOffset));
  382. bnd.bottomRight = km * bnd.bottomRight;
  383. bnd.topLeft = km * bnd.topLeft;
  384. topRight = km * topRight;
  385. bottomLeft = km * bottomLeft;
  386. if ((bnd.bottomRight.x >= 0 && bnd.bottomRight.x < (float)size.x)
  387. || (bnd.bottomRight.y >= 0 && bnd.bottomRight.y < (float)size.y)
  388. || (bnd.topLeft.x >= 0 && bnd.topLeft.x < (float)size.x)
  389. || (bnd.topLeft.y >= 0 && bnd.topLeft.y < (float)size.y)
  390. || (topRight.x >= 0 && topRight.x < (float)size.x)
  391. || (topRight.y >= 0 && topRight.y < (float)size.y)
  392. || (bottomLeft.x >= 0 && bottomLeft.x < (float)size.x)
  393. || (bottomLeft.y >= 0 && bottomLeft.y < (float)size.y))
  394. obj->render(km, zRObj, kamName);
  395. }
  396. }
  397. void Welt2D::render(
  398. Mat3<float>& kamMat, Punkt size, Bild& zRObj, const char* kamName)
  399. {
  400. if (!info.hasSize || !info.circular)
  401. {
  402. for (auto obj : *objects)
  403. {
  404. Rect2<float> bnd = obj->getBoundingBox();
  405. Vertex topRight = Vertex(bnd.topLeft.y, bnd.bottomRight.x);
  406. Vertex bottomLeft = Vertex(bnd.topLeft.x, bnd.bottomRight.y);
  407. bnd.bottomRight = kamMat * bnd.bottomRight;
  408. bnd.topLeft = kamMat * bnd.topLeft;
  409. topRight = kamMat * topRight;
  410. bottomLeft = kamMat * bottomLeft;
  411. if ((bnd.bottomRight.x >= 0 && bnd.bottomRight.x < (float)size.x)
  412. || (bnd.bottomRight.y >= 0 && bnd.bottomRight.y < (float)size.y)
  413. || (bnd.topLeft.x >= 0 && bnd.topLeft.x < (float)size.x)
  414. || (bnd.topLeft.y >= 0 && bnd.topLeft.y < (float)size.y)
  415. || (topRight.x >= 0 && topRight.x < (float)size.x)
  416. || (topRight.y >= 0 && topRight.y < (float)size.y)
  417. || (bottomLeft.x >= 0 && bottomLeft.x < (float)size.x)
  418. || (bottomLeft.y >= 0 && bottomLeft.y < (float)size.y))
  419. obj->render(kamMat, zRObj, kamName);
  420. }
  421. }
  422. else if (info.circular)
  423. {
  424. render(kamMat, size, zRObj, 0, 0, kamName);
  425. render(kamMat, size, zRObj, info.size.x, 0, kamName);
  426. render(kamMat, size, zRObj, 0, info.size.y, kamName);
  427. render(kamMat, size, zRObj, info.size.x, info.size.y, kamName);
  428. render(kamMat, size, zRObj, -info.size.x, 0, kamName);
  429. render(kamMat, size, zRObj, 0, -info.size.y, kamName);
  430. render(kamMat, size, zRObj, -info.size.x, -info.size.y, kamName);
  431. render(kamMat, size, zRObj, -info.size.x, +info.size.y, kamName);
  432. render(kamMat, size, zRObj, +info.size.x, -info.size.y, kamName);
  433. }
  434. }
  435. const WeltInfo& Welt2D::getWorldInfo() const
  436. {
  437. return info;
  438. }
  439. ArrayIterator<Object2D*> Welt2D::getMembers()
  440. {
  441. return objects->begin();
  442. }