xlib_playground4.html (5809B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width,initial-scale=1"> 6 <link rel="stylesheet" type="text/css" href="/style.css"> 7 <link rel="icon" type="image/x-icon" href="/pics/favicon.ico"> 8 <title>Xlibで遊んでみる4</title> 9 </head> 10 <body> 11 <header> 12 <a href="/">主頁</a> | 13 <a href="/about.html">自己紹介</a> | 14 <a href="/journal">日記</a> | 15 <a href="/farm">農業</a> | 16 <a href="/kitchen">台所</a> | 17 <a href="/computer">電算機</a> | 18 <a href="/poetry">詩</a> | 19 <a href="/books">本棚</a> | 20 <a href="/gallery">絵</a> | 21 <a href="https://git.mtkn.jp">Git</a> 22 </header> 23 <main> 24 <article> 25 <h1>Xlibで遊んでみる4</h1> 26 <time>2023-01-02</time> 27 28 <p> 29 前回: <a href="xlib_playground3.html">Xlibで遊んでみる3</a> 30 </p> 31 <p> 32 言語: C言語<br /> 33 ソースコード: <a href="https://git.mtkn.jp/xlib_playground">git</a> 34 </p> 35 36 <h2>衝突判定とその処理</h2> 37 <p> 38 これまでは一つの四角形だけを描画していたが、今回は複数の四角形を作成して動かしてみた。ランダムな場所にランダムな運動量で動かして、他のものやウィンドウの縁とぶつかったら跳ね返るようにした。</p> 39 <p> 40 回転しない四角形どうしの衝突判定は簡単である。x軸方向とy軸方向の両方に重なりがあれば衝突している: 41 </p> 42 <pre><code>struct square { 43 float ppx, ppy; // previous position 44 float px, py; // current position 45 float vx, vy; // velocity 46 int w, h; // width and height 47 }; 48 49 int 50 test_collision(struct square *s1, struct square* s2) 51 { 52 return s1->px < s2->px + s2->w && s2->px < s1->px + s1->w && 53 s2->py < s1->py + s1->h && s1->py < s2->py + s2->h; 54 } 55 </code></pre> 56 57 <p> 58 衝突後の処理は多少めんどくさかった。衝突した時は既にめりこんでいるので、まずはそれぞれをめりこんだ距離の半分ずつずらして衝突を解消するようにした。この際、x軸方向にぶつかったのか、y軸方向にぶつかったのかで、それぞれの軸方向にひっぺがすようにしている。二つの四角形の各軸に関するめりこんだ距離<code>lapx</code>、<code>lapy</code>と各軸に関する相対速度<code>rel_vx</code>、<code>rel_vy</code>の比を比べればどちらの軸方向にぶつかったかが分かるはずである、多分 : 59 </p> 60 <pre><code>void 61 handle_collision_mm(struct square *s1, struct square *s2) 62 { 63 if (!test_collision(s1, s2)) 64 return; 65 66 float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px); 67 float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py); 68 float rel_vx = max(s1->vx - s2->vx, s2->vx - s1->vx); 69 float rel_vy = max(s1->vy - s2->vy, s2->vy - s1->vy); 70 71 if (lapx / rel_vx < lapy / rel_vy) { 72 if (s1->px + s1->w < s2->px + s2->w / 2) { 73 s1->px -= lapx / 2; 74 s2->px += lapx / 2; 75 } else { 76 s1->px += lapx / 2; 77 s2->px -= lapx / 2; 78 } 79 } else { 80 if (s1->py + s1->h < s2->py + s2->h / 2) { 81 s1->py -= lapy / 2; 82 s2->py += lapy / 2; 83 } else { 84 s1->py += lapy / 2; 85 s2->py -= lapy / 2; 86 } 87 } 88 } 89 </code></pre> 90 <p> 91 衝突は弾性衝突として、衝突したそれぞれの四角形の速度を更新した。質量は四角形の面積として計算している。衝突後の速度はエネルギー保存則と運動量保存則から導いたのでしんどかった。 92 </p> 93 <pre><code>void 94 handle_collision_elastic(struct square *s1, struct square *s2) 95 { 96 if(!test_collision(s1, s2)) 97 return; 98 99 float v1, v2; 100 float m1 = s1->w * s1->h; 101 float m2 = s2->w * s2->h; 102 103 float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px); 104 float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py); 105 106 if (lapx < lapy) { 107 v1 = s1->vx; 108 v2 = s2->vx; 109 s1->vx = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1; 110 s2->vx = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2; 111 } else { 112 v1 = s1->vy; 113 v2 = s2->vy; 114 s1->vy = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1; 115 s2->vy = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2; 116 } 117 118 handle_collision_mm(s1, s2); 119 } 120 </code></pre> 121 122 <h2>サブティック</h2> 123 <p> 124 この名前が適切かどうか分からないが、前のフレームから次のフレームまでの時間をさらに何等分かして衝突判定の制度を上げた(マクロは括弧でかこって分かりにくいバグを防げとどこかに書いていたのでそうすることにした): 125 </p> 126 <pre><code>#define SUB_TIC (4) 127 128 void 129 game_play(void) 130 { 131 /* ... */ 132 while (next_menu == GAME_PLAY) { 133 /* ... */ 134 for (int j = 0; j < SUB_TICK; j++) { 135 for (int i = 0; i < NUM_SQUARE; i++) 136 next_tick(&square[i], 1000 * 1000 * 1000 / FPS / SUB_TICK); 137 138 for (int i = 0; i < NUM_SQUARE; i++) 139 for (int j = i + 1; j < NUM_SQUARE; j++) { 140 handle_collision_elastic(&square[i], &square[j]); 141 /* ... */ 142 } 143 /* ... */ 144 } 145 /* ... */ 146 } 147 /* ... */ 148 } 149 </code></pre> 150 151 <h2>完成品</h2> 152 <p> 153 <a href="https://git.mtkn.jp/xlib_playground/file/ex4/ex4.c.html">git</a> 154 </p> 155 <p> 156 <video controls> 157 <source src="videos/ex4.webm" type="video/webm"> 158 </video> 159 </p> 160 161 <h2>参考</h2> 162 <ul> 163 <li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> 164 </ul> 165 <p> 166 次の記事: <a href="xlib_playground5.html">Xlibで遊んでみる5</a> 167 </p> 168 </article> 169 170 </main> 171 <footer> 172 <address>info(at)mtkn(dot)jp</address> 173 <a href="http://creativecommons.org/publicdomain/zero/1.0?ref=chooser-v1" rel="license noopener noreferrer">CC0 1.0</a> 174 </footer> 175 </body> 176 </html>