ブログ

勉強に役立つかもしれないゲームプログラミングPart3

 

みなさんこんにちは!武田塾垂水校の講師Iです。
前回はウィンドウの表示について書いたのですが、自分が伝え忘れてたこともあったりしてかなり長いこと書いてしまいました。
今回はそんな反省点を踏まえてなるべく短くまとめようと思います!
さてそんな今回ですが…画像の表示その1をやります!
その1って…画像の表示くらいパパっと出来るんじゃないの?と思う方もいるかもしれませんが、それを使用する際の注意点だったり必要な知識を詰め込んだりすると前回の二の舞になるので分けさせていただきました。
それでは前置きが長くなるのもあれなので早速進めていきましょう。

C言語で画像を扱う際の注意点

最初に画像を表示させる前に幾つか注意点を挙げさせていただきます。
とりあえず画面のスクショでも飯テロ画像でも好きな子の写真でも何でもいいので今回表示させたい画像を1つ用意してください。
ここで注意点1つ目!その画像データの拡張子を確認してください。
拡張子というのはデータの名前の後ろに付いている「.○○」ってやつです。
大体の場合「.jpeg」とか「.png」とか書いていると思いますがC言語で扱う際は拡張子が「.bmp」でないといけません。
もしかすると先述の2つでも出来る方法があるかもしれませんが多分bmpに変えた方が楽かと思います
という訳でbmp(ビットマップの略称)に変えるやり方ですが自分はペイントソフトを使っています。
もしMacにペイントソフトがなかったらごめんなさい…自分で調べてください…
ペイントを使うやり方では画像データを右クリック→プログラムで開く→ペイントをクリックするか、ペイントを開く→画像を開く→表示したい画像を探して開く、と言った感じでペイントで画像を開きます。
画像が開くことが出来たら後は簡単です。名前を付けて保存からbmpを選択するだけです。

TakedaBlogPart4_02TakedaBlogPart4_03

これでbmpで保存することが出来ます。
因みにbmpで保存するときにいろいろ設定できるのですが…特にいじらなくても大丈夫だと思います。この後表示させるときに不具合があったらそこをいじってみると直る…かもしれません。
まあこんな感じです。さっさと次行きましょ次。

そして注意点2つ目ですが画像の場所です。
visual studioでプログラミングを始めた際にソリューションの保存先を決めたと思いますが、そのフォルダ内にある自分が付けたプロジェクト名のフォルダの中に必ず入れましょう
ソリューションをどこに保存したか忘れた場合はエクスプローラーの右上にある検索バーで検索が出来ます。めっちゃ時間かかりますけど。
※下の画像のソリューション名やプロジェクト名は自分が「TakedaBlogProject」と付けただけなので
皆さんが付けたファイル名になっていたらOKです。
TakedaBlogPart4_05

出来ればプロジェクトのファイルの中で「ここには画像を入れるぞ!」ってフォルダを作ってその中に入れて置いておくとなお良しです。

TakedaBlogPart4_06

この画像専用フォルダを作るのは分かりやすさを重視した行為なので別にやらなくても良いと思います。
画像本体に関してはとりあえずこんな感じです。では次。

いよいよプログラミングで組み込む

そしていよいよプログラムコードを組み込んでいきますが、今回もコピペで結構です。(コピペ出来ない人がいたら申し訳ないけど手書きで…)

HDC hdc;
PAINTSTRUCT ps;
static HDC hMemDC;
static HBITMAP hPause;

hPause = (HBITMAP)LoadImage(
NULL,
"Resource\\pause.bmp",
IMAGE_BITMAP,
0, 0,
LR_LOADFROMFILE
);

if (hPause == NULL) {
MessageBox(NULL, "画像が読み込めませんでした", "エラー", MB_OK);
return 0;
}

hMemDC = CreateCompatibleDC(NULL);

hdc = BeginPaint(hWnd, &ps);

SelectObject(hMemDC, hPause);

BitBlt(
hdc,
0, 0,
CLIENT_W, CLIENT_H,
hMemDC,
0, 0,
SRCCOPY
);

EndPaint(hWnd, &ps);

これを前回のめちゃくちゃながったるいコードの「//ここにコードを書く」のすぐ下に貼り付けてください。
ただし今回はこのままで実行、という訳にはいきません。最低でも1つは手直しをしないといけないところがあります。
それは次の処理が書いているところです。

hPause = (HBITMAP)LoadImage(
NULL,
"Resource\\pause.bmp",
IMAGE_BITMAP,
0, 0,
LR_LOADFROMFILE
);

これは1番上にも「LoadImage」と書いている通り画像を読み込む処理です。
これの中身は割とどうでもいいので上から3行目のコードを見てください。
これを見て勘の良い人は気付くと思いますが.bmpという拡張子が付いてますね?
そうです。ここは読み込みたい画像の名前を入れるところなんですね。
ただ、自分が仮組みで入れたものが入っているのでそこを皆さんが先ほどプロジェクトのフォルダに入れた画像の名前を入れてください…
とここで注意点3つ目!画像用フォルダを作った人はどのフォルダに入っているのかを言ってあげないといけません!
じゃあそれをどうやってコンピュータに教えるのかという話ですが…ちゃんとそういう書き方があります。

(画像が入ってるフォルダの名前)\\(画像の名前)

これでコンピュータ側が「あ、このフォルダの中にあるこの画像を読み込めばいいんだな」と分かってくれる訳です。
これに似たようなものをエクスプローラーで見ることが出来るのですがさほど重要でもないのでそれに関しては割愛します。気になった人は探してみてください。

とりあえずこれで画像をウィンドウに出すことには成功したと思います。ビルドエラーを吐いたり「画像が読み込めませんでした」と表示されたりした場合は誤字を疑うか写真の保存形式の方をペイントでいじってみてください。
因みに文字列(””で囲まれた文章)に赤い波線が付いてる場合は初期設定が出来てないのでこれの1個前の記事を見てください。
エラーの処理方法についても今度記事にする予定(てかかなり大事だから次回やるかも)なのでそちらも見てください。

今回のコード解説

さて、ここからはこれを見ている全員が上のコードをコピペして動かせた前提で話していきます。
今回重要な点は大雑把に分けて…

・if文

・関数

の2つあります。
関数はいろんなことが出来るので全てを覚えきるのが難しい上に多分この記事で全部は教えられないので余裕があれば覚える程度でいいですが、if文に関しては簡単なうえにかなり重要なとこなのでif文だけでもしっかり覚えていってください!

めちゃくちゃ大事!分岐処理のif文

という訳でif文の解説です。
if文のifは「もし~なら」って感じの意味ですね。if文の意味もそれとほとんど同じです。

if( 条件 ) {
    条件を満たしていたら行う処理
}

こんな感じに書くと「()内の条件を満たしているなら{}内の処理を行う」という意味になります。
まあ細かいことを書くとちょっと難しい話になってきますが今回はこれと今から少し触る比較演算子ってものだけ知っていればいいです。
さて、今回のソースコードの中にもこのif文を使った部分がありますね。そこを見てみましょう。

if (hPause == NULL) {
MessageBox(NULL, "画像が読み込めませんでした", "エラー", MB_OK);
return 0;
}

ここの()内にある条件を見てください。「hPause == NULL」?なんじゃそりゃ?となると思います。
結論から言うと「hPause」は少し前に定義した変数、「NULL」が「何もない」という意味の定数、そしてそれらに挟まれている「==」が先ほど述べた比較演算子というものです。
先に比較演算子について説明しますと前後の変数または定数を比較してみてその演算子が成り立っていたらtrue(真)、そうでなかったらfalse(偽)を返す計算式みたいなものです。
比較演算子にはいろんな種類がありますが基本的には数学の不等式で使っていた等号不等号とほとんど一緒です
ここでの「==」(=のこと)や「!=」(≠のこと)等コンピュータ側の都合だったりで形が違うものもありますが、<と>と<=と>=は形もほぼそのままで使えます。(<=とかの場合=を後ろにしないといけない決まりはありますが)
ここだと「hPauseとNULL(何もない)が同じである」→「hPauseに何も入ってなければ」という条件になります。
そしてその条件を満たしていたら下に書いてるメッセージボックスがうんたらかんたらと書いてる処理を行う訳ですね。
まだif文の全てを語ったわけではないのですがとりあえずここでif文の説明は終わりにします。
もっと知りたい方は自分で調べるか今後がっつり解説記事も書く予定(いつになるかは未定)なのでそちらを見てください。

さり気なくめちゃくちゃ使ってる?関数

既に前回の二の舞になりかけてますが関数の解説です。
さて、関数と聞くとこの記事を見てるであろう誰もがf(x)=ax²+bx+cとかを思い浮かべると思いますが…まあやってることは割と一緒です。
関数とは、特定の動作を1つのコマンドにまとめたものです。
このソース内のLoadImageという関数を例に挙げると、「LoadImage(~)」のコマンド1つで特定の画像を読み込んでいる訳ですが本来ならもっと複雑な工程を踏んでるはずです。
ですがそれをいちいち書くのがめんどくさいですよね?場合によっては何回も使うのですから。
ならば先にコマンドとしてコンピュータに記憶させておいてコマンドの名前1つ書くだけで終わるようにしたらいいじゃないか!
と先人達は思って関数を作った、という訳です。
因みにこれ前回の記事でほんの少し触れたのですが…覚えてますか?
そう、ライブラリの解説で一瞬だけ存在をほのめかしましたね。ライブラリの中身はこの関数の説明だったり定数の定義だったりします。

とまあライブラリの真相に少しせまったところで関数の構造について軽くお話しします。
関数には引数(ひきすう)と返り値という2つの要素が一応あります
引数はその関数の外側から引っ張ってくる要素、返り値は関数を処理した後に残る1つの答えです。
数学の関数で言うと、y=f(x)においてyは関数f(x)を処理した時の答えなので返り値でxは関数f(x)に必要な引数です。
そう聞くとプログラミングにおける関数も数学の関数みたいな見た目してませんか?名前の後ろに()が付いていてその中に引数が入っているところはかなり似てますよね。

因みに上の説明で「一応」と付けてますけど引数や返り値がない関数もあります
え?ないってどういうこと?と思う人もいると思いますがそのまんまとしか言いようがないです。引数がない関数は引数なんて要らない処理を書いてる関数で、返り値がない関数は答えとして何も返す必要がない関数です。
引数がないパターンはともかく返り値がないパターンは今回のソース内にもあります。SelectObject関数やBitBlt関数がそうですね。
その辺りの関数と返り値のある関数(ここだとLoadImageやCreateCompatibleDC等)を見比べてみると、返り値のない関数はそれ単体で使われていて、返り値のある関数はその前に「=」が付いています。
これは返り値の有無による性質の違いですね。返り値がない関数はその関数内で完結しているため計算や代入の途中に組み込むことが出来ず単体で使用することになり、返り値がある関数はその関数内では完結していないため計算や代入の途中に組み込むことが出来るが単体では使用できません
英語で例えると返り値のない関数はS+Vみたいな1つの文章となっているのでそれだけ書いても文法的には問題ないけど、
返り値のある関数はOだけとかCだけみたいな1つの文章として成り立ってないのでこれとは別にSとVを用意してあげないとちゃんと意味が伝わらないよ、
って感じです。うん分かりづらいですねすみませんでした。
そして引数の有無に関してですが…この記事で説明すると長くなるので関数の中身を見始めるタイミングで解説しようと思います。
このシリーズとは別にちゃんと(?)解説する記事も書く予定なのでそちらも是非見て理解を深めてください。

最後に

いやあ結局前回の二の舞になってしまいました…(笑)
しかも当初の予定と違ってBitBltの説明出来てないんですよね…これを使いこなせてやっと画像の表示その1が終わるのに…。
まあ今回お堅い説明だけで終わってしまいましたが次回からこの知識(主に関数)の実践的な使い方について教えていきますので次の記事も是非見ていってください。
ここまで読んでくださりありがとうございました。

垂水校では無料受験相談を実施中


勉強でお悩みの受験生の方に向け

無料受験相談を実施しております。

「勉強方法が分からない」

「志望校の決め方が分からない」

「志望校合格に必要な勉強時間が知りたい」

など、お気軽にご相談下さい。

 

無料受験相談

あなたに合った勉強法を教えます!

無料受験相談に行ってみる