www.mtkn.jp

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

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