「文字数オーバー」エラーの為に"Worldクラス(3)"を更に分割しなければなりませんでしたが、前回の続きでアバター機能追加の為に新作した"AvatarController"ダイアログ
をやります。オリジナルのC++にはなかった機能ですので、適宜「解説:」を追加しておきます。
【Worldクラス後半】
//////////////////////////////
//AvatarController ダイアログ
//(最長3秒で自動的に閉じる)
//解説:最初は「長考可」でしたが、ゲームスピード、切迫感醸成の為に自動的に閉じるようにしました。
//////////////////////////////
class AvatarController : Form
{
///////////////////////
//定数定義(変更不可)
///////////////////////
const int Wld_Width = 80; //Worldの幅(セル数)
const int Max_Dir = 8; //↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7
const int Not_Found = -1; //Find_***処理用
//クラスフィールド
private World wld; //Worldクラスインスタンス
private Cell cell; //自分(Avatar)セル自身
private Cell you; //遭遇する他のCell
private int yDir; //遭遇する他のCellの方向
private int fDir = Not_Found; //食べ物の方向
//ダイアログコントロール
//グループボックス
GroupBox gBox;
GroupBox gBoxFood;
GroupBox gBoxMove;
//ラベル
private Label lblMe;
private Label lblYou;
private Label lblTribe;
private Label lblAffection;
private Label lblHostility;
private Label lblMeTribe;
private Label lblMeAffection;
private Label lblMeHostility;
private Label lblYouTribe;
private Label lblYouAffection;
private Label lblYouHostility;
//チェックボックス
private CheckBox InterMarriage;
//ボタン
private Button btnGetClose; //親交
private Button btnIntimidate; //威嚇
private Button btnFight; //闘争
private Button btnFlee; //逃走
private Button btnEat; //摂食
private Button[] btnDir; //移動
private Button btnPass; //パス(何もしない)
//自動終了タイマー
Timer dlgTimer;
//worldはcのいる世界、dirがNot_Foundでなければ、遭遇した他のセルがy(nullでない)
public AvatarController(World world, Cell c, Cell y, int dir)
{ //解説:引数はWorldクラスインスタンス、自分のセル、遭遇したセルとそれがいる方向
//引数の記録
wld = world;
cell = c;
you = y;
yDir = dir;
//ダイアログの属性設定
this.Text = "アバターコントローラー";
this.ClientSize = new Size(320, 460);
this.ControlBox = false; //システムボタンを無効化
this.ShowInTaskbar = true; //タスクバー上表示
this.FormBorderStyle = FormBorderStyle.FixedDialog; //境界のスタイル
this.StartPosition = FormStartPosition.CenterScreen;//画面中央(解説:親の右隣にされますが...)
InitControls(); //コントロールの配置
SetControls(cell); //コントロールの初期設定
//3秒で閉じる設定にする
dlgTimer = new Timer();
dlgTimer.Tick += new EventHandler(OnPass_Click);
dlgTimer.Interval = 3000; //解説:ミリ秒単位なので「3秒」
dlgTimer.Start();
}
private void InitControls()
{
//フォームのレイアウトを一時停止
this.SuspendLayout();
//グループボックス(相手セルへの対応)
gBox = new GroupBox();
gBox.Location = new Point(10, 10);
gBox.Size = new Size(ClientSize.Width - 20, 180);
gBox.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left);
gBox.Enabled = false; //初期状態は使用不可
gBox.Text = "遭遇したCellへの対応";
//チェックボックスの属性設定
InterMarriage = new CheckBox();
InterMarriage.Location = new Point(10, 16);
InterMarriage.Size = new Size(ClientSize.Width - 40, 18);
InterMarriage.CheckAlign = ContentAlignment.MiddleRight;
InterMarriage.TextAlign = ContentAlignment.MiddleLeft;
InterMarriage.Text = "異種族婚許可";
InterMarriage.AutoCheck = false; //ユーザー変更不可
//ラベルの属性設定
lblTribe = new Label();
lblTribe.Size = new Size(60, 18);
lblTribe.Location = new Point(10, 68);
lblTribe.BorderStyle = BorderStyle.Fixed3D;
lblTribe.Text = "種族";
lblTribe.TextAlign = ContentAlignment.MiddleCenter;
lblTribe.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblAffection = new Label();
lblAffection.Size = new Size(60, 18);
lblAffection.Location = new Point(10, 94);
lblAffection.BorderStyle = BorderStyle.Fixed3D;
lblAffection.Text = "愛着性";
lblAffection.TextAlign = ContentAlignment.MiddleCenter;
lblAffection.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblHostility = new Label();
lblHostility.Size = new Size(60, 18);
lblHostility.Location = new Point(10, 120);
lblHostility.BorderStyle = BorderStyle.Fixed3D;
lblHostility.Text = " 敵対性";
lblHostility.TextAlign = ContentAlignment.MiddleCenter;
lblHostility.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblMe = new Label();
lblMe.Size = new Size(100, 18);
lblMe.Location = new Point(80, 42);
lblMe.BorderStyle = BorderStyle.Fixed3D;
lblMe.Text = "アバターセル";
lblMe.TextAlign = ContentAlignment.MiddleCenter;
lblMe.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblMe.BackColor = Color.SkyBlue;
lblMeTribe = new Label();
lblMeTribe.Size = new Size(100, 18);
lblMeTribe.Location = new Point(80, 68);
lblMeTribe.BorderStyle = BorderStyle.Fixed3D;
lblMeTribe.Text = "";
lblMeTribe.TextAlign = ContentAlignment.MiddleCenter;
lblMeTribe.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblMeTribe.BackColor = Color.SkyBlue;
lblMeAffection = new Label();
lblMeAffection.Size = new Size(100, 18);
lblMeAffection.Location = new Point(80, 92);
lblMeAffection.BorderStyle = BorderStyle.Fixed3D;
lblMeAffection.Text = "";
lblMeAffection.TextAlign = ContentAlignment.MiddleCenter;
lblMeAffection.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblMeAffection.BackColor = Color.SkyBlue;
lblMeHostility = new Label();
lblMeHostility.Size = new Size(100, 18);
lblMeHostility.Location = new Point(80, 120);
lblMeHostility.BorderStyle = BorderStyle.Fixed3D;
lblMeHostility.Text = "";
lblMeHostility.TextAlign = ContentAlignment.MiddleCenter;
lblMeHostility.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblMeHostility.BackColor = Color.SkyBlue;
lblYou = new Label();
lblYou.Size = new Size(100, 18);
lblYou.Location = new Point(190, 42);
lblYou.BorderStyle = BorderStyle.Fixed3D;
lblYou.Text = "相手のセル";
lblYou.TextAlign = ContentAlignment.MiddleCenter;
lblYou.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblYou.BackColor = Color.Violet;
lblYouTribe = new Label();
lblYouTribe.Size = new Size(100, 18);
lblYouTribe.Location = new Point(190, 68);
lblYouTribe.BorderStyle = BorderStyle.Fixed3D;
lblYouTribe.Text = "";
lblYouTribe.TextAlign = ContentAlignment.MiddleCenter;
lblYouTribe.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblYouTribe.BackColor = Color.Violet;
lblYouAffection = new Label();
lblYouAffection.Size = new Size(100, 18);
lblYouAffection.Location = new Point(190, 92);
lblYouAffection.BorderStyle = BorderStyle.Fixed3D;
lblYouAffection.Text = "";
lblYouAffection.TextAlign = ContentAlignment.MiddleCenter;
lblYouAffection.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblYouAffection.BackColor = Color.Violet;
lblYouHostility = new Label();
lblYouHostility.Size = new Size(100, 18);
lblYouHostility.Location = new Point(190, 120);
lblYouHostility.BorderStyle = BorderStyle.Fixed3D;
lblYouHostility.Text = "";
lblYouHostility.TextAlign = ContentAlignment.MiddleCenter;
lblYouHostility.Font = new Font("MS明朝", 8, FontStyle.Regular);
lblYouHostility.BackColor = Color.Violet;
//ボタンの属性設定
btnGetClose = new Button(); //親交
btnGetClose.Size = new Size(60, 24);
btnGetClose.Location = new Point(10, 148);
btnGetClose.Text = "親交";
btnGetClose.BackColor = Color.LimeGreen;
btnGetClose.Click += new EventHandler(OnGetClose_Click);
btnIntimidate = new Button(); //威嚇
btnIntimidate.Size = new Size(60, 24);
btnIntimidate.Location = new Point(82, 148);
btnIntimidate.Text = "威嚇";
btnIntimidate.BackColor = Color.Orange;
btnIntimidate.Click += new EventHandler(OnIntimidate_Click);
btnFight = new Button(); //闘争
btnFight.Size = new Size(60, 24);
btnFight.Location = new Point(154, 148);
btnFight.Text = "闘争";
btnFight.BackColor = Color.Red;
btnFight.Click += new EventHandler(OnFight_Click);
btnFlee = new Button(); //逃走
btnFlee.Size = new Size(60, 24);
btnFlee.Location = new Point(226, 148);
btnFlee.Text = "逃走";
btnFlee.BackColor = Color.DeepSkyBlue;
btnFlee.Click += new EventHandler(OnFlee_Click);
//帰属関係設定
gBox.Controls.Add(InterMarriage);
gBox.Controls.Add(lblMe);
gBox.Controls.Add(lblMeTribe);
gBox.Controls.Add(lblMeAffection);
gBox.Controls.Add(lblMeHostility);
gBox.Controls.Add(lblYou);
gBox.Controls.Add(lblYouTribe);
gBox.Controls.Add(lblYouAffection);
gBox.Controls.Add(lblYouHostility);
gBox.Controls.Add(lblTribe);
gBox.Controls.Add(lblAffection);
gBox.Controls.Add(lblHostility);
gBox.Controls.Add(btnGetClose);
gBox.Controls.Add(btnIntimidate);
gBox.Controls.Add(btnFight);
gBox.Controls.Add(btnFlee);
this.Controls.Add(gBox);
//グループボックス(食物への対応)
gBoxFood = new GroupBox();
gBoxFood.Location = new Point(10, gBox.Height + 20);
gBoxFood.Size = new Size(ClientSize.Width - 20, 48);
gBoxFood.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left);
gBoxFood.Text = "食物への対応";
gBoxFood.Enabled = false; //初期状態は使用不可
//ボタンの属性設定
btnEat = new Button();
btnEat.Size = new Size(gBoxFood.Width - 40, 24);
btnEat.Location = new Point(20, 16);
btnEat.Text = "食べる";
btnEat.BackColor = Color.LawnGreen;
btnEat.Click += new EventHandler(OnEat_Click);
//帰属関係設定
gBoxFood.Controls.Add(btnEat);
this.Controls.Add(gBoxFood);
//グループボックス(移動対応)
gBoxMove = new GroupBox();
gBoxMove.Location = new Point(10, gBox.Height + gBoxFood.Height + 30);
gBoxMove.Size = new Size(ClientSize.Width - 20, 160);
gBoxMove.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left);
gBoxMove.Text = "移動対応";
//ボタンの属性設定
btnDir = new Button[8]; //↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7
int btnW = 40, btnH = 40;
int posX = (gBoxMove.Width - btnW * 3 - 8) / 2;
int posY = 20;
//本プログラムのリソースマネージャー作成(解説:".dll"なので、実行ファイル".exe"の場合とちょっと違います。)
ResourceManager rm = new ResourceManager("Cell_World", Assembly.GetAssembly(typeof(World)));
Bitmap bmp; //解説:貼り付け処理用ビットマップフィールド。Dispose()処理が必要か否か調べ、".resource"ファイルのビットマップへのポインターとしてしか機能していないので、「不要」という結論になりました。
btnDir[0] = new Button(); //解説:ボタンインスタンスを作ります。以下同じ。
btnDir[0].Size = new Size(btnW, btnH); //解説:大きさを決定します。以下同じ。
btnDir[0].Location = new Point(posX + btnW + 4, posY); //解説:位置決めします。以下同じ。
btnDir[0].BackColor = Color.LightCyan; //解説:ボタンの背景色を指定します。以下同じ。
btnDir[0].Click += new EventHandler(OnUp_Click); //解説:ボタンが押された場合の割り込みメソッドを指定します。
bmp = (Bitmap)rm.GetObject("U"); //リソース埋め込みビットマップの読み込み(アドレスをbmpポインターへ)
bmp.MakeTransparent(Color.White); //解説:".resource"ファイルのビットマップを透明化します。以下同じ。
btnDir[0].Image = bmp; //解説:ボタンにビットマップを貼り付けます。
btnDir[0].Enabled = false; //初期状態は使用不可
btnDir[1] = new Button();
btnDir[1].Size = new Size(btnW, btnH);
btnDir[1].Location = new Point(posX + (btnW + 4) * 2, posY);
btnDir[1].BackColor = Color.LightCyan;
btnDir[1].Click += new EventHandler(OnUpRight_Click);
bmp = (Bitmap)rm.GetObject("UR"); //ビットマップの読み込み
bmp.MakeTransparent(Color.White);
btnDir[1].Image = bmp;
btnDir[1].Enabled = false; //初期状態は使用不可
btnDir[2] = new Button();
btnDir[2].Size = new Size(btnW, btnH);
btnDir[2].Location = new Point(posX + btnW * 2 + 8, posY + btnH + 4);
btnDir[2].BackColor = Color.LightCyan;
btnDir[2].Click += new EventHandler(OnRight_Click);
bmp = (Bitmap)rm.GetObject("R"); //ビットマップの読み込み
bmp.MakeTransparent(Color.White);
btnDir[2].Image = bmp;
btnDir[2].Enabled = false; //初期状態は使用不可
btnDir[3] = new Button();
btnDir[3].Size = new Size(btnW, btnH);
btnDir[3].Location = new Point(posX + (btnW + 4) * 2, posY + btnH * 2 + 8);
btnDir[3].BackColor = Color.LightCyan;
btnDir[3].Click += new EventHandler(OnDownRight_Click);
bmp = (Bitmap)rm.GetObject("DR"); //ビットマップの読み込み
bmp.MakeTransparent(Color.White);
btnDir[3].Image = bmp;
btnDir[3].Enabled = false; //初期状態は使用不可
btnDir[4] = new Button();
btnDir[4].Size = new Size(btnW, btnH);
btnDir[4].Location = new Point(posX + btnW + 4, posY + btnH * 2 + 8);
btnDir[4].Click += new EventHandler(OnDown_Click);
btnDir[4].BackColor = Color.LightCyan;
bmp = (Bitmap)rm.GetObject("D"); //ビットマップの読み込み
bmp.MakeTransparent(Color.White);
btnDir[4].Image = bmp;
btnDir[4].Enabled = false; //初期状態は使用不可
btnDir[5] = new Button();
btnDir[5].Size = new Size(btnW, btnH);
btnDir[5].Location = new Point(posX, posY + btnH * 2 + 8);
btnDir[5].BackColor = Color.LightCyan;
btnDir[5].Click += new EventHandler(OnDownLeft_Click);
bmp = (Bitmap)rm.GetObject("DL"); //ビットマップの読み込み
bmp.MakeTransparent(Color.White);
btnDir[5].Image = bmp;
btnDir[5].Enabled = false; //初期状態は使用不可
btnDir[6] = new Button();
btnDir[6].Size = new Size(btnW, btnH);
btnDir[6].Location = new Point(posX, posY + btnH + 4);
btnDir[6].BackColor = Color.LightCyan;
btnDir[6].Click += new EventHandler(OnLeft_Click);
bmp = (Bitmap)rm.GetObject("L"); //ビットマップの読み込み
bmp.MakeTransparent(Color.White);
btnDir[6].Image = bmp;
btnDir[6].Enabled = false; //初期状態は使用不可
btnDir[7] = new Button();
btnDir[7].Size = new Size(btnW, btnH);
btnDir[7].Location = new Point(posX, posY);
btnDir[7].BackColor = Color.LightCyan;
btnDir[7].Click += new EventHandler(OnUpLeft_Click);
bmp = (Bitmap)rm.GetObject("UL"); //ビットマップの読み込み
bmp.MakeTransparent(Color.White);
btnDir[7].Image = bmp;
btnDir[7].Enabled = false; //初期状態は使用不可
//帰属関係設定
gBoxMove.Controls.Add(btnDir[0]);
gBoxMove.Controls.Add(btnDir[1]);
gBoxMove.Controls.Add(btnDir[2]);
gBoxMove.Controls.Add(btnDir[3]);
gBoxMove.Controls.Add(btnDir[4]);
gBoxMove.Controls.Add(btnDir[5]);
gBoxMove.Controls.Add(btnDir[6]);
gBoxMove.Controls.Add(btnDir[7]);
this.Controls.Add(gBoxMove);
//「パス」(Pass)ボタンの属性設定(解説:内容的には"Cancel"です。)
btnPass = new Button();
btnPass.Size = new Size(60, 24);
btnPass.Location = new Point(ClientSize.Width - btnPass.Width - 10, ClientSize.Height - btnPass.Height - 10);
btnPass.Text = "パス";
btnPass.Click += new EventHandler(OnPass_Click);
this.Controls.Add(btnPass);
//フォームのレイアウトを再開
this.ResumeLayout(false);
this.PerformLayout();
}
private void SetControls(Cell cell) //解説:ダイアログへの引数から、コントロールの初期状態を設定します。
{
//異種族間婚許可の確認
InterMarriage.Checked = cell.Intmarg;
//Avatarの属性表示(自分(引数cell)から自分の属性をラベルに表示します。)
string[] tribes = new string[] {"ピンク", "ブルー", "グリーン", "死亡"};
lblMeTribe.Text = tribes[cell.Tribe];
lblMeAffection.Text = cell.Affection.ToString();
lblMeHostility.Text = cell.Hostility.ToString();
//Avatarセルの周囲状況をダイアログに反映させる
//解説:コンピューター処理では周囲状況への対応優先順位が
//「1-セル」「2-食物」「3-野原」ですが、ダイアログでは
//アバター(ユーザー)が自由に選択できます。
for(int i = 0; i < Max_Dir; i++)
{
switch(cell.Around[i]) //ダイアログ呼び出し前にCheck_Around実行済
{
case 0: //野原
//「移動」処理の矢印の.Enabledを変更(進める)
btnDir[i].Enabled = true;
break;
case 1: //山(進めない)
case 2: //河川(進めない)
break; //解説:処理なし、です。
case 3: //食物
//「食べる 」処理のgBoxFood.Enabledを変更(食べられる)
fDir = i; //食物のある方向
gBoxFood.Enabled = true;
break;
default: //セル(cell.Around[i] >= 4)
break; //解説:↓でセルyとyDirを使って行いますので、ここでは処理なし、です。
}
if(yDir != Not_Found) //他のセルと遭遇したならば(解説:Cell yがnullではなく、その方向(yDir)が-1ではない)
{
if(you.Tribe < 3) //生存するセル(Cell-P、Cell-B、Cell-G)なら
{
gBox.Enabled = true; //他のセルへの対応が可能となる
}
else if(you.Tribe == 3) //死亡したセルなら食物扱いとなるので
{
fDir = yDir;
gBoxFood.Enabled = true;
}
//他のセルの属性表示(解説:二つ以上いたとしても、yとyDirについて処理します。)
lblYouTribe.Text = tribes[you.Tribe];
lblYouAffection.Text = you.Affection.ToString();
lblYouHostility.Text = you.Hostility.ToString();
}
}
}
//終了処理
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
//タイマーの停止と廃棄(解説:タイマーは開放<Dispose()>する必要があります。)
dlgTimer.Stop();
dlgTimer.Dispose();
}
//解説:以下ではWorldクラスインスタンスの「5つの"Inter-Cell relation/reaction(セル間関係/反応)」を処理します。
//③-(セル間関係)(1) get_close()-親しくなり、愛着性が高まり、敵対性が低まります。
//③-(セル間関係)(2) make_love()ー一定の愛着性を超えると交尾し、生殖力により出産します。
//③-(セル間関係)(3) intimidate()ー敵対性と愛着性の度合いにより、相手を威嚇し、敵対性が高まり、愛着性が低まります。
//③-(セル間関係)(4) fight()ー異種族婚許可、敵対性により、相互に攻撃、被害を受けます。
//③-(セル間関係)(5) flee()ー敵対状態になっても、攻撃力、防御力の差が大きければ逃走します。」
//その為にWorldクラスインスタンス(wld)のアドレスが必要となり、本ダイアログの引数に入れています。
private void OnGetClose_Click(object sender, EventArgs e)
{
wld.Get_Close(cell, you, yDir);
Close();
}
private void OnIntimidate_Click(object sender, EventArgs e)
{
wld.Intimidate(cell, you, yDir);
Close();
}
private void OnFight_Click(object sender, EventArgs e)
{
wld.Fight(cell, you, yDir);
Close();
}
private void OnFlee_Click(object sender, EventArgs e)
{
wld.Flee(cell, you, yDir);
Close();
}
//解説:以下は自分(Cellクラスインスタンスのcell)のメソッドで処理します。
private void OnEat_Click(object sender, EventArgs e)
{
cell.Get_Food(fDir);
Close();
}
private void OnUp_Click(object sender, EventArgs e)
{
cell.Get_Move(0);
Close();
}
private void OnUpRight_Click(object sender, EventArgs e)
{
cell.Get_Move(1);
Close();
}
private void OnRight_Click(object sender, EventArgs e)
{
cell.Get_Move(2);
Close();
}
private void OnDownRight_Click(object sender, EventArgs e)
{
cell.Get_Move(3);
Close();
}
private void OnDown_Click(object sender, EventArgs e)
{
cell.Get_Move(4);
Close();
}
private void OnDownLeft_Click(object sender, EventArgs e)
{
cell.Get_Move(5);
Close();
}
private void OnLeft_Click(object sender, EventArgs e)
{
cell.Get_Move(6);
Close();
}
private void OnUpLeft_Click(object sender, EventArgs e)
{
cell.Get_Move(7);
Close();
}
//解説:お分かりの通り、全ての「5つの"Inter-Cell relation/reaction(セル間関係/反応)」、
//「摂食」、「移動」処理を実行すると本ダイアログを閉じます(Close())。
//従って、「一回の<3秒間の>ダイアログ表示でユーザーが選択した一つの行動」
//しかとれないことになります。
private void OnPass_Click(object sender, EventArgs e)
{
Close(); //解説:「パス」はCancelと同じく何もしないでダイアログを閉じることです。
}
}
} //解説:これはWorld_Cell(namespace)の閉じ括弧です。
以上で3回(実質的に4回ですが...)にわたって行ったWorldクラスの解説を終了します。
今後はこのCell_World.dll、Worldクラスインスタンスであるウィンドウコントロールの実際の使用例として、Cells.exeのソースを解説してゆきましょう。
