www.mtkn.jp

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

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-&gt;px &lt; s2-&gt;px + s2-&gt;w && s2-&gt;px &lt; s1-&gt;px + s1-&gt;w &&
     53 	       s2-&gt;py &lt; s1-&gt;py + s1-&gt;h && s1-&gt;py &lt; s2-&gt;py + s2-&gt;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-&gt;px + s1-&gt;w, s2-&gt;px + s2-&gt;w) - max(s1-&gt;px, s2-&gt;px);
     67 	float lapy = min(s1-&gt;py + s1-&gt;h, s2-&gt;py + s2-&gt;h) - max(s1-&gt;py, s2-&gt;py);
     68 	float rel_vx = max(s1-&gt;vx - s2-&gt;vx, s2-&gt;vx - s1-&gt;vx);
     69 	float rel_vy = max(s1-&gt;vy - s2-&gt;vy, s2-&gt;vy - s1-&gt;vy);
     70 
     71 	if (lapx / rel_vx &lt; lapy / rel_vy) {
     72 		if (s1-&gt;px + s1-&gt;w &lt; s2-&gt;px + s2-&gt;w / 2) {
     73 			s1-&gt;px -= lapx / 2;
     74 			s2-&gt;px += lapx / 2;
     75 		} else {
     76 			s1-&gt;px += lapx / 2;
     77 			s2-&gt;px -= lapx / 2;
     78 		}
     79 	} else {
     80 		if (s1-&gt;py + s1-&gt;h &lt; s2-&gt;py + s2-&gt;h / 2) {
     81 			s1-&gt;py -= lapy / 2;
     82 			s2-&gt;py += lapy / 2;
     83 		} else {
     84 			s1-&gt;py += lapy / 2;
     85 			s2-&gt;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-&gt;w * s1-&gt;h;
    101 	float m2 = s2-&gt;w * s2-&gt;h;
    102 
    103 	float lapx = min(s1-&gt;px + s1-&gt;w, s2-&gt;px + s2-&gt;w) - max(s1-&gt;px, s2-&gt;px);
    104 	float lapy = min(s1-&gt;py + s1-&gt;h, s2-&gt;py + s2-&gt;h) - max(s1-&gt;py, s2-&gt;py);
    105 
    106 	if (lapx &lt; lapy) {
    107 		v1 = s1-&gt;vx;
    108 		v2 = s2-&gt;vx;
    109 		s1-&gt;vx = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1;
    110 		s2-&gt;vx = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2;
    111 	} else {
    112 		v1 = s1-&gt;vy;
    113 		v2 = s2-&gt;vy;
    114 		s1-&gt;vy = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1;
    115 		s2-&gt;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 &lt; SUB_TICK; j++) {
    135 			for (int i = 0; i &lt; NUM_SQUARE; i++)
    136 				next_tick(&square[i], 1000 * 1000 * 1000 / FPS / SUB_TICK);
    137 
    138 			for (int i = 0; i &lt; NUM_SQUARE; i++)
    139 				for (int j = i + 1; j &lt; 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>