画像位置の管理、自弾の発射 など
演習26 画像の位置管理を中央座標に
・自機の位置を画像の中央座標で行うように変更しよう
・これに合わせて、画像、X座標、Y座標、左右方向の速度、表示状態を持つ構造体を定義する
struct Item {
public Image i; //画像
public int x; //中心X座標
public int y; //中心Y座標
public int hv; //左右方向の速度(左向きは負の数、右向きは正の数)
public int v; //表示状態(0:非表示、1以上:表示)
}
・自機の情報は(今度登場する各アイテムの情報も)この構造体で表そう
・これに合わせて、中心座標を用いて画像を描画するDrawItemメソッドを作り、その内部でe.Graphics.DrawImageメソッドを実行するように
しよう
private void DrawItem(PaintEventArgs e, Item it) {
xからit.i.Widthの半分を差し引いて左上X座標を得る
yからit.i.Heightの半分を差し引いて左上Y座標を得る
e.Graphics.DrawImage(it.i, 左上X座標, 左上Y座標);
}
・合わせてデータメンバを整理しよう
int gamemode = 0; //0:スタート画面、1:プレイ画面
int score = 0; //スコア
Image backi = Image.FromFile("backb.bmp"); //背景画像の読込
Image playeri = Image.FromFile("player.gif"); //自機画像の読込
Image playerl = Image.FromFile("playerl.gif"); //自機左寄画像の読込
Image playerr = Image.FromFile("playerr.gif"); //自機右寄画像の読込
Font font1 = new Font("メイリオ", 20, FontStyle.Bold); //フォントを生成(メイリオ20P太字)
Font fontt = new Font("メイリオ", 80, FontStyle.Bold); //フォントを生成(メイリオ80P太字)
Brush brushs = new SolidBrush(Color.Yellow); //ブラシを生成(黄色)
Timer timer = new Timer(); //タイマーを生成
int backy = 0; //背景画像のつなぎ目のY座標
//int playerx = 300; //【削除】自機のX座標
//int playerv = 0; //【削除】自機の左右移動量(0:停止,-1:左,1:右)
・合わせてMainメソッドも整理しよう
Program f = new Program(); //継承したフォームのインスタンスを生成
f.Size = new Size(660, 520); //インスタンスのSizeプロパティに高さと幅を代入
f.Text = "Game"; //インスタンスのTextプロパティにフォーム名を代入
f.ControlBox = false; //ControlBoxを非表示にする
f.FormBorderStyle = FormBorderStyle.Fixed3D; //フォームサイズ変更を禁止
Application.Run(f); //インスタンスを画面に出す
作成例
//演習26 画像の位置管理を中央座標に
using System; //フォームアプリケーションに必須
using System.Windows.Forms; //フォームアプリケーションに必須
using System.Drawing; //Image用
struct Item { //【追加】アイテムを表す構造体
public Image i; //画像
public int x; //中心X座標
public int y; //中心Y座標
public int hv; //左右方向の速度(左向きは負の数、右向きは正の数)
public int v; //表示状態(0:非表示、1以上:表示)
}
class Program : Form { //Formクラスを継承
[System.Runtime.InteropServices.DllImport("user32.dll")] //外部DLLのインポート
private static extern short GetKeyState(int nVirtKey); //メソッドの外部定義指定
int gamemode = 0; //0:スタート画面、1:プレイ画面
int score = 0; //スコア
Image backi = Image.FromFile("backb.bmp"); //背景画像の読込
Image playeri = Image.FromFile("player.gif"); //自機画像の読込
Image playerl = Image.FromFile("playerl.gif"); //自機左寄画像の読込
Image playerr = Image.FromFile("playerr.gif"); //自機右寄画像の読込
Font font1 = new Font("メイリオ", 20, FontStyle.Bold); //フォントを生成(メイリオ20P太字)
Font fontt = new Font("メイリオ", 80, FontStyle.Bold); //フォントを生成(メイリオ80P太字)
Brush brushs = new SolidBrush(Color.Yellow); //ブラシを生成(黄色)
Timer timer = new Timer(); //タイマーを生成
int backy = 0; //背景画像のつなぎ目のY座標
Item player; //【追加】プレイヤーの構造体オブジェクト
//int playerx = 300; //【削除】自機のX座標
//int playerv = 0; //【削除】自機の左右移動量(0:停止,-1:左,1:右)
//【以下追加】中心座標を用いて画像を描画
private void DrawItem(PaintEventArgs e, Item it) {
int xx = it.x - it.i.Width / 2; //幅の半分を差し引いて左上X座標を得る
int yy = it.y - it.i.Height / 2; //高さの半分を差し引いて左上Y座標を得る
e.Graphics.DrawImage(it.i, xx, yy);
}
protected override void OnPaint(PaintEventArgs e) { //Formのメソッドをオーバーライド
base.OnPaint(e); //まず、Formクラスにおけるメソッドの内容(基本再描画処理)を実行
e.Graphics.DrawImage(backi, 0, backy); //背景画像を(0,つなぎ目)から描画
e.Graphics.DrawImage(backi, 0, backy - backi.Height); //背景画像をその上に描画
if (gamemode == 0) { //スタート画面
e.Graphics.DrawString("GAME1", fontt, brushs, 100, 100); //タイトルの描画
e.Graphics.DrawString("Hit Enter to Start", font1, brushs, 200, 300); //メッセージの描画
} else if (gamemode == 1) { //プレイ画面
string s = String.Format("SCORE:{0:000,000}", score); //スコア文字列を編集
e.Graphics.DrawString(s, font1, brushs, 400, 10); //スコア文字列の描画
switch (player.hv) { //【変更】自機の向きによって分岐
case 0: player.i = playeri; break; //【変更】通常
case 1: player.i = playerr; break; //【変更】右寄
case -1: player.i = playerl; break; //【変更】左寄
}
DrawItem(e, player); //【追加】自機を表示
}
}
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) { //タイマーから呼ばれるメソッド
backy = (backy < backi.Height) ? backy + 1 : 0; //背景画像のつなぎ目を下げる
if (gamemode == 1) { //プレイ画面
player.hv = 0; //【変更】自機の向きを通常にする
if (player.x > playeri.Width / 2 && GetKeyState((int)Keys.Left) < 0)
{ //【変更】左端ではなく←キーが押されている?
player.x -= 10; //【変更】自機を左へ
player.hv = -1; //【変更】左に移動中
}
if (player.x < backi.Width - playeri.Width / 2 && GetKeyState((int)Keys.Right) < 0) { //【変更】右端ではなく→キーが押されている?
player.x += 10; //【変更】自機を右へ
player.hv = 1; //【変更】右に移動中
}
}
Invalidate(); //画面再描画を依頼する
}
Program() { //コンストラクタ
DoubleBuffered = true; //ダブルバッファリングの導入
KeyDown += new KeyEventHandler(OnKeyDown); //キーボードが押された時に呼ばれるメソッドを登録
timer.Tick += new EventHandler(Play); //タイマーから呼ばれるメソッドを登録
timer.Interval = 10; //タイマーの間隔
player.i = playeri; //【追加】自機の画像
player.x = 320; //【追加】自機のX座標
player.y = 410; //【追加】自機のY座標
player.hv = 0; //【追加】自機の左右方向の速度
}
static void Main() { //publicの指定は任意
Program f = new Program(); //継承したフォームのインスタンスを生成
f.Size = new Size(660, 520); //インスタンスのSizeプロパティに高さと幅を代入
f.Text = "Game"; //インスタンスのTextプロパティにフォーム名を代入
f.ControlBox = false; //ControlBoxを非表示にする
f.FormBorderStyle = FormBorderStyle.Fixed3D; //フォームサイズ変更を禁止
Application.Run(f); //インスタンスを画面に出す
}
}
演習27 自弾の表示(単独バージョン)
・ゲームモードが1(プレイ画面)の時に、スペースキーが押されたら自弾を出そう ・ただし、出現していないときに限る(まずは1個のみとする) ・出現位置は自機の位置で決まり、自機の直上とする ・自機はItem構造体で表す ・画像は下記を利用可能bullet.gif 20x20
手順と仕様
① 自弾画像をImage型変数bulletiに読込む ② 自弾の構造体オブジェクトpbを定義 ② 描画処理:プレイ画面で自弾があれば自弾を描画 ③ タイマーイベント処理:スペースキーが押されていて自弾が非表示なら表示にする。 また、画像を設定し、X座標は自機と同じに、Y座標は直上に触れる位置にする
作成例
//演習27 自弾の表示(単独バージョン)
using System; //フォームアプリケーションに必須
using System.Windows.Forms; //フォームアプリケーションに必須
using System.Drawing; //Image用
struct Item { //アイテムを表す構造体
public Image i; //画像
public int x; //中心X座標
public int y; //中心Y座標
public int hv; //左右方向の速度(左向きは負の数、右向きは正の数)
public int v; //表示状態(0:非表示、1以上:表示)
}
class Program : Form { //Formクラスを継承
[System.Runtime.InteropServices.DllImport("user32.dll")] //外部DLLのインポート
private static extern short GetKeyState(int nVirtKey); //メソッドの外部定義指定
int gamemode = 0; //0:スタート画面、1:プレイ画面
int score = 0; //スコア
Image backi = Image.FromFile("backb.bmp"); //背景画像の読込
Image playeri = Image.FromFile("player.gif"); //自機画像の読込
Image playerl = Image.FromFile("playerl.gif"); //自機左寄画像の読込
Image playerr = Image.FromFile("playerr.gif"); //自機右寄画像の読込
Image bulleti = Image.FromFile("bullet.gif"); //【追加】自弾画像の読込
Font font1 = new Font("メイリオ", 20, FontStyle.Bold); //フォントを生成(メイリオ20P太字)
Font fontt = new Font("メイリオ", 80, FontStyle.Bold); //フォントを生成(メイリオ80P太字)
Brush brushs = new SolidBrush(Color.Yellow); //ブラシを生成(黄色)
Timer timer = new Timer(); //タイマーを生成
int backy = 0; //背景画像のつなぎ目のY座標
Item player; //プレイヤーの構造体オブジェクト
Item pb; //【追加】自弾の構造体オブジェクト
//中心座標を用いて画像を描画
private void DrawItem(PaintEventArgs e, Item it) {
int xx = it.x - it.i.Width / 2; //幅の半分を差し引いて左上X座標を得る
int yy = it.y - it.i.Height / 2; //高さの半分を差し引いて左上Y座標を得る
e.Graphics.DrawImage(it.i, xx, yy);
}
protected override void OnPaint(PaintEventArgs e) { //Formのメソッドをオーバーライド
base.OnPaint(e); //まず、Formクラスにおけるメソッドの内容(基本再描画処理)を実行
e.Graphics.DrawImage(backi, 0, backy); //背景画像を(0,つなぎ目)から描画
e.Graphics.DrawImage(backi, 0, backy - backi.Height); //背景画像をその上に描画
if (gamemode == 0) { //スタート画面
e.Graphics.DrawString("GAME1", fontt, brushs, 100, 100); //タイトルの描画
e.Graphics.DrawString("Hit Enter to Start", font1, brushs, 200, 300); //メッセージの描画
} else if (gamemode == 1) { //プレイ画面
string s = String.Format("SCORE:{0:000,000}", score); //スコア文字列を編集
e.Graphics.DrawString(s, font1, brushs, 400, 10); //スコア文字列の描画
switch (player.hv) { //自機の向きによって分岐
case 0: player.i = playeri; break; //通常
case 1: player.i = playerr; break; //右寄
case -1: player.i = playerl; break; //左寄
}
DrawItem(e, player); //自機を表示
if (pb.v == 1) { //【以下追加】自弾がある?
DrawItem(e, pb); //自弾を表示
}
}
}
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) { //タイマーから呼ばれるメソッド
backy = (backy < backi.Height) ? backy + 1 : 0; //背景画像のつなぎ目を下げる
if (gamemode == 1) { //プレイ画面
player.hv = 0; //自機の向きを通常にする
if (player.x > playeri.Width / 2 && GetKeyState((int)Keys.Left) < 0)
{ //左端ではなく←キーが押されている?
player.x -= 10; //自機を左へ
player.hv = -1; //左に移動中
}
if (player.x < backi.Width - playeri.Width / 2 && GetKeyState((int)Keys.Right) < 0) { //右端ではなく→キーが押されている?
player.x += 10; //自機を右へ
player.hv = 1; //右に移動中
}
}
if (GetKeyState((int)Keys.Space) < 0) { //【以下追加】スペースキーが押されている?
if (pb.v == 0) { //自弾が非常時?
pb.v = 1; //表示にする
pb.i = bulleti; //画像を設定
pb.x = player.x; //X座標は自機の中心に合わせる
pb.y = player.y - player.i.Height / 2 - pb.i.Height / 2; //Y座標は自機の直上に合わせる
}
}
Invalidate(); //画面再描画を依頼する
}
Program() { //コンストラクタ
DoubleBuffered = true; //ダブルバッファリングの導入
KeyDown += new KeyEventHandler(OnKeyDown); //キーボードが押された時に呼ばれるメソッドを登録
timer.Tick += new EventHandler(Play); //タイマーから呼ばれるメソッドを登録
timer.Interval = 10; //タイマーの間隔
player.i = playeri; //自機の画像
player.x = 320; //自機のX座標
player.y = 410; //自機のY座標
player.hv = 0; //自機の左右方向の速度
}
static void Main() { //publicの指定は任意
Program f = new Program(); //継承したフォームのインスタンスを生成
f.Size = new Size(660, 520); //インスタンスのSizeプロパティに高さと幅を代入
f.Text = "Game"; //インスタンスのTextプロパティにフォーム名を代入
f.ControlBox = false; //ControlBoxを非表示にする
f.FormBorderStyle = FormBorderStyle.Fixed3D; //フォームサイズ変更を禁止
Application.Run(f); //インスタンスを画面に出す
}
}
提出:演習26または27(未完成でも可)
bullet.gif 20x20