文字列の描画(つづき)、画面遷移、など
提出フォロー:演習19 チェス盤を描こう・改
・木目の画像を用意してImageとして用いることで、リアルなチェス盤を描こう ・mokume0.png https://ha242.rundog.org/wp-content/uploads/2025/06/mokume0.png mokume1.png https://ha242.rundog.org/wp-content/uploads/2025/06/mokume1.png ・合わせて升目のサイズを50×50にしよう
作成例
//演習19 チェス盤を描こう・改
using System; //C#標準クラス用
using System.Windows.Forms; //Application、Formクラス用
using System.Drawing; //Size、Graphics、Image、Penクラス、Color構造体用
class Program : Form { //Formクラスの派生クラス
Image backi, playeri, chess0, chess1; //【変更】画像ファイル用変数
protected override void OnPaint(PaintEventArgs e) { //描画処理のオーバライド
base.OnPaint(e); //元のメソッドの内容を呼び出す
e.Graphics.DrawImage(backi, 0, 0); //画像をフォーム左上に配置
e.Graphics.DrawImage(playeri, backi.Width / 2 - playeri.Width / 2,
backi.Height - playeri.Height * 2); //自機を中央下部に描画
//Pen pCyan2 = new Pen(Color.Cyan, 2); //【削除】水色の太さ2のペンを生成
Brush bMokume0 = new TextureBrush(chess0); //【変更】木目テクスチャブラシ0を生成
Brush bMokume1 = new TextureBrush(chess1); //【変更】木目テクスチャブラシ1を生成
for(int i = 0; i < 8; i++) { //8列
for(int j = 0; j < 8; j++) { //8行
if ((i + j) % 2 == 0) { //1つおきに
e.Graphics.FillRectangle(bMokume0, 10 + i * 50, 20 + j * 50, 50, 50); //木目0
} else {
e.Graphics.FillRectangle(bMokume1, 10 + i * 50, 20 + j * 50, 50, 50); //木目1
}
}
}
}
public Program() { //コンストラクタ
try { //例外処理対象
backi = Image.FromFile("backb2.bmp"); //背景画像ファイルを読み込む
playeri = Image.FromFile("player.gif"); //自機画像ファイルを読み込む
chess0 = Image.FromFile("mokume0.png"); //【追加】チェス画像ファイル0を読み込む
chess1 = Image.FromFile("mokume1.png"); //【追加】チェス画像ファイル1を読み込む
} catch (Exception e) { //例外処理内容
MessageBox.Show(e.ToString()); //内容をメッセージボックスに表示
}
KeyDown += new KeyEventHandler(OnKeyDown); //キー押し下げ時のメソッドを登録
}
void OnKeyDown(object o, KeyEventArgs e){ //キー押し下げ時に呼ばれるメソッド
if (e.KeyCode.ToString() == "Escape") { //押されたキーのコードを文字列化したらEscape?
Close(); //フォームアプリケーションを終了
}
}
static void Main() { //実行用メソッド(publicはなくてOK)
Program f = new Program(); //自クラスのインスタンスを生成
f.Text = "Game"; //Form名を設定
f.StartPosition = FormStartPosition.Manual; //「手動設定」を設定
Point p = new Point(300,0); //X座標とY座標のPointインスタンスを生成
f.Location = p; //インスタンスプロパティで初期位置を設定
f.FormBorderStyle = FormBorderStyle.FixedSingle; //フォームサイズの固定化
f.ControlBox = false; //コントールボックスの非表示
f.ClientSize = new Size(640, 480); //クライアントサイズの幅と高さを指定
Application.Run(f); //生成済のインスタンスを実行
}
}
テーマ19 文字列の描画【再掲載】
・コンソールアプリケーションでは既定のフォントによりデバッグコンソールに文字列を表示している
・しかし、フォームアプリケーションでは画像などと同様にフォーム上に文字列を描画する
・よって、色や大きさに加えてフォントも指定できる
・文字列の描画にはDrawString()メソッドを用い、色の指定にはブラシを用いる
・フォントの指定にはSystem.Drawing.Fontクラスのオブジェクトを用いる
・Fontクラスには複数のコンストラクタがあるが、シンプルなのはFont("フォント名", ポイント数)
例: Font f = new Font("メイリオ", 15);
・DrawStringメソッドにブラシと左上座標、幅、高さを渡すことで矩形の塗りつぶしが可能
・書式例: e.Graphics.DrawString(文字列, フォント, ブラシ, 左上X座標, 左上Y座標);
演習20 チェス盤の下に文字列を描こう
・8×8の升目の下に「Game Start」という文字列を、フォントスタイル「メイリオ」、ポイント数「15」、太字、色「Cyan」で描こう
作成例
//演習20 チェス盤の下に文字列を描こう
using System; //C#標準クラス用
using System.Windows.Forms; //Application、Formクラス用
using System.Drawing; //Size、Graphics、Image、Penクラス、Color構造体用
class Program : Form { //Formクラスの派生クラス
Image backi, playeri, chess0, chess1; //画像ファイル用変数
protected override void OnPaint(PaintEventArgs e) { //描画処理のオーバライド
base.OnPaint(e); //元のメソッドの内容を呼び出す
e.Graphics.DrawImage(backi, 0, 0); //画像をフォーム左上に配置
e.Graphics.DrawImage(playeri, backi.Width / 2 - playeri.Width / 2,
backi.Height - playeri.Height * 2); //自機を中央下部に描画
Brush bMokume0 = new TextureBrush(chess0); //木目テクスチャブラシ0を生成
Brush bMokume1 = new TextureBrush(chess1); //木目テクスチャブラシ1を生成
for(int i = 0; i < 8; i++) { //8列
for(int j = 0; j < 8; j++) { //8行
if ((i + j) % 2 == 0) { //1つおきに
e.Graphics.FillRectangle(bMokume0, 10 + i * 50, 20 + j * 50, 50, 50); //木目0
} else {
e.Graphics.FillRectangle(bMokume1, 10 + i * 50, 20 + j * 50, 50, 50); //木目1
}
}
}
Font fm15 = new Font("メイリオ", 15, FontStyle.Bold); //【追加】フォントを生成
Brush bcyan = new SolidBrush(Color.Cyan); //【追加】シアン色のソリッドブラシを生成
e.Graphics.DrawString("Game Start", fm15, bcyan, 150, 420); //【追加】文字列を描画
}
public Program() { //コンストラクタ
try { //例外処理対象
backi = Image.FromFile("backb2.bmp"); //背景画像ファイルを読み込む
playeri = Image.FromFile("player.gif"); //自機画像ファイルを読み込む
chess0 = Image.FromFile("mokume0.png"); //チェス画像ファイル0を読み込む
chess1 = Image.FromFile("mokume1.png"); //チェス画像ファイル1を読み込む
} catch (Exception e) { //例外処理内容
MessageBox.Show(e.ToString()); //内容をメッセージボックスに表示
}
KeyDown += new KeyEventHandler(OnKeyDown); //キー押し下げ時のメソッドを登録
}
void OnKeyDown(object o, KeyEventArgs e){ //キー押し下げ時に呼ばれるメソッド
if (e.KeyCode.ToString() == "Escape") { //押されたキーのコードを文字列化したらEscape?
Close(); //フォームアプリケーションを終了
}
}
static void Main() { //実行用メソッド(publicはなくてOK)
Program f = new Program(); //自クラスのインスタンスを生成
f.Text = "Game"; //Form名を設定
f.StartPosition = FormStartPosition.Manual; //「手動設定」を設定
Point p = new Point(300,0); //X座標とY座標のPointインスタンスを生成
f.Location = p; //インスタンスプロパティで初期位置を設定
f.FormBorderStyle = FormBorderStyle.FixedSingle; //フォームサイズの固定化
f.ControlBox = false; //コントールボックスの非表示
f.ClientSize = new Size(640, 480); //クライアントサイズの幅と高さを指定
Application.Run(f); //生成済のインスタンスを実行
}
}
テーマ20 画面遷移
・タイトル画面とプレイ画面とゲームオーバー画面のように、画面が移り変わることを画面遷移という
・画面ごとに違うプログラムを用意して呼び出すこともあるが、プログラム内で「今はどの画面なのか」を変数で保持すればシンプルに記述できる
・この変数をゲームモードやシーン等と呼び、プログラム内で共有することで、画面遷移を見やすく記述できる
・ゲームモードやシーンに用いる値は列挙型にすると意味がわかりやすくなる
・構造例:
class クラス名 : Form { //Formクラスを継承
enum { TITLE, PLAY, OVER }; //タイトル画面、プレイ画面、ゲームオーバー画面
int ゲームモード = TITLE;
その他の初期化処理を記述
protected override void OnPaint(PaintEventArgs e) { //描画処理のオーバライド
全画面に共通の描画処理
ゲームモードがTITLEならばタイトル画面を描画
ゲームモードがPLAYならばプレイ画面を描画
ゲームモードがOVERならばゲームオーバー画面を描画
}
public static void Main() { //実行用メソッド
:
}
クラス名() { //コンストラクタ
:
}
キー押し下げ時に実行されるメソッド {
共通処理(Escキーが押し下げられたら終了)
ゲームモードがTITLEの時にEnterやSpaceキーが押し下げられたらゲームモードをPLAYに
ゲームモードがOVERの時にEnterキーが押し下げられたらゲームモードをTITLEやPLAYに
}
}
テーマ21 画面再描画
・プログラム側で画面を書き換えても、そのままでは実画面には反映しない ・そのため、画面再描画をシステムに依頼する必要がある(OnPaintの直接実行は不可) ・画面再描画をシステムに依頼するにはContolクラスの静的メソッドInvalidateを引数なしで呼べばよい(「Contol.」は省略可) ・書式:Invalidate(); //画面再描画を依頼
演習21 タイトル画面の表示とプレイ画面への遷移:次回
・テーマ20「画面遷移」の「構造例」を実装してタイトル画面の表示とプレイ画面への遷移を確認しよう ・タイトル画面は中央に「GAME」、中央下に「Hit Enter Key」と適当なフォントで表示 ・プレイ画面は中央に「START」と適当なフォントで表示 ※チェス盤、機体などの描画はいったん削除
提出:演習20 チェス盤の下に文字列を描こう