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