:タイマー処理 など
テーマ24 タイマー処理
・画面を自動的に変更したり、一定時間おきに何かを行いたい場合、タイマーを用いることが出来る
・タイマーは、System.Windows.Forms.Timerクラスのデフォルトコンストラクタで生成できる
・このインスタンスメソッドTickイベントに、タイマーに呼び出して欲しいメソッドを登録する
・登録には、EventHandlerデリゲートを用いる
例:
Timer t = new Timer();
t.tick += new EventHandler(タイマーに呼び出して欲しいメソッド名);
・そして、インスタンスプロパティIntervalに、動作間隔をミリ秒で指定する
例:t.Interval = 20;
・それから、インスタンスメソッドStart()を呼ぶことでタイマーが動作する
・なお、タイマーに呼び出して欲しいメソッドは、戻り値型はvoid、引数型は(object, EventArgs)とすること・
※ 通常、メソッド内で引数を用いることはない
テーマ25 数値の形式指定文字列化
・WriteLineメソッドなどで使える{0}、{1}、…を用いた形式指定文字列化は、文字列の生成でも使える
・Stringクラスの静的メソッドFormatに、形式指定文字列を値や式を渡して、編集結果の文字列を得ることができる
・書式例: string s = String.Format("形式指定文字列", 値や式, …);
・例: string s = String.Format("{0}は{1}倍速い!", "シャア", 3); //文字列"シャアは3倍速い!"を得る
演習21 タイマーによるスコアアップ
・500ミリ秒ごとにスコアが1ずつ増えるようにしよう
・手順
① スコア用の変数 int score を0で初期化しておく
② スコア表示を変数scoreを用いるように変更する
③ タイマーから呼び出されるPlayメソッドを作成し、この中でscoreをインクリメントし、再描画する
④ タイマーを生成し、500ミリ秒ごとにPlayメソッドを呼び出すよう定義して、開始する
⑤ OnPaintメソッドにおけるスコアの表示に変数scoreを用いるように変更する(形式指定文字列を利用)
※ タイマーの生成はデータメンバの定義で行えばよい
※ タイマーのイベント登録とインターバルの設定はコンストラクタで行えばよい
※ タイマーのStartは、画面がプレイ画面に遷移する時に行えば良い
※ 画面のチラツキが発生するが、次の演習で解消する
作成例
//演習21 タイマーによるスコアアップ
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; //【追加】スコア
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, 0); //背景画像を(0,0)から描画
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++; //スコアアップ
Invalidate(); //画面再描画を依頼する
}
Program() { //コンストラクタ
KeyDown += new KeyEventHandler(OnKeyDown); //キーボードが押された時に呼ばれるメソッドを登録
timer.Tick += new EventHandler(Play); //【追加】タイマーから呼ばれるメソッドを登録
timer.Interval = 500; //【追加】タイマーの間隔
}
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); //インスタンスを画面に出す
}
}
テーマ26 ダブルバッファリング
・画面に動きがあるアプリケーションでは、画面の書き換えのタイミングのずれによりチラつきが起きる
・これを防ぐには、画像メモリを2重化し、描画を終えた画像メモリを表示用の画像メモリに一気に高速転送する
・この仕組みをダブルバッファリングという
・C#の.NETフレームワーク4.6以降のGDI+では(現行のVisualStudioでは)、System.Windows.Forms.Formクラスの
DoubleBufferedプロパティをtrueにすれば良い
演習22 ダブルバッファリングの導入
・コンストラクタでダブルバッファリングを導入しよう
作成例
//演習22 ダブルバッファリングの導入
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; //スコア
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, 0); //背景画像を(0,0)から描画
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++; //スコアアップ
Invalidate(); //画面再描画を依頼する
}
Program() { //コンストラクタ
DoubleBuffered = true; //【追加】ダブルバッファリングの導入
KeyDown += new KeyEventHandler(OnKeyDown); //キーボードが押された時に呼ばれるメソッドを登録
timer.Tick += new EventHandler(Play); //タイマーから呼ばれるメソッドを登録
timer.Interval = 500; //タイマーの間隔
}
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); //インスタンスを画面に出す
}
}
提出:演習22 ダブルバッファリングの導入