スネークゲーム1
スネークゲーム 1
------------------------------------------------------------
今回からスネークというゲームプログラムを
取り上げて詳しく見ていきたいと思います。
標準ライブラリークラスの使い方、
ゲームのクラスの作り方、
そしてゲームプログラムの作り方を習得しましょう。
スネークゲームは1970年代中頃に作られたゲームで、
オーソドックスですが、ポピュラーなゲームです。
スネークゲームプログラムは
下記 MQL5のarticles/65にありますので、
各自ダウンロードしてください。
Creating a "Snake" Game in MQL5
https://www.mql5.com/en/articles/65
httpsページ最下部にある、
1.Attached files Download ZIP
あるいは
2.snake-mql5-doc.zip
3.snake_game_mql5_en.zip
をダウンロードします。
1は、2と3の両方が含まれているので、
1をダウンロードした方がいいでしょう。
ダウンロードした後、ZIPファイルを解凍し展開します。
ZIPファイルを右クリックすると、メニューが表示されます。
「すべて展開」を選択し、クリックします。
展開すると、
snake_game_mql5_en.zip
snake-mql5-doc.zip
ファイルが2つあります。
snake_game_mql5_en.zipを解凍します。
新しいフォルダーの中にファイルが解凍されます。
snake-mql5-doc.zipは使いませんが、
解凍しておくと良いでしょう
snake_game_mql5_enのフォルダーには、
Snake.mql5
Snake.mqh
のあるExpertsフォルダーと
body.bmp
square.bmpなどイメージファイルのある
Imagesフォルダーがあります。
解凍したファイルを、次はMeta editorに移動しますので、
アップデートMQL4を用意します。
古いMQL4は標準ライブラリークラスが有りませんので使えません。
この際古いMQL4はアップデートMQL4に変更しましょう。
MQL5は問題なく使えます。
Metaeditorを開きます。
MQL4左側ナビゲータのExpertsを選択し、
マウスを右クリックし、メニューを表示します。
「フォルダーを開く」をクリックします。
そこに先ほどの
Snake.mqhファイル
Snake.mql5ファイルを移動します。
イメージファイルはMQL4左側ナビゲータのImagesに移動します。
Imagesフォルダーを開き、そこにGamesフォルダーごと移動を行なっても大丈夫です。
Snake.mql5ファイルはそのままでは使えませんので、
*.mql4ファイルにコードを移動する必要があります。
新規作成 ー> エキスパートアドバイザー(テンプレート)から
プログラムのないSnake.mql4ファイルを作ります。
ファイルの中をすべて消去し、
Snake.mql5ファイルのプログラムをそこにコピーし、保存します。
Snake.mqhファイルと
body.bmp、square.bmpなどイメージファイルはそのまま使えます。
しかし、
Snake.mqhのプログラムを見ると、プログラムの上の方には、
#include というコードがあります。
このVirtualKeys.mqhファイルは、
なぜかアップデートMQL4に有りません。
MQL5からもってくる必要があります。
MQL5からコピーしてIncludeフォルダーに置いて下さい。
(これが無いとスネークゲームが動きません。)
その後Snake.mql4をコンパイルします。
MT5ではゲームパネルの縦サイズは問題ありませんが、
MT4では少し長いので調整する必要がありますが、
それは次回に説明いたします。
(参考:以下のコードはVirtualKeys.mqhプログラム(途中省略)です。
標準ライブラリーのあるIncludeフォルダーにあります。
MQL5からコピーして、アップデートMQL4の同じ場所に持ってきます。)
/+------------------------------------------------------------------+
//| VirtualKeys.mqh |
//| Copyright 2009-2013, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link "http://www.mql5.com"
//+------------------------------------------------------------------+
//| Virtual keys copied from winuser.h |
//+------------------------------------------------------------------+
//
// Virtual Keys, Standard Set
//
#define VK_LBUTTON 0x01
#define VK_RBUTTON 0x02
#define VK_CANCEL 0x03
#define VK_MBUTTON 0x04
#define VK_XBUTTON1 0x05
#define VK_XBUTTON2 0x06
…
省略
…
#define VK_ATTN 0xF6
#define VK_CRSEL 0xF7
#define VK_EXSEL 0xF8
#define VK_EREOF 0xF9
#define VK_PLAY 0xFA
#define VK_ZOOM 0xFB
#define VK_NONAME 0xFC
#define VK_PA1 0xFD
#define VK_OEM_CLEAR 0xFE
--------------------------------------+
スネークゲーム 2
------------------------------------------------------------
スネークゲームは、市販のゲームのように複雑なものではなく、ごく簡単なものです。
ゲームのプログラミングで、図形、テキスト、ボタン等のチャートへの描き方、
イベントの処理の仕方を習得して行きたいと思います。
今回はパネルのサイズの修正からです。
アプリケーションはもともとMT5で使っていたコードなので、
アップデートMT4では少し大きすぎて、
コントロールパネルやステータスパネルが隠れしまいます。
このままでは、スタート、ストップなどのコントロールが出来ませんので、
サイズを調整します。
始めに、Snake.mqhファイルで調整します。
スネークの動き回る所はプレイングフィールドですが、
調整はこのフィールドを構成する各セルで行います。
Snake.mqhファイルのSQUARE_WIDTHとSQUARE_HEIGHTの値を変更します。
各セルは正方形で、長さの単位はpixelです。
変更前
#define SQUARE_WIDTH 20
#define SQUARE_HEIGHT 20
変更後
#define SQUARE_WIDTH 14
#define SQUARE_HEIGHT 14
変更後は、14 pixels にしています。
この数値以下にして下さい。
15以上にするとコントロールパネルが隠れてしまいます。
イメージファイルは
定義では以下のデイレクトリーです。
#define IMG_FILE_NAME_SQUARE "\\Images\\Games\\Snake\\square.bmp"
#define IMG_FILE_NAME_SQUARE で定義してあるデイレクトリーに
イメージファイルがあるか確認しておきましょう。
プレイングフィールドの縦の長さを変えるには、別の方法もあります。
Snake.mqhの定義に最後にある、
int game_level[][20][20]で、セルの縦の数を変更する事で行うことも出来ます。
詳細は省きますが、
game_level[][15][20]の3次元配列の、2番目の配列の要素数を15に変えます。
そして、正方形に並んだ数値の塊は6個あり、
それは各レベルのフィールドの初期状態を表示していますが、
正方形に並んだ数値の下から5行をそれぞれ削除します。
各正方形の中の9の数値は、障害物の位置を表しています。
1の数値はスネークの頭、2は胴体、3は尻尾の初期位置を表しています。
セルの大きさに戻りますが、
セルの大きさを14ピクセルにすると、
ステータスパネルの表示文字
Level: 0 of 5
Food left over 12
Live: 5
の右側が隠れてしまいますので、これも修正します。
修正は
Snake.mq4ファイルとSnake.mqhファイルで行います。
修正箇所はSnake.mq4はコードの始めの方にある、
#define spaces2
#define spaces6
#define spaces8
です。
表示文字の左端からの空白数を定義していますので、
ここで調整します。
spaces2はFood left over 12の表示、
spaces6はLevel: 0 of 5の表示、
spaces8はLive: 5 の表示に使われます。
spaces2は半角で2個の空白、spaces6は半角6個の空白、spaces8は半角8個の空白を意味しています。
以下のように、spaces2は半角で0個の空白、spaces6は半角2個の空白、spaces8は半角3個に調整します。
#define spaces2 ""
#define spaces6 " "
#define spaces8 " "
これでもまだ Food left over 12 の表示は隠れていまいますので、
#define FOOD_LEFT_OVER_EDIT_TEXTでの表示を
以下のように"Food rest: %u" に変えます。%uは非負整数を定義しています。
#define FOOD_LEFT_OVER_EDIT_TEXT "Food rest: %u"
スネークはフィールドの食べ物のベリーを食べて胴体が長くなっていく訳ですが、
"Food rest: %u"でベリーの残量を表示します。
さらに、ヘッダーパネル、コントロールパネル、ステータスパネルの横の長さを変更して
プレイイングフィールドの横の長さに合わせます。
以下のように、Snake.mqhファイルで飛び飛びに並んでいる定義を修正します。
変更前
#define CONTROL_WIDTH (COUNT_COLUMNS*(SQUARE_WIDTH-1)+1)/3
#define STATUS_WIDTH (COUNT_COLUMNS*(SQUARE_WIDTH-1)+1)/3
#define HEADER_WIDTH COUNT_COLUMNS*(SQUARE_WIDTH-1)+1
変更後
#define CONTROL_WIDTH (COUNT_COLUMNS*(SQUARE_WIDTH-1)+5)/3
#define STATUS_WIDTH (COUNT_COLUMNS*(SQUARE_WIDTH-1)+5)/3
#define HEADER_WIDTH COUNT_COLUMNS*(SQUARE_WIDTH-1)+3
パネルの大きさの修正は以上です。
次の修正は、スネークの動くスピードです。
SPEED_SNAKEを調整します。
#define SPEED_SNAKE 50
Sleep()関数を使用しているので、
数値が大きくなると遅くなります。
200くらいが適当でしょう。
#define SPEED_SNAKE 200
これでコンパイルします。
エラーが無かったら、OKです。
チャートにドロップインし、ゲームをして見ましょう。
スネークの方向変換は、キーボードの矢印キーで行います。
-----------------------------------------------------+
スネークゲーム 3
ゲームの概略
細部のプログラミングをやっていて、
ゲームの全体が見えなくったときは、
このゲームの概略に戻ってください。
自分でプログラミングするとき、
このような概略を作っておくと便利です。
1.ゲームタイトルは「Snake」よりなる。
2.コントロールパネルはスタート、ポーズ、ストップよりなる。
3.インフォメーションパネルはゲームのレベル、食べ物の残量、現在のライブ数よりなる。
4.スネークの動き回るフィールド(プレイングフィールド)は縦20個、横20個のセルよりなる。
5.スネークは緑色の頭、胴体、尻尾よりなる。
6.スネークの食べ物()がフィールドに置かれる。
7.スネークの灰色の障害物がフィールドに置かれる。
8.スネークは左右、上下に動く。胴体は頭の後について動き、尻尾は胴体の後について動く。
9.スネークが食べ物を食べる(スネークの頭が食べ物にぶつかる)と、胴体が1つ増える。
10.ゲームの各レベルは食べ物が12個あり、スネークが食べ物を食べるごとに減っていく。
11.スネークの胴体は1個から始まる。
12.スネークが食べ物を12個食べ、胴体が12個になると、次のレベルに移動する。
13.スネークが障害物にぶつかると、ライブ数が1つ減る。
14.ライブ数は0から5まである。ライブ数は、各レベルで5から始まる。
15.レベル0のゲームは、障害物はない。
16.スネークが障害物にぶつかると、各レベルのスタート地点に戻る。
17.ライブ数が0以下になると、スタート地点に戻り、レベルが1つ下がる。
ゲームプログラムの概要
1、インフォメーションパネル
Editタイプのオブジェクトで、
ゲーム中の食べ物の残りの数を知らせる。
Editタイプのオブジェクトは表示文字の編集が可能。
2、ゲームタイトル
Buttonタイプのオブジェクトで、表示は変える必要がない。
3、コントロールパネル
Buttonタイプのオブジェクトで、
Buttonタイプオブジェクトはボタンをクリックすることで、イベント処理を行う事が可能。
4.プレイングフィールド
BmpLabelのオブジェクトで、
BmpLabelオブジェクトはフィルド等イメージファイルを貼り付ける事が出来る。
5.すべてのオブジェクトはチャートの左側上部からの相対位置とし、
XピクセルとYピクセルの距離により位置を定義する。
6、スネークがプレイングフィールドの上下左右の端にきた時、
スネークは反対側の端に現れる。
7、スネークの頭の方向はスネークの動きの方向と同じ。
8、胴体の動きは頭の動きとは異なる。
9、尻尾の動きは最も近い胴体で決まる。
10、スネークがBerryを食べたときは、尻尾は動かず、
スネークの一番後の胴体があった場所に、新しく生成された胴体のエレメントが置かれる。
スネークの動作の3つの状態
1、方向に従った、頭の上下左右の1セルの移動
2、以前あった頭の位置へ胴体エレメントの移動
3、以前あった胴体の位置へ尻尾エレメントの移動
障害物にぶつかると、ゲームはスタート地点に戻る。
ゲームに使用するツール
(標準ライブラリークラスの使用)
1、CArrayObjectクラス
2、CChartObjectEditクラス、CChartObjectButtonクラス、CChartObjectBmpLabelクラス
CChartObjectEditクラスはインフォメーションパネルに使用。
CChartObjectButtonクラスはゲームタイトルとコントロールパネルに使用。
CChartObjectBmpLabelクラスはプレイングフィールド、スネーク、食べ物、障害物に使用。
CArrayObjectクラスはデータを組織化するためのクラスとして使用。
スネークゲーム 4
クラスを使わないときと、クラスを使用したとき
標準ライブラリーを使用するには
#includeを使いライブラリーをインクルードする必要があります。
例えば、
CChartObjectButtonオブジェクトを使うならば、
#include
と記述します。
ファイルパスはMQL5リファレンスでわかりますが、
MetaEditorナビゲータのIncludeフォルダでもわかります。
標準ライブラリーを使うとき、
大事なのは、継承関係を理解することです。
派生クラスが親クラスを継承しているとき、
派生クラスは、親クラスのプロパテイとメソッドを利用出来ます。
使い方を理解する為に、
標準ライブラリークラスを使用したときと、
使用しないときときを比べて見ます。
クラスを使わないときは
1、「butoon」という名前のボタンを生成
ObjectCreate(0,"button",OBJECT_BUTTON,0,00);
2、ボタンにテキストの文字を記述
ObjectString(0,"Button",OBJPROP_TEXT,"Button text");
3、ボタンのサイズを設定
ObjectSetInteger(0,"button",OBJPROP_XSIZE,100);
ObjectSetInteger(0,"button",OBJPROP_YSIZE, 20);
4、ボタンのポジションを設定
ObjectSetInteger(0,"button",OBJPROP_XDISTANCE,10);
ObjectSetInteger(0,"button",OBJPROP_YDISTANCE,10);
クラスを使用したときは
1、CChartObjectButtonクラスのオブジェクトの生成と、
ボタン変数へのポインタの割り当て
CChartObjectButton *button ;
button = new CChartObjectButton;
2、ボタンプロパテイを生成
幅=100、高さ=20、ポジション X=10、Y=10 (ピクセル)
button.
Creat(0,"button",0,10,10,100,20);
3、ボタンにテキストの文字を記述
button.Description("Button text");
クラスを使わないときと、クラスを使用したときを比べると、
クラスを使ったときの作業がよりシンプルで、
クラスオブジェクトは配列に保管(ストア)出来るので、操作が容易。
さらに、標準ライブラリクラスを使うので、
正確に、簡単に記述できる等の利点があります。
スネークゲーム 5
CArrayObjectクラスの特徴
標準ライブラリクラスCArrayObjectを使用することで、
繰り返し処理における、オブジェクトの、
配列への追加、削除、配列のサイズ変更など
の処理への信頼性を増すことが出来ます。
CArrayObjectクラスは
CObjectクラスタイプのオブジェクトの動的配列を組織化します。
CObjectクラスは標準ライブラリクラスの全ての親クラスです。
それは標準ライブラリクラスの、任意のクラスオブジェクトへ、
ポインタの動的配列を生成出来ることを意味します。
自分でクラスオブジェクトの動的配列を生成するとき、
CObjectクラスを継承する必要があります。
次の例はCObjectクラスを継承しているので、エラーはでません。
#include
class CMyClass : public CObject
{
//fields and methods
};
//CMyClassタイプのオブジェクトを生成し、my_obj変数の値へ、それを割り当てる。
CMyClass * my_obj = new CMyClass;
//オブジェクト ポインタ の動的配列を宣言
CArrayObj array_obj;
//arry_obj 配列の終わりで my_objオブジェクト ポインタを
//加える
arry_obj.Add(my_obj);
次の例はコンパイルのエラーになります。
#include
class CMyClass
{
//fields and methods
};
CMyClass * my_obj = new CMyClass;
arry_obj.Add(my_obj);
スネークゲーム 6
前回のsnake6の記述に誤りがありましたので、
もう一度記述致します。
CArrayObjectクラスの特徴
標準ライブラリクラスCArrayObjectを使用することで、
繰り返し処理における、オブジェクトの、
配列への追加、削除、配列のサイズ変更などの
処理への信頼性を増すことが出来ます。
CArrayObjectクラスは
CObjectクラスタイプのオブジェクトの動的配列を組織化します。
CObjectクラスは標準ライブラリクラスの全ての親クラスです。
それは標準ライブラリクラスの、任意のクラスオブジェクトへ、
ポインタの動的配列を生成出来ることを意味します。
自分でクラスオブジェクトの動的配列を生成するとき、
CObjectクラスを継承する必要があります。
次の例はCObjectクラスを継承しているので、エラーはでません。
#include
class CMyClass : public CObject
{
//fields and methods
};
//CMyClassタイプのオブジェクトを生成し、my_obj変数の値へ、それを割り当てる。
CMyClass * my_obj = new CMyClass;
//オブジェクト ポインタの動的配列を宣言
CArrayObj array_obj;
//arry_obj 配列の終わりで my_objオブジェクトポインタを
//加える
arry_obj.Add(my_obj);
次の例はコンパイルのエラーになります。
#include
class CMyClass
{
//fields and methods
};
CMyClass * my_obj = new CMyClass;
arry_obj.Add(my_obj);
ここまでは前回の訂正記事
----------------------------------
ここからは今回の記事
スネークゲームのプログラムを書くには
CArrayObjクラスのメソッドを使います。
Add
配列の終わりにエレメントを加える
Insert
配列の指定位置にエレメントを挿入する
Detach
指定位置のエレメントを消去(配列から削除)
At
指定位置のエレメント取得(配列から削除せず)
次はCArrayObjクラスの使用例です。
#include
class CMyClass : public CObject
{
public :
Char s ;
};
void MyPrint(ArrayObj *array_obj)
{
CMyClass *myobj;
for(int i=0 ; i{
//At 指定位置のエレメント取得
my_obj = arry_obj.At(i) ;
printf("%C",my_obj.s);
}
}
void OnInit()
{
CArrayObj *array_obj = new CArryObj();
CMyClass *my_obj ;
for(int i = 'a' ; i<='c' ; i++)
my_obj = new CMyClass();
my_obj.s = char(i);
//Add 配列の終わりにエレメントを加える
arry_obj.Add(my_obj);
MyPrint(array_obj);
my_obj = new CMyClass();
my_obj ='d';
//Insert 配列の指定位置にエレメントを挿入
my_obj.Insert(my_obj,1);
MyPrint(array_obj);
//Detach 指定位置のエレメントを消去
my_obj = array_obj.Detach(2);
MyPrint(array_obj);
delete array_obj;
return(0);
}
この例では、OnInit関数は3つの動的オブジェクトを生成
配列コンテンツのアウトプットはMyPrint関数の呼び出しによる動作をします。
Addメソッドを使用した配列ファイリングの後、そのコンテンツは(a,b,c)として
表示されます。
Insertメソッドの後、配列のコンテンツは(a,d,b,c)として表示されます。
最後のDetach メソッドの後、配列は(a,d,c)にロックされます。
deleteオペレータがarray_obj変数に対しして適用されると、CArrayObjの
デストラクタが呼び出され、array_obj配列の削除ばかりでなく、
ストアされたオブジェクトポインタも削除されます。
そして、CArrayObjクラスのメモリーマネジメントフラグはfalseにセットされます。
このフラグはFreeModeメソッドによりセットされます。
オブジェクトポインタの動的配列を削除するとき、ポインタが動的配列にストアされていて、
もしそのオブジェクトを削除する必要がないなら、次のコードを書く必要があります。
array_obj.FreeMode(false);
delete array_obj;
------------------------------------------------------------
今回からスネークというゲームプログラムを
取り上げて詳しく見ていきたいと思います。
標準ライブラリークラスの使い方、
ゲームのクラスの作り方、
そしてゲームプログラムの作り方を習得しましょう。
スネークゲームは1970年代中頃に作られたゲームで、
オーソドックスですが、ポピュラーなゲームです。
スネークゲームプログラムは
下記 MQL5のarticles/65にありますので、
各自ダウンロードしてください。
Creating a "Snake" Game in MQL5
https://www.mql5.com/en/articles/65
httpsページ最下部にある、
1.Attached files Download ZIP
あるいは
2.snake-mql5-doc.zip
3.snake_game_mql5_en.zip
をダウンロードします。
1は、2と3の両方が含まれているので、
1をダウンロードした方がいいでしょう。
ダウンロードした後、ZIPファイルを解凍し展開します。
ZIPファイルを右クリックすると、メニューが表示されます。
「すべて展開」を選択し、クリックします。
展開すると、
snake_game_mql5_en.zip
snake-mql5-doc.zip
ファイルが2つあります。
snake_game_mql5_en.zipを解凍します。
新しいフォルダーの中にファイルが解凍されます。
snake-mql5-doc.zipは使いませんが、
解凍しておくと良いでしょう
snake_game_mql5_enのフォルダーには、
Snake.mql5
Snake.mqh
のあるExpertsフォルダーと
body.bmp
square.bmpなどイメージファイルのある
Imagesフォルダーがあります。
解凍したファイルを、次はMeta editorに移動しますので、
アップデートMQL4を用意します。
古いMQL4は標準ライブラリークラスが有りませんので使えません。
この際古いMQL4はアップデートMQL4に変更しましょう。
MQL5は問題なく使えます。
Metaeditorを開きます。
MQL4左側ナビゲータのExpertsを選択し、
マウスを右クリックし、メニューを表示します。
「フォルダーを開く」をクリックします。
そこに先ほどの
Snake.mqhファイル
Snake.mql5ファイルを移動します。
イメージファイルはMQL4左側ナビゲータのImagesに移動します。
Imagesフォルダーを開き、そこにGamesフォルダーごと移動を行なっても大丈夫です。
Snake.mql5ファイルはそのままでは使えませんので、
*.mql4ファイルにコードを移動する必要があります。
新規作成 ー> エキスパートアドバイザー(テンプレート)から
プログラムのないSnake.mql4ファイルを作ります。
ファイルの中をすべて消去し、
Snake.mql5ファイルのプログラムをそこにコピーし、保存します。
Snake.mqhファイルと
body.bmp、square.bmpなどイメージファイルはそのまま使えます。
しかし、
Snake.mqhのプログラムを見ると、プログラムの上の方には、
#include
このVirtualKeys.mqhファイルは、
なぜかアップデートMQL4に有りません。
MQL5からもってくる必要があります。
MQL5からコピーしてIncludeフォルダーに置いて下さい。
(これが無いとスネークゲームが動きません。)
その後Snake.mql4をコンパイルします。
MT5ではゲームパネルの縦サイズは問題ありませんが、
MT4では少し長いので調整する必要がありますが、
それは次回に説明いたします。
(参考:以下のコードはVirtualKeys.mqhプログラム(途中省略)です。
標準ライブラリーのあるIncludeフォルダーにあります。
MQL5からコピーして、アップデートMQL4の同じ場所に持ってきます。)
/+------------------------------------------------------------------+
//| VirtualKeys.mqh |
//| Copyright 2009-2013, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link "http://www.mql5.com"
//+------------------------------------------------------------------+
//| Virtual keys copied from winuser.h |
//+------------------------------------------------------------------+
//
// Virtual Keys, Standard Set
//
#define VK_LBUTTON 0x01
#define VK_RBUTTON 0x02
#define VK_CANCEL 0x03
#define VK_MBUTTON 0x04
#define VK_XBUTTON1 0x05
#define VK_XBUTTON2 0x06
…
省略
…
#define VK_ATTN 0xF6
#define VK_CRSEL 0xF7
#define VK_EXSEL 0xF8
#define VK_EREOF 0xF9
#define VK_PLAY 0xFA
#define VK_ZOOM 0xFB
#define VK_NONAME 0xFC
#define VK_PA1 0xFD
#define VK_OEM_CLEAR 0xFE
--------------------------------------+
スネークゲーム 2
------------------------------------------------------------
スネークゲームは、市販のゲームのように複雑なものではなく、ごく簡単なものです。
ゲームのプログラミングで、図形、テキスト、ボタン等のチャートへの描き方、
イベントの処理の仕方を習得して行きたいと思います。
今回はパネルのサイズの修正からです。
アプリケーションはもともとMT5で使っていたコードなので、
アップデートMT4では少し大きすぎて、
コントロールパネルやステータスパネルが隠れしまいます。
このままでは、スタート、ストップなどのコントロールが出来ませんので、
サイズを調整します。
始めに、Snake.mqhファイルで調整します。
スネークの動き回る所はプレイングフィールドですが、
調整はこのフィールドを構成する各セルで行います。
Snake.mqhファイルのSQUARE_WIDTHとSQUARE_HEIGHTの値を変更します。
各セルは正方形で、長さの単位はpixelです。
変更前
#define SQUARE_WIDTH 20
#define SQUARE_HEIGHT 20
変更後
#define SQUARE_WIDTH 14
#define SQUARE_HEIGHT 14
変更後は、14 pixels にしています。
この数値以下にして下さい。
15以上にするとコントロールパネルが隠れてしまいます。
イメージファイルは
定義では以下のデイレクトリーです。
#define IMG_FILE_NAME_SQUARE "\\Images\\Games\\Snake\\square.bmp"
#define IMG_FILE_NAME_SQUARE で定義してあるデイレクトリーに
イメージファイルがあるか確認しておきましょう。
プレイングフィールドの縦の長さを変えるには、別の方法もあります。
Snake.mqhの定義に最後にある、
int game_level[][20][20]で、セルの縦の数を変更する事で行うことも出来ます。
詳細は省きますが、
game_level[][15][20]の3次元配列の、2番目の配列の要素数を15に変えます。
そして、正方形に並んだ数値の塊は6個あり、
それは各レベルのフィールドの初期状態を表示していますが、
正方形に並んだ数値の下から5行をそれぞれ削除します。
各正方形の中の9の数値は、障害物の位置を表しています。
1の数値はスネークの頭、2は胴体、3は尻尾の初期位置を表しています。
セルの大きさに戻りますが、
セルの大きさを14ピクセルにすると、
ステータスパネルの表示文字
Level: 0 of 5
Food left over 12
Live: 5
の右側が隠れてしまいますので、これも修正します。
修正は
Snake.mq4ファイルとSnake.mqhファイルで行います。
修正箇所はSnake.mq4はコードの始めの方にある、
#define spaces2
#define spaces6
#define spaces8
です。
表示文字の左端からの空白数を定義していますので、
ここで調整します。
spaces2はFood left over 12の表示、
spaces6はLevel: 0 of 5の表示、
spaces8はLive: 5 の表示に使われます。
spaces2は半角で2個の空白、spaces6は半角6個の空白、spaces8は半角8個の空白を意味しています。
以下のように、spaces2は半角で0個の空白、spaces6は半角2個の空白、spaces8は半角3個に調整します。
#define spaces2 ""
#define spaces6 " "
#define spaces8 " "
これでもまだ Food left over 12 の表示は隠れていまいますので、
#define FOOD_LEFT_OVER_EDIT_TEXTでの表示を
以下のように"Food rest: %u" に変えます。%uは非負整数を定義しています。
#define FOOD_LEFT_OVER_EDIT_TEXT "Food rest: %u"
スネークはフィールドの食べ物のベリーを食べて胴体が長くなっていく訳ですが、
"Food rest: %u"でベリーの残量を表示します。
さらに、ヘッダーパネル、コントロールパネル、ステータスパネルの横の長さを変更して
プレイイングフィールドの横の長さに合わせます。
以下のように、Snake.mqhファイルで飛び飛びに並んでいる定義を修正します。
変更前
#define CONTROL_WIDTH (COUNT_COLUMNS*(SQUARE_WIDTH-1)+1)/3
#define STATUS_WIDTH (COUNT_COLUMNS*(SQUARE_WIDTH-1)+1)/3
#define HEADER_WIDTH COUNT_COLUMNS*(SQUARE_WIDTH-1)+1
変更後
#define CONTROL_WIDTH (COUNT_COLUMNS*(SQUARE_WIDTH-1)+5)/3
#define STATUS_WIDTH (COUNT_COLUMNS*(SQUARE_WIDTH-1)+5)/3
#define HEADER_WIDTH COUNT_COLUMNS*(SQUARE_WIDTH-1)+3
パネルの大きさの修正は以上です。
次の修正は、スネークの動くスピードです。
SPEED_SNAKEを調整します。
#define SPEED_SNAKE 50
Sleep()関数を使用しているので、
数値が大きくなると遅くなります。
200くらいが適当でしょう。
#define SPEED_SNAKE 200
これでコンパイルします。
エラーが無かったら、OKです。
チャートにドロップインし、ゲームをして見ましょう。
スネークの方向変換は、キーボードの矢印キーで行います。
-----------------------------------------------------+
スネークゲーム 3
ゲームの概略
細部のプログラミングをやっていて、
ゲームの全体が見えなくったときは、
このゲームの概略に戻ってください。
自分でプログラミングするとき、
このような概略を作っておくと便利です。
1.ゲームタイトルは「Snake」よりなる。
2.コントロールパネルはスタート、ポーズ、ストップよりなる。
3.インフォメーションパネルはゲームのレベル、食べ物の残量、現在のライブ数よりなる。
4.スネークの動き回るフィールド(プレイングフィールド)は縦20個、横20個のセルよりなる。
5.スネークは緑色の頭、胴体、尻尾よりなる。
6.スネークの食べ物()がフィールドに置かれる。
7.スネークの灰色の障害物がフィールドに置かれる。
8.スネークは左右、上下に動く。胴体は頭の後について動き、尻尾は胴体の後について動く。
9.スネークが食べ物を食べる(スネークの頭が食べ物にぶつかる)と、胴体が1つ増える。
10.ゲームの各レベルは食べ物が12個あり、スネークが食べ物を食べるごとに減っていく。
11.スネークの胴体は1個から始まる。
12.スネークが食べ物を12個食べ、胴体が12個になると、次のレベルに移動する。
13.スネークが障害物にぶつかると、ライブ数が1つ減る。
14.ライブ数は0から5まである。ライブ数は、各レベルで5から始まる。
15.レベル0のゲームは、障害物はない。
16.スネークが障害物にぶつかると、各レベルのスタート地点に戻る。
17.ライブ数が0以下になると、スタート地点に戻り、レベルが1つ下がる。
ゲームプログラムの概要
1、インフォメーションパネル
Editタイプのオブジェクトで、
ゲーム中の食べ物の残りの数を知らせる。
Editタイプのオブジェクトは表示文字の編集が可能。
2、ゲームタイトル
Buttonタイプのオブジェクトで、表示は変える必要がない。
3、コントロールパネル
Buttonタイプのオブジェクトで、
Buttonタイプオブジェクトはボタンをクリックすることで、イベント処理を行う事が可能。
4.プレイングフィールド
BmpLabelのオブジェクトで、
BmpLabelオブジェクトはフィルド等イメージファイルを貼り付ける事が出来る。
5.すべてのオブジェクトはチャートの左側上部からの相対位置とし、
XピクセルとYピクセルの距離により位置を定義する。
6、スネークがプレイングフィールドの上下左右の端にきた時、
スネークは反対側の端に現れる。
7、スネークの頭の方向はスネークの動きの方向と同じ。
8、胴体の動きは頭の動きとは異なる。
9、尻尾の動きは最も近い胴体で決まる。
10、スネークがBerryを食べたときは、尻尾は動かず、
スネークの一番後の胴体があった場所に、新しく生成された胴体のエレメントが置かれる。
スネークの動作の3つの状態
1、方向に従った、頭の上下左右の1セルの移動
2、以前あった頭の位置へ胴体エレメントの移動
3、以前あった胴体の位置へ尻尾エレメントの移動
障害物にぶつかると、ゲームはスタート地点に戻る。
ゲームに使用するツール
(標準ライブラリークラスの使用)
1、CArrayObjectクラス
2、CChartObjectEditクラス、CChartObjectButtonクラス、CChartObjectBmpLabelクラス
CChartObjectEditクラスはインフォメーションパネルに使用。
CChartObjectButtonクラスはゲームタイトルとコントロールパネルに使用。
CChartObjectBmpLabelクラスはプレイングフィールド、スネーク、食べ物、障害物に使用。
CArrayObjectクラスはデータを組織化するためのクラスとして使用。
スネークゲーム 4
クラスを使わないときと、クラスを使用したとき
標準ライブラリーを使用するには
#includeを使いライブラリーをインクルードする必要があります。
例えば、
CChartObjectButtonオブジェクトを使うならば、
#include
と記述します。
ファイルパスはMQL5リファレンスでわかりますが、
MetaEditorナビゲータのIncludeフォルダでもわかります。
標準ライブラリーを使うとき、
大事なのは、継承関係を理解することです。
派生クラスが親クラスを継承しているとき、
派生クラスは、親クラスのプロパテイとメソッドを利用出来ます。
使い方を理解する為に、
標準ライブラリークラスを使用したときと、
使用しないときときを比べて見ます。
クラスを使わないときは
1、「butoon」という名前のボタンを生成
ObjectCreate(0,"button",OBJECT_BUTTON,0,00);
2、ボタンにテキストの文字を記述
ObjectString(0,"Button",OBJPROP_TEXT,"Button text");
3、ボタンのサイズを設定
ObjectSetInteger(0,"button",OBJPROP_XSIZE,100);
ObjectSetInteger(0,"button",OBJPROP_YSIZE, 20);
4、ボタンのポジションを設定
ObjectSetInteger(0,"button",OBJPROP_XDISTANCE,10);
ObjectSetInteger(0,"button",OBJPROP_YDISTANCE,10);
クラスを使用したときは
1、CChartObjectButtonクラスのオブジェクトの生成と、
ボタン変数へのポインタの割り当て
CChartObjectButton *button ;
button = new CChartObjectButton;
2、ボタンプロパテイを生成
幅=100、高さ=20、ポジション X=10、Y=10 (ピクセル)
button.
Creat(0,"button",0,10,10,100,20);
3、ボタンにテキストの文字を記述
button.Description("Button text");
クラスを使わないときと、クラスを使用したときを比べると、
クラスを使ったときの作業がよりシンプルで、
クラスオブジェクトは配列に保管(ストア)出来るので、操作が容易。
さらに、標準ライブラリクラスを使うので、
正確に、簡単に記述できる等の利点があります。
スネークゲーム 5
CArrayObjectクラスの特徴
標準ライブラリクラスCArrayObjectを使用することで、
繰り返し処理における、オブジェクトの、
配列への追加、削除、配列のサイズ変更など
の処理への信頼性を増すことが出来ます。
CArrayObjectクラスは
CObjectクラスタイプのオブジェクトの動的配列を組織化します。
CObjectクラスは標準ライブラリクラスの全ての親クラスです。
それは標準ライブラリクラスの、任意のクラスオブジェクトへ、
ポインタの動的配列を生成出来ることを意味します。
自分でクラスオブジェクトの動的配列を生成するとき、
CObjectクラスを継承する必要があります。
次の例はCObjectクラスを継承しているので、エラーはでません。
#include
class CMyClass : public CObject
{
//fields and methods
};
//CMyClassタイプのオブジェクトを生成し、my_obj変数の値へ、それを割り当てる。
CMyClass * my_obj = new CMyClass;
//オブジェクト ポインタ の動的配列を宣言
CArrayObj array_obj;
//arry_obj 配列の終わりで my_objオブジェクト ポインタを
//加える
arry_obj.Add(my_obj);
次の例はコンパイルのエラーになります。
#include
class CMyClass
{
//fields and methods
};
CMyClass * my_obj = new CMyClass;
arry_obj.Add(my_obj);
スネークゲーム 6
前回のsnake6の記述に誤りがありましたので、
もう一度記述致します。
CArrayObjectクラスの特徴
標準ライブラリクラスCArrayObjectを使用することで、
繰り返し処理における、オブジェクトの、
配列への追加、削除、配列のサイズ変更などの
処理への信頼性を増すことが出来ます。
CArrayObjectクラスは
CObjectクラスタイプのオブジェクトの動的配列を組織化します。
CObjectクラスは標準ライブラリクラスの全ての親クラスです。
それは標準ライブラリクラスの、任意のクラスオブジェクトへ、
ポインタの動的配列を生成出来ることを意味します。
自分でクラスオブジェクトの動的配列を生成するとき、
CObjectクラスを継承する必要があります。
次の例はCObjectクラスを継承しているので、エラーはでません。
#include
class CMyClass : public CObject
{
//fields and methods
};
//CMyClassタイプのオブジェクトを生成し、my_obj変数の値へ、それを割り当てる。
CMyClass * my_obj = new CMyClass;
//オブジェクト ポインタの動的配列を宣言
CArrayObj array_obj;
//arry_obj 配列の終わりで my_objオブジェクトポインタを
//加える
arry_obj.Add(my_obj);
次の例はコンパイルのエラーになります。
#include
class CMyClass
{
//fields and methods
};
CMyClass * my_obj = new CMyClass;
arry_obj.Add(my_obj);
ここまでは前回の訂正記事
----------------------------------
ここからは今回の記事
スネークゲームのプログラムを書くには
CArrayObjクラスのメソッドを使います。
Add
配列の終わりにエレメントを加える
Insert
配列の指定位置にエレメントを挿入する
Detach
指定位置のエレメントを消去(配列から削除)
At
指定位置のエレメント取得(配列から削除せず)
次はCArrayObjクラスの使用例です。
#include
class CMyClass : public CObject
{
public :
Char s ;
};
void MyPrint(ArrayObj *array_obj)
{
CMyClass *myobj;
for(int i=0 ; i
//At 指定位置のエレメント取得
my_obj = arry_obj.At(i) ;
printf("%C",my_obj.s);
}
}
void OnInit()
{
CArrayObj *array_obj = new CArryObj();
CMyClass *my_obj ;
for(int i = 'a' ; i<='c' ; i++)
my_obj = new CMyClass();
my_obj.s = char(i);
//Add 配列の終わりにエレメントを加える
arry_obj.Add(my_obj);
MyPrint(array_obj);
my_obj = new CMyClass();
my_obj ='d';
//Insert 配列の指定位置にエレメントを挿入
my_obj.Insert(my_obj,1);
MyPrint(array_obj);
//Detach 指定位置のエレメントを消去
my_obj = array_obj.Detach(2);
MyPrint(array_obj);
delete array_obj;
return(0);
}
この例では、OnInit関数は3つの動的オブジェクトを生成
配列コンテンツのアウトプットはMyPrint関数の呼び出しによる動作をします。
Addメソッドを使用した配列ファイリングの後、そのコンテンツは(a,b,c)として
表示されます。
Insertメソッドの後、配列のコンテンツは(a,d,b,c)として表示されます。
最後のDetach メソッドの後、配列は(a,d,c)にロックされます。
deleteオペレータがarray_obj変数に対しして適用されると、CArrayObjの
デストラクタが呼び出され、array_obj配列の削除ばかりでなく、
ストアされたオブジェクトポインタも削除されます。
そして、CArrayObjクラスのメモリーマネジメントフラグはfalseにセットされます。
このフラグはFreeModeメソッドによりセットされます。
オブジェクトポインタの動的配列を削除するとき、ポインタが動的配列にストアされていて、
もしそのオブジェクトを削除する必要がないなら、次のコードを書く必要があります。
array_obj.FreeMode(false);
delete array_obj;