初心者のためのゲームプログラミング入門

プログラミングとゲームの杜

初心者のためのプログラミング入門 & ゲームプログラムの作り方入門

Visual C# 2019 入門

25.グラフィックで絵を描こう その2

 

今回は [ グラフィックで絵を描こう ] の続きです。

前回「グラフィックは奥が深い」と言いましたが、正確には「表示関連は奥が深い」という感じでしょうか。

色々な機能があることも理由の1つですが、実行する環境に左右されやすいところが奥深いです。

例えば「開発環境と違う PC で実行したら表示が崩れた」なんてよくある話です。
でもまぁ、初心者である今はあまり気にせず気楽にいきましょう。

 

 

PictureBox に絵を描こう

前回、絵を Form1 に直接描いていました。
ですが、絵を描くための専用コントロールがあるので使ってみましょう。

それでは、新しくプロジェクトを作成して
ツールボックスから PictureBox を Form1 に配置してください。
Form1 と PictureBox のサイズは下図のように調整してください。

 

picturebox を配置する

 

適当に広げたら pictureBox1 の BorderStyle プロパティを FixedSingle に変更します。

picturebox に枠線をつける

 

実行すると配置した pictureBox1 に枠線が描かれて表示されます。
これで PictureBox がどのように配置されているのか分かりますね。

 

picturebox に枠線を引く

 

 

それでは pictureBox1 に線を描いてみましょう。
前回の手順を思い出しながら作業してください。

 

picturebox に線を描く

 

 

実行してみて下さい。
赤い線が描かれましたか?
Form1 に線を描いたときと同じ手順でしたね。
四角や円を描く手順もまったく同じなので試してみましょう。

 

赤い線を描く

 

 

座標に注意しよう

前回覚えたことは PictureBox でも全て使えます。
ただ注意することは座標です。
原点(x=0, y=0)は PictureBox の左上なので、
線の始点が ( 0, 0 ) なら画像のようになります。

コントロールの左上が基点になる

 

それからもう1つ、コントロールからはみ出した部分は描画されません。
次のようにプログラムを変更して実行してみましょう。

 

コントロールからはみ出た部分は描画されない

 

pictureBox1.Width はを取得できます。
pictureBox1.Width -50
とは、pictureBox1 の右端から左に 50 ほどずれた位置となります。
円のサイズが(100, 100)なので、ちょうど半円だけ描画されます。

23行目では、変数 xx を宣言すると同時に値もセットしています。
このような方法もあるので覚えておきましょう。

 

 

ボタンに絵を描いてみよう

PictureBox は絵を描くためのコントロールですが、前回は Form1 に絵を描きました。
では、ボタン Button ではどうでしょうか?
試してみましょう。

PictureBox をすこし小さくしてボタンを配置してください。
そして、プログラムを変更して実行しましょう。

 

ボタンに絵を描く

 

 

ボタンにも絵が描けましたね。
おそらく、他にも絵が描けるコントロールはあると思います。
(試していませんが)

そんなことよりも、絵を描く手順が今までと違うことに気が付きましたか?
CreateGraphics に注目してください。

 

creategraphics を使って絵を描く

 

この方法を使えば、任意のコントロールに絵を描くことができます。
ただし、Paint イベント以外で使うと、再描画が必要なタイミングで絵が消えてしまうので気を付けましょう。

またこの例では、PictureBox の Paint イベントでボタン内の絵を描いてます。
つまり、ボタン部分だけ再描画が必要になったとき
絵は消えてしまいます。(PictureBox の Paint イベントが発生しないため)
この点も注意しましょう。

 

 

 

ボタンが押されたとき絵を描いてみよう

ボタンを押したら PictureBox に円を描く…
というプログラムを作ってみましょう。

デザイン編集画面で button1 をダブルクリックして button1_Click を作成します。
その中に下のプログラムを入力します。

 

ボタンが押されたとき絵を描く

 

 

実行してみましょう。
ボタンをクリックすると黄色の円が表示されます。

 

ボタンが押されたとき絵を描く

円が表示されている状態で、このウィンドウを隠してみてください。
黄色い円が消える時があります。(消えないこともあります)

エクスプローラーを起動したり、縮小化して戻すと消えることもあります。
条件は分かりませんが消えてしまうことがあるため、使うなら注意が必要です。

 

 

 

PictureBox の Image プロパティを使う

ボタンの Click イベント内で描画した絵は消えてしまいました。
消えない方法はないのでしょうか。

簡単なのは Paint イベント内で描画することです。
描画を On / Off する変数を用意して、Click イベント内で切り替えます。
そして On のときだけ Paint イベント内で描画するようにすればいいのです。
この方法は、これまで学習してきた内容を思い出せば簡単なことなので説明は省略します。

 

 

これから、別の方法を説明します。
その前に Paint イベントのプログラムは必要ないので削除しましょう。
イベントプロパティの欄から削除すると、イベントに書き込んだプログラムは削除されます。覚えておいてください。

 

paint イベントを削除する

 

 

それでは Paint イベントを使わない別の方法です。
これには PictureBox の Image プロパティを使います。
テストするため、下図のように button1_Click のプログラムを変更してください。

 

グラフィックが消えないようにする

 

実行したらボタンを押して、絵が描画されることを確認しましょう。
また、なにかでこの絵を隠してみてください。
隠したものを取り除いても、絵は消えていません。

 

この方法は PictureBox コントロールに直接絵を描かないで
Bitmap に描いた絵を Image プロパティに入れて表示しています
試しに 30 行目の
pictureBox1.Image = img;
をコメントにして実行してみて下さい。
ボタンを押しても描画されません。

23 行目、Bitmap オブジェクトを作成していますが、パラメータは幅と高さです。
これには描画先である pictureBox1 の幅と高さを指定しています。

 

 

ドット(点)で絵を描こう

これまで線や四角、円などの描画をしてきました。
最後にドットで線を描く方法を説明します。

先ほどのプログラムを下図のように変更しましょう。
Graphics を使わず Bitmap のみの操作になります。

 

ドットで線を描く

 

SetPixel ( x、y、色 )
これは指定の座標に色を付けます。
ドット単位で色を付けられるので、計算式を使ってグラフなども作れます。

ここでは使っていませんが、GetPixel ( x、y ) を使えば座標の色を取得できます。
ドット単位の操作にはどちらも活用できそうです。
ただ、注意も必要です。
Bitmap の範囲を超えて操作するとエラーになります。
例外処理を入れるか、はみ出さないように描く必要があります。
どちらにしても面倒ですね。

 

これまで絵を描くというテーマで説明してきましたが、
情報としては不十分だったかなと思います。
それは目的によって、適切な方法が違ってくるからです。
やっぱりサンプルとなるゲームがあって、作成手順を説明していく方が楽ですね。

 

 

メモリの使用量が気になるとき

ここから先の話は初心者向けではありません。
読み飛ばして次のページへいっても問題ないです。

ちょっとテストしてみてください。
先ほどのプログラムを実行して、ボタンを数回クリックします。
そのとき診断ツールに表示されているメモリの使用量を確認しましょう。

 

ボタンを押しながらメモリの増え方をチェックする

 

あきらかに少しずつ増加しています。
これはボタンをクリックするたび Bitmap オブジェクトを作成しているためです。

使っているメモリが増えるということは、あまり良いことではありません。
「アプリを使っていたら、いきなり落ちた」
なんて経験あると思います。
アプリが落ちる原因はいろいろありますが、その中でもメモリの使いすぎという理由はかなり多いと思います。
良いプログラムを作りたいのであれば、このような症状を作らないように注意する必要があります。

 

 

対処方法としては、再利用するとか、いらないものは破棄するなどがあります。
今回のプログラムを次のように変更してテストしてみましょう。
メモリの増加はほとんどなくなります。

 

古いリソースは破棄する

 

追加した部分は、クリックを2回以上したときに機能します。
過去に作られたものがあるなら、それを破棄しています。