広告
↓発売日:2018年09月22日↓
新品価格 |
ちょっとさみしいコンソールプログラミングから直接こちらに来られた方の為に、せっかくDXライブラリを使っているので何か背景画像を表示したいと思います。
背景なんかいらないよ!という方はここは読み飛ばしていってください。
まずは今回のブロックパズル作りの土台のプログラムをご紹介します。
#include "DxLib.h" int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){ ChangeWindowMode(TRUE); DxLib_Init(); SetDrawScreen(DX_SCREEN_BACK); /*ここにプログラムを書いていきます*/ ScreenFlip(); WaitKey(); DxLib_End(); return 0; }
何も表示されないDxLibというウィンドウが現れれば成功です。
DXライブラリ、またはWin32アプリケーション初体験の方に少し説明しますと、まず今まで見慣れていたであろう「main()」が「WinMain()」というものに変わります。
それと一緒に「WinMain()」の戻り値、引数なども意味不明なモノに変わるのですが、ここのトコロは特に気にせず丸ごと覚えてしまいましょう。
そしてDXライブラリを使う為のいくつかの手順を踏みます。
ChangeWindowMode(TRUE);
表示されるプレイ画面を640×480のウィンドウ表示にします。
もちろん全画面表示にする事もできますのでもし興味ある方はDXライブラリのリファレンスを参考にしてみてください。
DxLib_Init();
DXライブラリを初期化します。
SetDrawScreen(DX_SCREEN_BACK);
グラフィック表示のチラつきをなくす為に裏画面に描画するという設定に変えます。
逆にこれをしないとグラフィックを表示する時にチラつきができます。
そしてその裏画面を目に見えるように表画面に反映させなきゃいけないので
ScreenFlip();
こちらの関数で表画面に裏画面を反映させます。
そしてこのままではプログラムが終了次第すぐにウィンドウが閉じてしまうので今回は「WaitKey()」というキー入力まで一時停止する関数で足止めをしてます。
DxLib_End();
DXライブラリを終了します。
これでDXライブラリを使う為の簡単な手順はおしまいです。
ここにゲームループなどを加えていろいろなゲームを作っていきます。
では説明はこのぐらいにしてさっそく画像を表示したいと思います。
まずはお好みの背景画像(640×480)を用意しましょう。
素晴らしき田園風景です!
そして用意したファイルを「back_img1.jpg」という名前でソースプログラムが置いてあるフォルダに置きます。
特別な設定をしなければたぶん
ドキュメント
↓
Visual Studio 2013
↓
Projects
↓
dxlib_sample(プロジェクト名)
↓
dxlib_sample(プロジェクト名)
これでソースプログラムが置いてあるフォルダにたどり着きます。
次はプログラムの方です。
まず画像用の変数を用意します。
int back_img1;
さきほどのファイル名と同じ名前ですがもちろん違う名前で大丈夫です。
画像ファイルですが「int」型で大丈夫です。
次にこの変数に実際の画像を読み込みます。
back_img1 = LoadGraph("./back_img1.jpg");
関数「LoadGraph("画像ファイルへのパス/画像ファイル名");」になります。
これで変数「back_img1」に先ほどの画像が読み込まれました。
後は表示するだけです。
いちよう座標の確認ですが
左上が(x0,y0)で右下が(x639,y479)になります。
それでは表示してみます。
DrawGraph(0,0,back_img1,TRUE);
関数「DrawGraph(左上のx座標,左上のy座標,画像の変数,TRUE)」になります。
画像の左上の角に合わせて指定した座標に画像を表示します。
最後の「TRUE」というのは画像の透明度を使う時は「TRUE」にするのですが基本的には「TRUE」のままで大丈夫です。
そしてこれらを先ほどのプログラムに追加すると・・・。
#include "DxLib.h" int back_img1; int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){ ChangeWindowMode(TRUE); DxLib_Init(); SetDrawScreen(DX_SCREEN_BACK); back_img1 = LoadGraph("./back_img1.jpg"); DrawGraph(0,0,back_img1,TRUE); ScreenFlip(); WaitKey(); DxLib_End(); return 0; }
背景がDXライブラリのウィンドウに現れました!
続けて壁とブロックを表示したいトコロですがその前にブロックパズル作りでよく使われる2重の「for」ループの動きの確認をしておきたいと思います。
for(y=0;y<4;y++){ for(x=0;x<4;x++){ } }
こちらが2重の「for」ループです。
ループの内側にループがありますね!
イメージとしては最初に内側のループを終わらせてから、外側のループを一つ進めるような感じになります。
これが慣れないとなかなかややこしいので実際にプログラムで動きを確認したいと思います。
int block[4][4] = { {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0} };
2重の「for」ループを使ってこちらのブロックを描いてみたいと思います。
次のプログラムを今は内容を気にせずにそのままコピーして実行してみてください。
一回一回入力待ちになるので何かキーを押してください。
#include "DxLib.h" int block[4][4] = { {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0} }; int Color_Red; int back_img1; int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){ ChangeWindowMode(TRUE); DxLib_Init(); SetDrawScreen(DX_SCREEN_BACK); Color_Red = GetColor(255,0,0); back_img1 = LoadGraph("./back_img1.jpg"); DrawGraph(0,0,back_img1,TRUE); for(int y=0;y<4;y++){ for(int x=0;x<4;x++){ DrawFormatString(x*20,y*20, Color_Red,"%d",block[y][x]); ScreenFlip(); WaitKey(); } } ScreenFlip(); WaitKey(); DxLib_End(); return 0; }
まずは内側のループで横一列を描きます。
0000
そして内側のループを終わらせて・・・。
↓
0000
0...
外側のループを一つ進めて再び内側のループに入る
なんとなく動きが確認できましたでしょうか?
2重以上のループは内側から外側のループへと移ります。
これを使って2次元配列をいろいろといじるので動きをイメージできるようにしておきましょう。
広告
さきほどのプログラムでもそうでしたが、2次元配列は左上が(0,0)でそこから右下方向に展開します。
たとえば「stage[23][18]」という2次元配列の場合は
左上が(0,0)、右下が(22,17)というように左上から右下にかけて展開していきます。
ここで気づかれた方いるかもしれませんが、これを「x,y」の座標で考えた時、普通は(x,y)の順番で座標を表しますが、当サイトでは2次元配列表記に合わせて(y,x)の順番で表記します。
それでは長らくお待たせしましたが、ようやく本題の壁とブロックを表示したいと思います。
「0」・・・何もない
「1」・・・ブロック
「9」・・・壁
を頭に入れておきましょう!
よく使う数字は定数化してしまいます。
/*ブロックの縦幅・横幅*/ #define BLOCK_HEIGHT 4 #define BLOCK_WIDTH 4 /*ステージの縦幅・横幅*/ #define STAGE_HEIGHT 23 #define STAGE_WIDTH 18 /*ブロック一つ分の幅*/ #define DRAW_BLOCK_WIDTH 20
ブロックの幅、ステージの幅などはよく登場するので定数化しました。
これをしておけば後でプログラムを確認する時や自分のオリジナリティを出すべくステージの拡張がしたい場合などにも便利ですね。
ループ用に使う変数などを除いて今回はできるだけわかりやすくするべく変数などはグローバルで宣言していきます。
int block[BLOCK_HEIGHT][BLOCK_WIDTH]; int stage[STAGE_HEIGHT][STAGE_WIDTH]; /*最初は四角いブロックのみ*/ int blocks[BLOCK_HEIGHT][BLOCK_WIDTH] = { {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0} }; /*ブロックの横位置*/ int block_x; /*ブロックの縦位置(内部計算用)*/ int block_y; /*ブロックの縦位置(表示用)*/ float block_y_count; /*色*/ int Color_Red; int Color_Black; /*画像*/ int back_img1;
ブロックの横位置と縦位置は
↓この左上の部分
0000
0110
0110
0000
の座標になります。
縦位置の内部計算用と表示用に分かれているのはまた後ほど説明いたします。
そして今回のブロックパズル作りによく使うDXライブラリの関数を紹介しておきます。
int Color_Red; Color_Red = GetColor(255,0,0);
色を設定する為の関数「GetColor()」になります。
「int」型の変数に指定した色を保存します。
GetColor(赤(0~255),緑(0~255),青(0~255))
みたいな感じで指定します。
DrawFormatString(0,0,Color_Black,"表示する文字");
指定した座標に文字を表示する為の「DrawFormatString()」になります。
DrawFormatString(x座標,y座標,色の指定,"表示する文字");
こんな感じで使います。
「printf()」みたいに「%d」などで変数の内容を表示する事も可能です。
ひとまずよく使う関数を2つ紹介しました。
あとはその都度説明しながらいきたいと思います。
まずは変数などを初期化していきます。
void my_init_var(){ int i,j; for(i=0;i<STAGE_HEIGHT;i++){ for(j=0;j<STAGE_WIDTH;j++){ stage[i][0] = 9; stage[i][1] = 9; stage[i][2] = 9; stage[20][j] = 9; stage[21][j] = 9; stage[22][j] = 9; stage[i][15] = 9; stage[i][16] = 9; stage[i][17] = 9; } } block_x = 7; block_y = 0; block_y_count = 0; Color_Red = GetColor(255,0,0); Color_Black = GetColor(0,0,0); back_img1 = LoadGraph("./back_img1.jpg"); }
「stage[23][18]」に壁の部分を作るべく左右、下を壁である「9」にします。
上の部分には、はみ出さないように重ねあわせるので壁は作りません。
あとはブロックの横位置、縦位置、色、画像などを設定して初期化は終わりです。
次にブロックを登録します。
void my_make_block(){ int x,y; for(y=0;y<BLOCK_HEIGHT;y++){ for(x=0;x<BLOCK_WIDTH;x++){ block[y][x] = blocks[y][x]; } } }
ブロックの元となる「blocks」からブロックをゲーム進行時のブロックの受け皿である「block」に移し替えます。
最初はわかりやすいように四角いブロックのみで話を進めていきます。
後半にブロックの元となる「blocks」でブロックの種類を増やして、ここでブロックをランダムに発生させていきます。
あとはこの「block[4][4]」と「stage[23][18]」を別々に画面に描いていきます。
一緒に描いても良いのですが、あとあとのラインクリア処理などの都合で別々に描きます。
まずはブロックです。
void my_draw_block(){ int x,y; for(y=0;y<BLOCK_HEIGHT;y++){ for(x=0;x<BLOCK_WIDTH;x++){ if(block[y][x] == 1)DrawFormatString(block_x * DRAW_BLOCK_WIDTH + x * DRAW_BLOCK_WIDTH, block_y_count + y * DRAW_BLOCK_WIDTH,Color_Red,"■"); } } }
「block[4][4]」を調べてブロックの部分「1」が出てきたら「■」に置き換えて表示します。
ちょっとだけ中身がややこしいので、余計な部分を整理して
if(block[y][x] == 1){ DrawFormatString(x * DRAW_BLOCK_WIDTH,y * DRAW_BLOCK_WIDTH, Color_Red,"■"); }
これがまず基本になります。
「DRAW_BLOCK_WIDTH」で決めた幅ずつブロックを描いていきます。
これだけでブロックのカタチは描かれますが、ブロックはx方向、y方向に移動しますのでその分を足し合わせます。
if(block[y][x] == 1){ DrawFormatString(block_x * DRAW_BLOCK_WIDTH + x * DRAW_BLOCK_WIDTH, block_y_count + y * DRAW_BLOCK_WIDTH,Color_Red,"■"); }
「block_x * DRAW_BLOCK_WIDTH」がx方向の移動分、「block_y_count」がy方向の移動分という事ですね。
これで移動分が反映されるのでここの値が変化すれば結果ブロックが動くというワケです。
このブロック移動分などを削除して表示するなりしてみるとわかりやすいかと思います。
続いてステージです。
void my_draw_stage(){ int x,y; for(y=0;y<STAGE_HEIGHT;y++){ for(x=0;x<STAGE_WIDTH;x++){ if(stage[y][x] == 1)DrawFormatString(x * DRAW_BLOCK_WIDTH, y * DRAW_BLOCK_WIDTH,Color_Red,"■"); else if(stage[y][x] == 9)DrawFormatString(x * DRAW_BLOCK_WIDTH, y * DRAW_BLOCK_WIDTH,Color_Black,"■"); } } }
同じように「stage[23][18]」を調べて壁の部分「9」が出てきたら「■」に置き換えて表示します。
ブロックの部分である「1」が出てきても置き換えて表示しておりますが、これは固定されたブロックの情報がこの後「stage[23][18]」にも保存されますのでこのようにしております。
メインです。
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){ ChangeWindowMode(TRUE); DxLib_Init(); SetDrawScreen(DX_SCREEN_BACK); my_init_var(); my_make_block(); my_draw_back(); my_draw_variable(); my_draw_block(); my_draw_stage(); ScreenFlip(); WaitKey(); DxLib_End(); return 0; }
今回はただ表示するだけなので今作った関数を並べるだけです。
「my_draw_back()」と「my_draw_variable()」は背景表示と変数の表示をしているだけなので説明は省かせて頂きます。
壁とブロックが表示できました!
最初はわかりやすいように全体を描画してますが次回以降は内側の部分だけを描いていきます。
背景描画、変数表示などの部分もそれぞれ
「my_draw_back()」
「my_draw_variable()」
という名前でメソッドわけしておりますので詳しくは中間ソースをご覧ください。
ここまでの中間ソースになります。
それでは次回は落下させてみたいと思います。
広告
↓発売日:2016年02月29日↓
12歳からはじめる ゼロからのC言語 ゲームプログラミング教室 新品価格 |
↓発売日:2018年06月22日↓
新品価格 |
↓発売日:2018年03月09日↓
新品価格 |
↓発売日:2017年06月14日↓
新品価格 |
↓発売日:2018年05月21日↓
新品価格 |
↓発売日:2017年12月07日↓
新品価格 |
↓発売日:2017年02月08日↓
新・明解C言語で学ぶアルゴリズムとデータ構造 (明解シリーズ) 新品価格 |
↓発売日:2017年09月26日↓
新品価格 |