はじめに
対戦型のテニスゲームを作成して、.NET Remotingを使ってみましょう。
対象読者
C#を使って.NET Remotingを覚えたい人。
必要な環境
- Windows
- Visual Studio 2005
解説概要
物理的に離れたPCで実行して結果を得る方法では、Webサービスが便利です。しかし、Webサーバが必要であったり、オーバヘッドが気になったりします。ここでは、別々のPC上での対戦型テニスゲームの作成を通して、.NET Remotingの使い方を見ていきます。
プロジェクトの作成
Visual Studio 2005(以下、VS2005)を起動しましょう。VS2005のExpress版ならば、Microsoftのサイトから無料でダウンロードできます。[ファイル]-[新規作成]-[プロジェクト]を選択し、プロジェクトの種類で[Visual C#]の[Windows]、テンプレートで[Windowsアプリケーション]を選択します。プロジェクト名は、「TennisGame」にして、[OK]ボタンを押してください。
ソリューションの設定
[表示]メニューから、[ソリューションエクスプローラ]を表示してください。これは、ソリューション内のファイルなどを管理できます。本アプリケーションは、.NET Remotingを利用するので、必要なDLLを指定します。ソリューションエクスプローラの[参照設定]を右クリックし、[参照の追加]を選びます。[.NET]タブのSystem.Runtime.Remotingを選択し、[OK]を押します。次にサーバ名を外部ファイルで指定可能にしてみましょう。ソリューションエクスプローラのPropertiesの「+」をクリックして開き、Settings.settingsをダブルクリックします。名前を「Server」に、値を「localhost」にします。
[ファイル]メニューの[すべてを保存]を選択して保存し、Settings.settingsを閉じてください。
メイン画面作成
最初に表示されているウィンドウ(Form1.cs[デザイン])はForm1のデザイン画面です。ソリューションエクスプローラの「Form1.cs」をダブルクリックすればいつでも開くことができます。Form1は、実行時に表示されるメイン画面です。タイトルを変更しましょう。[表示]メニューの[プロパティウィドウ]を表示してください。Form1を選択している状態で、プロパティのText
を探し、「Form1」から「Tennis」に変更します。
次に、Form1に部品を配置しましょう。[表示]メニューの[ツールボックス]を表示してください。[すべてのWindowsフォーム]からPictureBoxをクリックし、次にForm1上でもう一度クリックしてください。PictureBoxが配置されます(PictureBoxは、主に画像表示で用いられます)。PictureBoxの右上の右向きの小さい三角形を押して、[親コンテナにドッキングする]を選んでください。
PictureBoxが画面全体に引き伸ばされます。背景色を変更しましょう。PictureBoxのプロパティで、BackColor
の値欄のドロップダウンを選択し、カスタムの中から水色の列の一番下の色を選択してください(表示は、「0,64,64」となります)。次にツールボックスのButtonをクリックし、Form1上でもう一度クリックして、Buttonを配置してください。
配置したら、Form1の右上に移動させてください。Buttonのプロパティで、Text
を「Restart」に変更します。また、このボタンは最初は表示されないように、プロパティのVisible
を「false」にします。次に、TimerとBackgroundWorkerをForm1にドラッグしてください。TimerのプロパティのEnabled
を「True」にし、Interval
を「50」にしてください。
サーバクラスの作成
[プロジェクト]-[新しい項目の追加]を選択して[クラス]を選択し、[ファイル名]を「Server.cs」にして[OK]ボタンを押します。内容を次のように修正します。
using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using System.Text; namespace TennisGame { public class Server : MarshalByRefObject { public const int WinPoint = 3; public const float Size = 0.08F; private float[] barPos = new float[2]; public float BarPos(bool bFirst) { return barPos[bFirst ? 0 : 1]; } private int[] score = new int[2]; public int Score(bool bFirst) { return score[bFirst ? 0 : 1]; } private PointF discPos; public PointF DiscPos { get { return discPos; } } private SizeF dir; private int count; public bool IsWaiting; public bool IsRunning; public Server() { Reset(); count = 24; IsWaiting = true; IsRunning = true; } public void Reset() { barPos[0] = 0; barPos[1] = 1 - Form1.barRate; score[0] = score[1] = 0; Init(true); IsRunning = true; } private void Init(bool bFirst) { discPos = new PointF(0.5F, 0.5F); dir = new SizeF((float)( new Random().NextDouble() * 0.05 - 0.025), 0.05F * (bFirst ? -1 : 1)); count = 8; } public void Do() { if (IsWaiting) return; if (count > 0) { --count; return; } discPos += dir; if (discPos.X < Size) { discPos.X = -discPos.X + 2 * Size; dir.Width = -dir.Width; } else if (discPos.X > 1 - Size) { discPos.X = -discPos.X + 2 * (1 - Size); dir.Width = -dir.Width; } for (int i = 0; i < 2; i++) { if (i == 0 && discPos.Y >= Size) continue; else if (i == 1 && discPos.Y <= 1 - Size) continue; float x = discPos.X - barPos[i]; if (x < 0 || x > Form1.barRate) { if (++score[1 - i] >= WinPoint) IsRunning = false; else Init(i == 0); } else { discPos.Y = -discPos.Y + 2 * (i == 0 ? Size : (1 - Size)); dir.Height = -dir.Height; if (x < Form1.barRate * 0.3) dir.Width -= 0.016F; else if (x > Form1.barRate * 0.7) dir.Width += 0.016F; } } } public void Move(bool bFirst, bool bLeft) { int i = bFirst ? 0 : 1; barPos[i] += (bLeft ? -1 : 1) * Size / 3; if (barPos[i] < 0) barPos[i] = 0; else if (barPos[i] > 1 - Form1.barRate) barPos[i] = 1 - Form1.barRate; } } }
Server
オブジェクトは、サーバで作成されます。クライアントからは、Serverのプロクシを作成して、プロクシを通してサーバのServer
オブジェクトを実行します。.NET Remotingでは、サーバで実行するクラスをMarshalByRefObject
から派生させる必要があります。