何もない(真っ黒や真っ白の)画面からだんだん背景やキャラクタが現れてくるのをフェードイン、逆をフェードアウトと呼ぶ。フェードアウトの場合、パレットに格納されている256色の色を、少しずつ黒または白にしていけば、最後には真っ黒または真っ白になる。
![]()
これをプログラムで行う方法を紹介する。
パレットの生成はDirectDraw初期化処理で行い、プライマリ・サーフェイスにセットしている。
LPDIRECTDRAWPALETTE g_pDDPal = NULL;
g_pDDPal = DDLoadPalette(g_pDD, ビットマップファイル名又はリソース名);
g_pDDSPrimary->SetPalette(g_pDDPal);パレット情報を好きなように加工するには、パレット情報を取得しなければならない。取得するには、GetEntries関数を使って次のように取得する。
PALETTEENTRY ape[256];
g_pDDPal->GetEntries(0, 0, 256, ape);これにより、ape配列にパレット情報が格納される。この配列内のデータを加工し、新たなパレットとしてプライマリ・サーフェイスにセットすると、加工後のパレット情報で画像が描画される。セットするにはSetEntries関数を使って次のように行う。
g_pDDPal->SetEntries(0, 0, 256, ape); ※SetEntriesを実行すると、プライマリ・サーフェイスのパレット情報が即座に書き換わるため、Flipの直前で行うのが望ましい
GetEntries関数で読み込んだパレット情報をどのように加工するとフェードイン・フェードアウトの効果を出せるのか?
サンプルプログラムを紹介する。《フェードインを行うサンプル》
PALETTEENTRY ape_w[256]; // 作業用 static int FadeCnt =0; // フェードの段階 int i; /* 加工後の情報を作業用配列に格納する */ for (i=0 ; i<256 ; i++) { ape_w[i].peRed = (BYTE)(ape[i].peRed * FadeCnt >> 8); ape_w[i].peGreen = (BYTE)(ape[i].peGreen * FadeCnt >> 8); ape_w[i].peBlue = (BYTE)(ape[i].peBlue * FadeCnt >> 8); ape_w[i].peFlags = (BYTE)0; }FadeCnt++; if (FadeCnt> 256) { FadeCnt =0; return 0; } /* パレット情報を入れ替える */ g_pDDPal->SetEntries(0, 0, 256, ape_w);※この処理を繰り返し行うことにより、少しずつフェードインしてくる
※フェードインが終わったとき、apeとape_wの内容は同じになる《フェードアウトを行うサンプル》
PALETTEENTRY ape_w[256]; // 作業用 static int FadeCnt =256; // フェードの段階 int i; /* 加工後の情報を作業用配列に格納する */ for (i=0 ; i<256 ; i++) { ape_w[i].peRed = (BYTE)(ape[i].peRed * FadeCnt >> 8); ape_w[i].peGreen = (BYTE)(ape[i].peGreen * FadeCnt >> 8); ape_w[i].peBlue = (BYTE)(ape[i].peBlue * FadeCnt >> 8); ape_w[i].peFlags = (BYTE)0; }FadeCnt--; if (FadeCnt<= 0) { FadeCnt =256; return 0; } /* パレット情報を入れ替える */ g_pDDPal->SetEntries(0, 0, 256, ape_w);※この処理を繰り返し行うことにより、少しずつフェードアウトする
※フェードアウトが終わると、ape_wの内容はすべて黒になる
ゲームに組み込む場合、
myDraw.cpp内にフェードイン・フェードアウトを行うための各変数と、処理を行う関数を用意するのが望ましい。
まずは変数の宣言を次のように行う。
//============================================================================= // DirectDraw関係の自作関数群 //============================================================================= ・ ・ ・ //----------------------------------------------------------------------------- // グローバル変数 //----------------------------------------------------------------------------- static LPDIRECTDRAWPALETTE g_pDDPal = NULL; // プライマリ・サーフェイス・パレット static char szStrBmp[] = "STRING.BMP"; // 文字列画像ファイル名 static char szBackBmp[4][16] = { // ゲーム画面背景画像ファイル名 "START1.BMP", /* スタート画面用 */ "BACK1.BMP", /* 1面用 */ "BACK2.BMP", /* 2面用 */ "BACK3.BMP" /* 3面用 */ }; static char szCharaBmp[] = "CHARA1.BMP"; // ゲーム画面キャラクタ画像ファイル名/* フェードイン・フェードアウト用 */static PALETTEENTRY ape[256]; // 保存用パレット情報static int FadeType, FadeCnt, FadeSpeed;次に、パレット情報を取り出す処理を追加する。どこで実行してもいいが、パレットの生成後に行うのが良いだろう。
//----------------------------------------------------------------------------- // 関数名 : InitializeDraw() // 機能概要: Direct Draw オブジェクトの生成 // 戻り値 : 正常終了のとき:DD_OK、異常終了のとき:エラーコード //----------------------------------------------------------------------------- HRESULT InitializeDraw(HWND hWnd) { ・ ・ ・ // パレットの生成 g_pDDPal = DDLoadPalette(g_pDD, szCharaBmp); if (g_pDDPal == NULL) return InitFail(hWnd, hRet, "DDLoadPalette FAILED");g_pDDPal->GetEntries(0, 0, 256, ape);// 現在有効となっているパレット情報の取得// プライマリ・サーフェイスにパレットを設定する hRet = g_pDDSPrimary->SetPalette(g_pDDPal); if (hRet != DD_OK) return InitFail(hWnd, hRet, "SetPalette FAILED"); ・ ・ ・次に、フェードイン・フェードアウトを行う関数をmyDraw.cpp内に作成する。
//----------------------------------------------------------------------------- // 関数名 : FadeInit() // 機能概要: フェードイン・フェードアウト処理の初期化を行う // 引数 : type:0ならフェードアウト、1ならフェードイン // speed:フェードイン・フェードアウトのスピード //----------------------------------------------------------------------------- void FadeInit(int type, int speed) { FadeType = type; if (type == 0) FadeCnt = 0; else FadeCnt = 256; FadeSpeed = speed; } //----------------------------------------------------------------------------- // 関数名 : FadeInOut() // 機能概要: フェードイン・フェードアウトを行う // 戻り値 : 処理の途中ならtrue、処理が終わったらfalseを返す //----------------------------------------------------------------------------- bool FadeInOut(void) { PALETTEENTRY ape_w[256]; int i; /* パレット情報を直接操作する */ for (i=0 ; i<256 ; i++) { ape_w[i].peRed = (BYTE)(ape[i].peRed * FadeCnt >> 8); ape_w[i].peGreen = (BYTE)(ape[i].peGreen * FadeCnt >> 8); ape_w[i].peBlue = (BYTE)(ape[i].peBlue * FadeCnt >> 8); ape_w[i].peFlags = (BYTE)0; } /* FadeTypeが0ならフェードイン、1ならフェードアウト */ if (FadeType == 0) { FadeCnt += FadeSpeed; if (FadeCnt > 256) return false; } else { FadeCnt -= FadeSpeed; if (FadeCnt <= 0) return false; } /* パレット情報を入れ替える */ g_pDDPal->SetEntries(0, 0, 256, ape_w); return true; } //----------------------------------------------------------------------------- // 関数名 : PaletteRollback() // 機能概要: パレット情報を元に戻す //----------------------------------------------------------------------------- void PaletteRollback(void) { g_pDDPal->SetEntries(0, 0, 256, ape); }※これらの関数は他のソースから呼び出すため、myDraw.hにプロトタイプ宣言をしなければならない
では実際に使ってみよう。第12章のプログラムを、ゲームクリア時にフェードアウトしてからスタート画面に戻るように変更する。
まず、ゲームクリア時初期化処理で、フェードアウトの初期化を行う。
//----------------------------------------------------------------------------- // 関数名 : GameClearInit() // 機能概要: ゲームクリア処理前初期化処理 //----------------------------------------------------------------------------- void GameClearInit(HWND hWnd) {FadeInit(1, 1); // フェードアウトさせるEndTime = nowTickCount; g_FrameNo = GAME_CLEAR; }※フェードアウトなので1つ目の引数を1にセット
※2つ目の引数はフェードイン・フェードアウトのスピードなので、1以上であればいくつでもよい次に、ゲームクリア処理でフェードアウト処理を次のように実行する。
//----------------------------------------------------------------------------- // 関数名 : GameClearFrame() // 機能概要: ゲームクリア処理 //----------------------------------------------------------------------------- void GameClearFrame(HWND hWnd) { HRESULT hRet; RECT rcRect; char str[80]; BackDraw(); // 背景描画処理 CharDraw(); // キャラクタ描画処理 /* メッセージ表示 */ SetRect(&rcRect, 200, 0, 570, 24); hRet = g_pDDSBack-'gt;BltFast(100, 100, g_pDDSChara, &rcRect, DDBLTFAST_SRCCOLORKEY); if (hRet != DD_OK) return; /* 経過時間を表示 */ wsprintf(str, "TIME %06d", EndTime - MyChara.StartTime); if (!StringDraw(str, 300, 300, 1)) return;/* フェードアウトしてから、スタート画面に戻る */if (!FadeInOut()){PaletteRollback(); // パレット情報を元に戻すg_FrameNo = START_INIT;return;}}以上の修正を行い、プログラムを実行する。ゲームクリア時にフェードアウトが行われ、真っ黒になってからスタート画面に戻るようになる。
※この処理では、スタート画面に戻る直前の1フレームだけ、ゲームクリア画面が表示されてしまう・・・が、今は気にしないこと
第12章で作ったプログラムに上記修正を行い、ゲームクリア時にフェードアウトが行われることを確認しなさい。
《実行結果サンプル》
サンプルプログラムはexeだけなので、実行するには同一フォルダにビットマップファイルが必要!!
上記プログラムを改造する。スターと画面はフェードインしてから「HIT SPACE KEY」が表示されるようにプログラムを修正しなさい。
《ヒント》
状態別処理なので、START_INITとSTART_FRAMEのほかにSTART_FADE_FRAMEを追加すると、考えやすい(使わなくても可)。
《実行結果サンプル》
サンプルプログラムはexeだけなので、実行するには同一フォルダにビットマップファイルが必要!!