www.mtkn.jp

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

xlib_playground4.html (4963B)


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