:背景画面のスクロール、キーボードの状態を知る など
テーマ27 背景画像のスクロール
・背景画像を2枚用意して、1枚目の描画開始位置を少しずつずらし、空いた部分にもう1枚をつながるように描画すれば、 背景画像のスクロールが可能 ・なお、C#のGDI+では描画位置を示す座標を負の数や描画範囲外にできる。これにより、画像の一部を表示することが可能 ・画像全体が描画範囲の外になったら、描画対象から外すか、描画位置を変えると良い ・背景画像の縦スクロールの場合、描画開始位置が下端を超えたら0に戻すと良い ・背景画像は2枚になるが、画像オブジェクトは1つで良く、2つの参照変数で扱えば良い
演習23 背景画像の縦スクロール
・背景画像のつなぎ目のY座標を示す変数backyを0で初期化しておき、タイマーによってインクリメントする (背景画像.Heightを超えたら0に戻す) ・背景画像の描画を2回に増やし、(0, backy)からと、(0, backy - 背景画像.Height)から描画 ・タイマーのインターバルは10ミリ秒に変更すると良い
作成例
//演習23 背景画像の縦スクロール
using System; //フォームアプリケーションに必須
using System.Windows.Forms; //フォームアプリケーションに必須
using System.Drawing; //Image用
class Program : Form { //Formクラスを継承
Image backb = Image.FromFile("backb.bmp"); //背景画像の読込
Image enemy = Image.FromFile("enemy.gif"); //アイテム画像の読込
Image burn = Image.FromFile("burn.gif"); //効果用画像の読込
Pen mypen = new Pen(Color.Red, 2); //ペンを生成(初期値は赤、2)
Brush bred = new SolidBrush(Color.FromArgb(63, 255, 0, 0)); //ブラシを生成(赤の透明色)
Brush byel = new SolidBrush(Color.Yellow); //ブラシを生成(黄色)
Font f20 = new Font("メイリオ", 20, FontStyle.Bold); //フォントを生成(メイリオ20P太字)
Font f80 = new Font("メイリオ", 80, FontStyle.Bold); //フォントを生成(メイリオ80P太字)
int gamemode = 0; //0:スタート画面、1:プレイ画面
int score = 0; //スコア
int backy = 0; //【追加】背景画像のつなぎ目のY座標
Timer timer = new Timer(); //タイマーを生成
void DrawCircle(PaintEventArgs e, Pen p, int x, int y, int r) { //ペン、中心座標、半径を指定して円を描画
e.Graphics.DrawEllipse(p, x - r, y - r, 2 * r, 2 * r); //円の描画を呼ぶ
}
protected override void OnPaint(PaintEventArgs e) { //Formのメソッドをオーバーライド
base.OnPaint(e); //まず、Formクラスにおけるメソッドの内容(基本再描画処理)を実行
e.Graphics.DrawImage(backb, 0, backy); //【変更】背景画像を(0,つなぎ目)から描画
e.Graphics.DrawImage(backb, 0, backy - backb.Height); //【追加】背景画像をその上に描画
if (gamemode == 0) { //スタート画面
e.Graphics.DrawString("GAME1", f80, byel, 100, 100); //タイトルの描画
e.Graphics.DrawString("Hit Enter to Start", f20, byel, 200, 300); //メッセージの描画
} else if (gamemode == 1) { //プレイ画面
e.Graphics.FillRectangle(bred, 78, 411, 485, 64); //判定エリアを透明赤で塗りつぶす
e.Graphics.DrawRectangle(mypen, 78, 411, 485, 64); //判定エリアの描画
string s = String.Format("SCORE:{0:000,000}", score); //スコア文字列を編集
e.Graphics.DrawString(s, f20, byel, 400, 10); //スコア文字列の描画
}
}
void OnKeyDown(object o, KeyEventArgs e) { //キーボードが押された時に呼ばれるメソッド
if(e.KeyCode.ToString() == "Escape") { //Escキーが押されたら
Close(); //フォームアプリケーション終了
}
if(gamemode == 0 && e.KeyCode.ToString() == "Return") { //スタート画面でEnterキーが押されたら
gamemode = 1; //プレイ画面に切り替える
timer.Start(); //タイマー開始
Invalidate(); //画面再描画を依頼する
}
}
void Play(object o, EventArgs e) { //タイマーから呼ばれるメソッド
score++; //スコアアップ
backy = (backy < backb.Height) ? backy + 1 : 0; //【追加】背景画像のつなぎ目を下げる
Invalidate(); //画面再描画を依頼する
}
Program() { //コンストラクタ
DoubleBuffered = true; //ダブルバッファリングの導入
KeyDown += new KeyEventHandler(OnKeyDown); //キーボードが押された時に呼ばれるメソッドを登録
timer.Tick += new EventHandler(Play); //タイマーから呼ばれるメソッドを登録
timer.Interval = 10; //【変更】タイマーの間隔
}
static void Main() { //publicの指定は任意
Program p = new Program(); //継承したフォームのインスタンスを生成
p.Width = 660; //インスタンスのWidthプロパティに幅を代入
p.Height = 520; //インスタンスのHeightプロパティに高さを代入
p.Text = "Game"; //インスタンスのTextプロパティにフォーム名を代入
p.ControlBox = false; //ControlBoxを非表示にする
p.FormBorderStyle = FormBorderStyle.Fixed3D; //フォームサイズ変更を禁止
Application.Run(p); //インスタンスを画面に出す
}
}
テーマ28 キーボードの状態を得る
・キー入力イベントを用いる手法は「キーを押している間、〇〇する」には向かない
・代わりにタイマーイベントを用いてキーボードの状態を得る処理を呼び出してもらうと良い
・これを実現するには、WindowsAPIを提供するDLL(動的リンクライブラリ)の一つである「user32.dll」を直接インポートする
・インポートの書式: [System.Runtime.InteropServices.DllImport("user32.dll")] ※セミコロン不要
・すると、これに含まれるGetKeyStateメソッドを外部定義指定により利用可能になる
・外部定義指定の書式: private static extern short GetKeyState(int nVirtKey);
・これでGetKeyStateメソッドに引数としてKey列挙子をint型にキャストして与えると、そのキーが押されていれば負の数が返される
・インポートと外部定義指定はクラス定義の先頭で行うこと
演習24 上矢印キーが押されていたらスコアアップ
・上矢印キーのKey列挙子はKeys.Up ・これを用いて、Playメソッド内で、上矢印キーが押されているかチェックし、押されていたらスコアをインクリメントしよう
提出:演習23または24(未完成でもOK)