「ゲームプログラミング/RPG」の版間の差分

削除された内容 追加された内容
→‎画像関係: バグが発生するが裏画面を複数の関数で受け渡しできる方法が見つかったので参考例として追記
822 行
== 画像関係 ==
=== 半透明のレイヤー合成を使いたい場合 ===
==== 概要 ====
たとえばRPGでは、戦闘に入ったときなど、マップ画面の上に半透明の黒レイヤーでマップをやや隠して、その上に戦闘画面の画像を描画したいような場合もあるかと思います。
 
844 ⟶ 845行目:
いろいろと対策しましょう。
 
==== 具体的な解決策 ====
 
半透明レイヤーを重ねるコードを書く際、どうコードを書けばいいかというと、答えは直感に反しますが、答えは、レイヤーで隠される画像側のプログラムのほうにコードを書くことになるかと思います。(隠す側の画像のプログラムではないのです。)
 
868 ⟶ 869行目:
 
=== Windowsによる画面消去 ===
半透明レイヤー合成に限らず、Windowsではプログラマーが画面クリアの命令を書いてなくても、OSがなんらかの理由で強制的にいったん画面クリアする場合があります。
 
典型的なのが、アプリをウィンドウ右上の最小化ボタンを押してタスクバーに格納すると、いったん画面が消去されてから、WM_PAINTを実行するという再描画が始まります。
890 ⟶ 891行目:
 
 
==== 方法1(非推奨) ====
;グローバル変数でも画像を保管できない
バグが発生しやすいので非推奨な方法ですが、もし異なる関数どうしで、裏画面(ダブルバッファ)用の画像を受け渡しする場合、下記のような方法で画像の受け渡しが一応は出来ます。しかし、他の画像関連の関数の描画時に原因不明のバグ画像が発生する事が多く、あまりオススメできないです。
なお、これとは別の方法を試みても、グローバル変数などで画像を保有する方法は、うまくいかないです。(標準c言語の文法どおりの仕様には、Windows APIの仕様は従っていないのです。)
 
参考前に、下記の方法を紹介しておきます。
 
たとえば、戦闘画面の背景にマップ画面を書く場合、コード例として下記
<syntaxhighlight lang="C">
// マップ描画側の関数
void map2_Draw(HDC hdc,HDC hbackDC) {
// hbackDC上で 画像の作成のコードを個々に書いておく
 
// ここにマップ描画の関数を書くが、本画面(hdc)に転送 BitBlt しないでおく
// BitBlt(hdc, 0, 0, 700, 500, hbackDC, 0, 0, SRCCOPY); // なのでコレはコメントアウト
}
 
 
void battle_Draw(HDC hdc) {
filterFlag = 1; // 背景にフィルターをかぶせるのでフラグのセット
 
static HDC hbackDC = CreateCompatibleDC(hdc); // 裏画面用のハンドル
map2_Draw(hdc, hbackDC);
 
BitBlt(hdc, 0, 0, 700, 500, hbackDC, 0, 0, SRCCOPY);
// ここまでマップ画面の記述
// 後略
</syntaxhighlight>
 
 
 
のようにすれば、一応は、異なる関数どうしで裏画面のデバイスコンテキストの受け渡しが出来ます。
 
つまり、呼び出しの戦闘関数側で、引数をhdcだけでなく、裏画面用の hbackDC も引数として含めて、
map2_Draw(hdc, hbackDC);
のような2引数以上の関数にして呼び出す必要があります。
 
また、このため、呼び出されるマップ側にも、引数として
void map2_Draw(HDC hdc,HDC hbackDC) {
のように引数を増やす必要があります。
 
 
このため、既存のマップ描画関数では引数がhdcの一つだけなので、そのままでは使いまわし出来ないです。よって、戦闘画面の背景用に書き換える必要があるので、なので既存の map1_Draw(HDC hdc) をコピーペーストして新しく map2_Draw(HDC hdc,HDC hbackDC) 関数を作らなければなりません。
 
このため、この方式では、あまりコード行数は減らないし、むしろ行数が増えます。
 
 
しかも、せっかく作ったコードなのに、実際にテストプレイしてみると、街頭の戦闘シーンだけは画像は正常に表示されるのですが、上述のコード例の場合、なぜか戦闘後のマップ移動画面がバグりました。
 
このwikiを書いた著者の戦闘画面の描画プログラムが単に欠陥なのか、それともwindowsの仕様上の問題があるのかは当wiki著者には分かりません。
 
ですが、どちらにしろ、上記の方式では、たとえ異なる関数どうしの間で裏画面の受け渡しが出来たとしても、デバッグやメンテナンスがかなり難しくなると予想されるので、なるべくこの方式は避けるほうが安全でしょう。
 
 
ネットでさらっと検索して調べてみても、この問題の対処法は全然見当たりません。ネット上にいるゲームプログラマー志望の皆さん、どうもここまで実験してないようです。
 
なので、前の節で述べたように、マップ側で本画面に転写するなど、裏画面を作成した関数の側で、本画面にも転写してしまうのが、バグが発生しないで安全です。
 
 
=== windowsでは出来ない事 ===
上述のような問題が発生する背景として、windowsでは下記のような、機能不足の仕様があるという理由があります。
 
 
;グローバル変数で画像を保管できない
なお、これとは別の方法を試みても、グローバル変数などで画像を保有する方法は、試みても、、うまくいかないです。(標準c言語の文法どおりの仕様には、Windows APIの仕様は従っていないのです。)
 
たとえば、あらかじめグローバル変数として(コード冒頭の部分の)グローバル領域で
904 ⟶ 968行目:
 
このようなWindowsAPIの非直感的な仕様のため、どうしても背景を複数のモードで使いまわしたい場合にはWindowsの場合、やむを得ず、CPUに負担は掛かってしまうのですが、結局は前の節で説明したように、関数などを用いて各モードごとに同じ描画をする方法しか、IT業界ですら、この関数の方法しか世間的にはよく知られていません。
 
 
;static でも保存できない