www.mtkn.jp

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

xlib_playground2.html (7993B)


      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で遊んでみる2</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で遊んでみる2</h1>
     26 <time>2022-12-22</time>
     27 
     28 <p>前回: <a href="xlib_playground1.html">Xlibで遊んでみる1</a></p>
     29 <p>言語はC言語である。ソースコードは<a href="https://git.mtkn.jp/xlib_playground">ここ</a>にある。
     30 </p>
     31 
     32 <h2>FPSの固定</h2>
     33 <p>前のフレームからの経過時間を計測して<code>1.0/FPS</code>を越えるまで待機させる。このときに<code>nanosleep()</code>を使うとなぜか上手くいかなかった。ナノ秒単位で処理できそうな名前なのに使えない。多分OSのコンテクストスイッチがどうとかいう話やと思う。知らんけど。組み込みとかで使うんかな?
     34 </p>
     35 
     36 <p>
     37 とりあえず<code>while</code>ループの中でひたすら時刻を読んでいる。リソースの無駄遣いではないのだろうか:
     38 </p>
     39 <pre><code>#defin FPS 60
     40 
     41 int
     42 main(void)
     43 {
     44 	long t0, t1, dt;
     45 	int fps_count;
     46 
     47 	clock_gettime(CLOCK_MONOTONIC, &ts);
     48 	t0 = ts.tv_nsec;
     49 
     50 	while (!quit) {
     51 		// fix fps
     52 		dt = 0;
     53 		while (dt &lt; 1.0 * 1000 * 1000 * 1000 / FPS){
     54 			clock_gettime(CLOCK_MONOTONIC, &ts);
     55 			t1 = ts.tv_nsec;
     56 			dt = t1 &gt; t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000;
     57 		}
     58 		// count fps.
     59 		fps_count++;
     60 		if (t1 &lt; t0){
     61 			printf("fps: %u\n", fps_count);
     62 			fps_count = 0;
     63 		}
     64 		clock_gettime(CLOCK_MONOTONIC, &ts);
     65 		t0 = ts.tv_nsec;
     66 	}
     67 }
     68 </code></pre>
     69 <p>
     70 時刻は<code>clock_gettime()</code>で測定して1秒未満の部分: <code>tv_nsec</code>だけを利用している。<code>tv_nsec</code>はナノ秒ナノで、10<sup>9</sup>を掛けている。<code>dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000</code>で前回の時刻と現在の時刻の少数部分を比較している。繰り上がりがあれば前回の時刻よりも現在の時刻の方が小さくなるので1秒足すことで調整している。</p>
     71 <p>
     72 FPSの計測の部分は、フレーム毎に<code>fps_count</code>を1ずつ増やし、ナノ秒が繰り上がった時点での<code>fps_count</code>を表示している。</p>
     73 <p>
     74 あまり正確な方法ではないように思うが、コンパクトにまとまったのではないだろうか。</p>
     75 
     76 <h2>キーボード入力の処理</h2>
     77 <p>キーボードからの入力を受け取る:</p>
     78 <pre><code>XSelectInput(display, window,
     79     ExposureMask|KeyPressMask|KeyReleaseMask);
     80 </code></pre>
     81 <p>ここではキーボードのキーを押した時と離した時に<code>XEvent</code>の通知を受け取るように設定した。
     82 </p>
     83 <p>
     84 <code>XNextEvent()</code>からひとつずつ入力を受け取ると、複数のキーが同時に押された時にうまく処理できなかったので、押されているキーを配列に保存しておくことにした:</p>
     85 <pre><code>enum Keys {
     86 	Key_D,
     87 	Key_S,
     88 	Key_A,
     89 	Key_W,
     90 	Key_Space,
     91 	Num_Key, //number of keys in this enum
     92 };
     93 enum Key_State {
     94 	Key_Up,
     95 	Key_Down,
     96 };
     97 
     98 int key_state[Num_Key];
     99 </code></pre>
    100 
    101 <p>
    102 入力の処理は<code>handle_inputs()</code>関数内で行なう。<code>A</code>、<code>S</code>、<code>D</code>、<code>W</code>のうちどれかのキーが押されているとそれぞれ左、下、右、上方向に速度を加算するようにした。また、<code>Q</code>が押されるか、windowが破壊されると<code>quit</code>フラグを<code>1</code>にしてメインループから抜けるようにしている:</p>
    103 <pre><code>int   quit;
    104 
    105 void
    106 handle_inputs(void)
    107 {
    108        XEvent event;
    109        while (XPending(display) &gt; 0) {
    110                XNextEvent(display, &event);
    111                switch (event.type) {
    112                case KeyPress: {
    113                        switch (XLookupKeysym(&event.xkey, 0)) {
    114                        case 'q':
    115                                quit = 1;
    116                                break;
    117                        case 'd':
    118                                key_state[Key_D] = Key_Down;
    119                                break;
    120                        case 'a':
    121                                key_state[Key_A] = Key_Down;
    122                                break;
    123                        case 'w':
    124                                key_state[Key_W] = Key_Down;
    125                                break;
    126                        case 's':
    127                                key_state[Key_S] = Key_Down;
    128                                break;
    129                        default:
    130                                break;
    131                        }
    132                } break;
    133                case KeyRelease: {
    134                        switch (XLookupKeysym(&event.xkey, 0)) {
    135                        case 'd':
    136                                key_state[Key_D] = Key_Up;
    137                                break;
    138                        case 'a':
    139                                key_state[Key_A] = Key_Up;
    140                                break;
    141                        case 'w':
    142                                key_state[Key_W] = Key_Up;
    143                                break;
    144 
    145                        case 's':
    146                                key_state[Key_S] = Key_Up;
    147                                break;
    148                        default:
    149                                break;
    150                        }
    151                } break;
    152                case ClientMessage: {
    153                        if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
    154                                quit = 1;
    155                        }
    156                } break;
    157                default:
    158                        break;
    159                }
    160        }
    161 
    162        vx = vy = 0;
    163        if (key_state[Key_D] == Key_Down)
    164                vx += 300;
    165        if (key_state[Key_A] == Key_Down)
    166                vx += -300;
    167        if (key_state[Key_S] == Key_Down)
    168                vy += 300;
    169        if (key_state[Key_W] == Key_Down)
    170                vy += -300;
    171 }
    172 </code></pre>
    173 
    174 <p>
    175 入力によって変更された速度は、<code>main()</code>関数内で次の座標を計算するために使用される:
    176 </p>
    177 <pre><code>float px = 200, py = 200;
    178 float vx = 0, vy = 0;
    179 int   width = 40, height = 40;
    180 
    181 int
    182 main(void)
    183 {
    184 	/* ... */
    185 	quit = 0;
    186 	while (!quit) {
    187 		handle_input()
    188 		/* ... */
    189 		px = px + vx * dt / 1000 / 1000 / 1000;
    190 		py = py + vy * dt / 1000 / 1000 / 1000;
    191 		// bind within the window
    192 		if (px &lt; 0)
    193 			px = 0;
    194 		if (win_width &lt; px + width)
    195 			px = win_width - width;
    196 		if (py &lt; 0)
    197 			py = 0;
    198 		if (win_height &lt; py + height)
    199 			py = win_height - height;
    200 
    201 		XClearArea(display, window,
    202 		    0, 0,                  // position
    203 		    win_width, win_height, // width and height
    204 		    False);
    205 		XFillRectangle(display, window, gc,
    206 		    px, py,    // position
    207 		    width, height);   // width and height
    208 	}
    209 	/* ... */
    210 }
    211 </code></pre>
    212 
    213 <h2>完成品</h2>
    214 <a href="https://git.mtkn.jp/xlib_playground/file/ex2/ex2.c.html">ソースコード</a>
    215 <p>色を変えてみた。</p>
    216 <video controls>
    217 	<source src="videos/ex2.webm" type="video/webm">
    218 </video>
    219 
    220 <h2>参考</h2>
    221 <ul>
    222 <li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li>
    223 </ul>
    224 <p>次の記事: <a href="xlib_playground3.html">Xlibで遊んでみる3</a>
    225 </p>
    226 		</article>
    227 
    228 	</main>
    229 	<footer>
    230 		<address>info(at)mtkn(dot)jp</address>
    231 		<a href="http://creativecommons.org/publicdomain/zero/1.0?ref=chooser-v1" rel="license noopener noreferrer">CC0 1.0</a>
    232 	</footer>
    233 </body>
    234 </html>