ネットワークゲームへのアプローチ1  スレッド

ここでは将来、ネットワークゲームを作るための下準備をします。

ネットワークゲームを作るためのベースとなるのは、言うまでもなく通信です。
そして通信にどうしても必要なのがスレッドです。
スレッドというのは、プロセスというか、プログラムというか、同時に走っている別なプログラムです。

ウィンドウズでは、同時にいくつものプログラムが走っていますが、自分のプログラムの中でも同じように複数のプログラム(とくにこれをプロセスと呼びます)を走らせることができます。

この方法をスレッドと呼びます。ほかのコンピュータと通信する場合はいつデータが入ってくるかわからないので常にその入り口を監視していなければなりません。

ゲームプログラム(に限りませんが)メインプログラムの中に監視機能を組み込むのはとても面倒だし、データ取りこぼしもでてくるし有効な方法とはいえません。

そこで、データの入り口の監視はスレッドに任せることにします。

まずスレッドとはどう動くのか、それを理解するために小さなスレッドを作って動かしてみましょう。

プロジェクトはSDIのFormViewを選択します。フォームが出来たらボタンを二つ配置します。そのボタンの一つには「スレッドの開始」、もう一つには「スレッドの停止」というキャプションをつけます。

キャプションは、ボタンの上で右クリックをしてプロパティを開き、その右側のテキストを変更すれば変わります。

次にボタンのハンドラを作ります。ボタンをダブルクリックして出てきたメンバ関数追加ウィンドウでそのままリターンキーを押します。

次にそのハンドラのファイルの先頭に移動して、インクルードファイル群のしたに以下のようにインクルードを追加します。

#include "process.h"

これでスレッドを作る土台が完成です。

次はスレッドの本体を作ります。

ここではViewの中にテキストを表示するスレッドを作ります。

CClientDC DC(this);      // デバイスコンテキストを作る
DC.TextOut(100 200,"ここにシュート"); // X位置、Y位置、表示テキスト

これが画面にテキストを表示するコードです。試しにボタンのハンドルにこのコードを追加してちゃんと動くか確認してみましょう。

ちゃんと字が表示されましたか。では次にこれをランダムな位置に表示してみます。テキストの表示位置に乱数を入れてやると押すたびに違う位置にテキストがおかれます。

int mybias = 200;
DC.TextOut(rand() % 200 + mybyas ,rand() % 200 + mybyas,"1234");

ここでmybyas とあるのは、表示位置の右上座標を決めています。x、yがともに200以上に限定されます。つまり左上の隅に固まらないという意味です。これもちゃんと動きましたか?

では次にこの部分をスレッドにして勝手にテキストを置くようにしてみましょう。

スレッド部分はグローバル関数とします。なぜグローバルにする必要があるのか、考えてください。「SelfPut」という関数を作ります。これがスレッドの本体になります。以下のような関数です。
 

int goout=0;
 
void SelfPut(void *ch)
{
    CThreadView *pthreadview = (CThreadView *)ch; // ThreadView は自分のVIewの名前を入れる
    CClientDC DC(pthreadview);         // 書き込みDC
     while(1)
{
      Sleep( 100L );             // スリープ
      DC.TextOut(rand() % 200 + mybyas ,rand() % 200 + mybyas,"1234");
   if goout ==1 break;
}
}
 

あれ、おかしいじゃないか・・・って思いましたか?そう思ったのはまじめに勉強していた人です。そうです、これは無限ループになっています。でも通常できないこうした書き方がスレッドでは許されてしまうのです。なぜかというと、ここで無限ループにはまっていてもプロセスの管理がなされるので強制的にほかのプロセスに移ってしまうからです。つまりスレッドというのはプログラムの一部というよりは、ウィンドウズが直接管理しているような形になるのでこれで大丈夫なのです。

こういうことができなければスレッドを使う意味が無い、ともいえます。

スレッドを止めるのは、goout というグローバルフラグです。ここが1になとスレッドのループが終わって関数からリターンします。スレッドからリターンするということは、そのスレッドが終了することを意味します。

Sleepというのは、休み時間をあらわしています。いくらウィンドウズが管理しているといってもスレッド自体が重ければやはりウィンドウズ全体の動きに影響を与えます。おまけに1秒に一回くらいしか実行しないのであれば1秒に一回呼び出されるのが行儀よいプログラムというものでしょう。

次にこのスレッドを動かします。

スレッドを動かすにはボタンのハンドルに以下のようなコードを書きます。
 

_beginthread( SelfPut, // 動かすスレッドの本体
          1,   // スレッドのスタック。システムに任せる場合は0
         this); // スレッドに渡すパラメータ。ここでは親を識別するためのポインタ
 

スレッドの終了ボタンには   goout=1 を入れてください。

では、実行。



こんな風に出ればOK。

簡単でしょ?