Welt2D.cpp 14 KB

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