www.mtkn.jp

Manuscripts for my personal webpage.
git clone https://git.mtkn.jp/www.mtkn.jp
Log | Files | Refs | LICENSE

xlib_playground4.html (4944B)


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