久々に迷路を作っていきたいと思います。
前回までは、ピクチャーボックスをキーボードの操作で移動できるようにしました。
次にやりたいのは、壁にぶつかったら、動作しないようにする事です。
今回の事は、インターロックの考え方になるので、一緒に学びましょう!!
※インターロックとは、、ある一定の条件が整わないと他の動作ができなくなるような機構のこと
移動の可否の判断は??
まずは移動していいかどうかというのは、どう判断するのでしょうか?
今だと機械学習が発達し、あいまいな事を判断できるようになってきてます。
しかし、プログラミングする時は、あいまいを表現する事は出来ない為、明確にする必要があります。
では、移動できない時とは、どんな時でしょうか?
『移動先が壁の時やエリア外の時が移動できません』
では、この部分をどうやって判断するか考えてみましょう。
ピクチャーボックスが移動するのは?
まずは、前回作った関数です。
private void Move_PictureBox(PictureBox pic,Point pntValue)
{
int x = pic.Location.X + pntValue.X;
int y = pic.Location.Y + pntValue.Y;
pic.Location = new Point(x, y);
return;
}
青マーカー部の時にピクチャーボックスは移動します。
その為、移動する前に、移動する場所が移動していい場所かをチェックしましょう。
そこで、移動の可否を判断する関数を入れて、可能な時にピクチャーボックスを移動させましょう。
private void Move_PictureBox(PictureBox pic, Point pntValue)
{
if (pic != null)
{
int x = pic.Location.X + pntValue.X;
int y = pic.Location.Y + pntValue.Y;
//移動先が壁でないか確認する。
Point pnttarget = new Point(x, y);
if (Check_Target(pic,pnttarget) == true)
{
//移動
pic.Location = pnttarget;
}
}
return;
}
黄色マーカー部は、移動先のポイント(位置)を表しています。
青色マーカー部で、その移動先のポイント(位置)が移動していい場所か判断します。
判断するための関数を作りました。(Check_Target(Picturebox,Point))
判断に必要な情報は、ピクチャーボックスの情報と移動先のポイント(位置)です。
判断の結果がOK(True)の場合、移動させます。
移動の可否判断方法
難関でした。。。いい方法が閃かなくて。。。
いい方法は他に絶対あるはずですが、
今回は、移動先のピクチャーボックスの4つ角が壁に当たらないかを確認したいと思います。
まずは4つ角のポイントを計算します。
先ほどの関数の中を作っていきましょう。
private bool Check_Target(PictureBox pic, Point pntTarget) { //4角分 Point[] pnt = new Point[4]; pnt[0] = new Point(pntTarget.X, pntTarget.Y); pnt[1] = new Point(pntTarget.X + pic.Width, pntTarget.Y); pnt[2] = new Point(pntTarget.X, pntTarget.Y + pic.Height); pnt[3] = new Point(pntTarget.X + pic.Width, pntTarget.Y + pic.Height); (処理) return true; }
まずは、ポイントを4つ角分作ります。(ポイント型の配列)
各ポイントに、左上、右上、左下、右下のポイントを入れます。
つぎは4つ角が壁に当たっていないか判断します。
イケていない方法ですが、全てのラベルを確認します。
private bool Check_Target(PictureBox pic, Point pntTarget)
{
(先ほどの部分なので省略)
foreach (Point p in pnt)
{
for (int x = 0; x < Maze_X; x++)
{
for (int y = 0; y < Maze_Y; y++)
{
Rectangle rct = new Rectangle(lblMaze(x, y).Location, lblMaze(x, y).Size);
if(rct.Contains(p) == true)
{
if (lblMaze(x, y).BackColor == Color.Gray)
{
return false;
}
}
}
}
}
return true;
}
foreachを使って配列分回します。その時の配列のデータはpと名前を付けます。(黄色)
次にラベル分ループで回します。
ラベルは命名規則として座標が入っているので、x,yの分を回します。(青色)
ラベルのループのタイミングでラベルの情報を取得し、ラベルの四角のエリアを定義ます。(赤色)
四角のエリアの中にポイント(位置)pが入っているかを確認します(赤色)
ポイントに入っている場合、その時のラベルの色(BackColor)を確認し、灰色であれば、壁に当たるという事です!!
ではこれで動かしてみましょう。
壁の時は移動できない事は確認しました。
壁では止まるようには、なったけど。。。
壁では止まるようになったけど、ラベルの範囲外には移動できます。
そこで、ラベルの範囲外も壁と同様に移動できないようにしましょう!!
ラベルの範囲外というのは、どういう判断をすればいいのでしょうか??
各角をラベル分回していますが、どのラベルにも見つからなかった場合は、ラベルの外に行こうといていることになります。その為、フラグと条件を増やしたいと思います。
private bool Check_Target(PictureBox pic, Point pntTarget) { (先ほどの部分なので省略) foreach (Point p in pnt) { bool isFind = false; for (int x = 0; x < Maze_X; x++) { for (int y = 0; y < Maze_Y; y++) { Rectangle rct = new Rectangle(lblMaze(x, y).Location, lblMaze(x, y).Size); if(rct.Contains(p) == true) { isFind = true; //見つかったのでフラグを立てる if (lblMaze(x, y).BackColor == Color.Gray) { return false; } } } } //見つからなかったら、ラベル外if (isFind == false)
{
return false;
}
} return true; }
角のループ開始時にフラグを定義し(黄色)、
角がラベルの中に入っていた場合、ContainsでTrueと判断されるので、
その時に定義したフラグを立てます。(赤色)
ラベルのループが回り切った時に定義したフラグ(isFind)がFalseの時に
ラベル外と判断します。(青色)
これで、ラベル外に行かないようになりました。
最後に
今回は、ラベルを移動させて、移動できるかできないかの判断を入れるようにしました。
これは、インターロックの考え方として使えますので、ぜひとも覚えておきましょう。
基本的には、移動先を計算し、移動先に移動可能かどうかを先に判断します。
判断する方法は様々だと思いますので、いろいろと考えてみましょう☆
業務でプログラミング(C#/VB/Python)を作っている。
挫折を何回も繰り返し、幾度の壁を乗り越えてきた。
乗り越えてきた事を忘れないように記録に残す。
同じ思いをしている人への情報提供になれたらと思う。
基本は初心者に向けたプログラムの情報を提供する。
コメント