DOBON.NET DOBON.NETプログラミング掲示板過去ログ

シューティングゲームの背景のスクロール

環境/言語:[Visual Studio 2005 / Visual C++ 2005 / Windows XP]
分類:[.NET]

いつもお世話になっています。
只今シューティングゲームを作成しているのですが、
背景をスクロールさせるコードを書いているのでが、下の通りにやると、
画面の点滅、および、例外エラーが発生してしまいます。

下は、ロード時に星を描画するコードです。

private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
// 背景描画処理 ここから
Bitmap^ img = gcnew Bitmap(320, 512);
Graphics^ gr = Graphics::FromImage(img);
//黒に塗りつぶす
gr->FillRectangle(Brushes::Black, gr->VisibleClipBounds);
// 星を描画 ここから
for (y = 0;y < img->Height - 1;y++) {
for (x = 0;x < img->Width - 1;x++) {
int x1 = random->Next(img->Width - 1);
int x2 = random->Next(img->Width - 1);
int x3 = random->Next(img->Width - 1);
if (x == x1) {
img->SetPixel(x,y,Color::Red);
}
else if (x == x2) {
img->SetPixel(x,y,Color::Yellow);
}
else if (x == x3) {
img->SetPixel(x,y,Color::Blue);
}
}
}
// 星を描画 ここまで
this->BackgroundImage = img;
// 背景描画処理 ここまで
}


ここまでは問題ないのですが、下が問題の背景をスクロールさせるコードです。
backgroundWorkerを使用してみました。

private: System::Void BackgroundMove_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
Bitmap^ img = gcnew Bitmap(320,512);
Bitmap^ bg = gcnew Bitmap(this->BackgroundImage);
Graphics^ gr = Graphics::FromImage(img);
gr->DrawImage(bg, 0, 1);
this->BackgroundImage = img;
Bitmap^ bmp = gcnew Bitmap(this->BackgroundImage);
for (int x = 0;x < bmp->Width;x++) {
Random^ random = gcnew Random();
int x1 = random->Next(bmp->Width - 1);
int x2 = random->Next(bmp->Width - 1);
int x3 = random->Next(bmp->Width - 1);
if (x == x1) {
bmp->SetPixel(x,0,Color::Red);
}
else if (x == x2) {
bmp->SetPixel(x,0,Color::Yellow);
}
else if (x == x3) {
bmp->SetPixel(x,0,Color::Blue);
}
else {
bmp->SetPixel(x,0,Color::Black);
}
}
this->BackgroundImage = bmp;
}

このスクロールさせるコードに問題があるのか、backgroundWorkerを使用しているのが問題なのか
また、背景をうまくスクロールさせる方法をどなたかご教授下さい。
回答、よろしくお願いします。
■No27027に返信(masaさんの記事)
スクロールさせるコードが書かれているようには見えません。
このサンプルコードでコンピュータに命令している内容を
説明してもらえませんか?
るしぇさん、コメントを追加して投稿し直します。



private: System::Void BackgroundMove_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
// 320*512(背景のサイズ)の画像を作成 (img)
Bitmap^ img = gcnew Bitmap(320,512);
// 今の背景を取得 (bg)
Bitmap^ bg = gcnew Bitmap(this->BackgroundImage);
Graphics^ gr = Graphics::FromImage(img);
// 今の背景をimgの0,1の地点に描画
gr->DrawImage(bg, 0, 1);
// 背景に設定(この時点で、画像の状態になります。)
this->BackgroundImage = img;
// 先ほど背景に設定した画像を取得 (bmp)
Bitmap^ bmp = gcnew Bitmap(this->BackgroundImage);
背景の上(1*320)は白なので、ランダムな位置に星(赤、黄、青)を描画、それ以外の場所は黒を描画
for (int x = 0;x < bmp->Width;x++) {
Random^ random = gcnew Random();
int x1 = random->Next(bmp->Width - 1);
int x2 = random->Next(bmp->Width - 1);
int x3 = random->Next(bmp->Width - 1);
if (x == x1) {
bmp->SetPixel(x,0,Color::Red);
}
else if (x == x2) {
bmp->SetPixel(x,0,Color::Yellow);
}
else if (x == x3) {
bmp->SetPixel(x,0,Color::Blue);
}
else {
bmp->SetPixel(x,0,Color::Black);
}
}
// 星を描画したものを背景に設定
this->BackgroundImage = bmp;
}
添付ファイル: 1278485585.png (10 KB)
■No27044に返信(masaさんの記事)
こちらもプロなので、メソッド単位の意味など見ただけで分かります。
それがサンプルコード全体でどんな動きをするかも想像は付きます。
その結果がスクロールさせるコードが書かれているようには見え
なかったということです。

ところが、masa さんはこのサンプルコードをスクロールさせるコード
だと言い、このスクロールさせるコードに問題があるのか分からないと
おっしゃいました。一つ一つのメソッドの動きを解説されましたので、
では、このサンプルコード全体がどういうコードなのか1文で説明して
ください。一つ一つのメソッドの動きを総合すると、どんな動きに
なりますか?
2010/07/07(Wed) 23:19:32 編集(投稿者)
2010/07/07(Wed) 20:19:04 編集(投稿者)

るしぇさん、返信ありがとうございます。
正確には、スクロールさせるコードというより、スクロールしているように見えるコードです。
このコードを実行すると、背景が1ドット下に移動し、一番上は空いてしまうので、ランダムに星を描画します。
これにより、画面が少しずつ下にずれていく、つまりスクロールしているようにみせているわけです。
ソースコードと実行ファイルを添付します。

添付した実行ファイルは、なかなかスクロールしません。
起動直後に例外が出たりします。何回か起動しなおすとスクロールします。
この現象を解決したいのですが・・・
添付ファイル: 1278501207.zip (28 KB)
■No27049に返信(masaさんの記事)

ざっとコードを拝見させていただいただけですので、間違ったことを言っていたら申し訳ありません。

コードを拝見させていただくと、タイマーを使っているわけでも、ループさせているわけでもないため、るしぇさんがおっしゃっているように、どのようにスクロールさせたいのかが全く分かりません。BackgroundMove_DoWorkメソッドが定期的に、何回も呼び出されることを期待していらっしゃるのだと思いますが、もしそうしたいのであれば、タイマーを使ってみてください。
添付されているファイルのコードをみると,実は別スレッドでwhile(true)で永久ループしているようです。
ただ,別スレッドでフォームのbackgroundimageを変更しようとしています。原則として別スレッドでUIの変更はできないと思います。
2010/07/09(Fri) 19:15:53 編集(投稿者)

すみません。コードにwhileを書き忘れていました。添付ファイルのように以下のコードになります。
private: System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
// 背景のスクロール処理(繰り返し)
while (true) {
Bitmap^ img = gcnew Bitmap(320,512);
Bitmap^ bg = gcnew Bitmap(this->BackgroundImage);
Graphics^ gr = Graphics::FromImage(img);
gr->DrawImage(bg, 0, 1);
for (int x = 0;x < img->Width;x++) {
Random^ random = gcnew Random();
int x1 = random->Next(img->Width - 1);
int x2 = random->Next(img->Width - 1);
int x3 = random->Next(img->Width - 1);
if (x == x1) {
img->SetPixel(x,0,Color::Red);
}
else if (x == x2) {
img->SetPixel(x,0,Color::Yellow);
}
else if (x == x3) {
img->SetPixel(x,0,Color::Blue);
}
else {
img->SetPixel(x,0,Color::Black);
}
}
this->BackgroundImage = img;
Application::DoEvents();
}
}

もしタイマで動作させた場合には、画面の点滅、例外は発生しないのですか?
> もしタイマで動作させた場合には、画面の点滅、例外は発生しないのですか?

試してみればよいのではと思ってしまいますが...

どのタイマかによりますが,System.Windows.Forms.Timerであれば問題あり
ません。

ただ,このままタイマにしても,画面がちらつくはずです。
DoubleBufferdについて調べてみてください。

また,毎回Randomをつくっているので星のならびに規則性が出てきそうです。
1つのRandomから乱数を得た方がよいと思います。

最後に,いらなくなった前の背景画像はDisposeした方が確実だと思います。
backgroundWorker1_DoWorkでループしていたのですね。申し訳ありませんでした。となると、このループを無くして、YASさんがおっしゃっているように、System.Windows.Forms.TimerでbackgroundWorker1_DoWorkを定期的に呼び出す感じになるのではないでしょうか。

もしちらつきを気にされるようでしたら、BackgroundImageプロパティを頻繁に変更するのではなく、Paintイベントですべて描画するようにした方が良いかもしれません。
2010/07/10(Sat) 16:32:26 編集(投稿者)

YASさん、管理人さん、回答ありがとうございます。
まず、フォームのDoubleBufferdプロパティをtrueにし、
backgroundWokerを削除し、タイマを設置しました。
以下がタイマの動作です。

private: System::Void backgroundMove_Tick(System::Object^ sender, System::EventArgs^ e) {
// 320*512の画像を作成(img)
Bitmap^ img = gcnew Bitmap(320,512);
// 背景を取得(bg)
Bitmap^ bg = gcnew Bitmap(this->BackgroundImage);
Graphics^ gr = Graphics::FromImage(img);
// bgをimgの1ドット下(0,1)に描画
gr->DrawImage(bg, 0, 1);
// bgの一番下(512*1)をimgに描画
gr->DrawImage(bg,0,-511);
// imgを背景に設定
this->BackgroundImage = img;
}

これで、画面のちらつきもなくなり、さらには目的のスクロールを達成することができました。
この方法なら、背景が星ではないときにも使用できます。
一応完成したファイルを添付しておきます。

回答していただいた るしぇさん、YASさん、管理人さん、ありがとうございました。
これで解決です。
添付ファイル: 1278747073.zip (28 KB)
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板