星を降らせて擬似スクロール

背景のスクロールには様々な種類があるが、ここでは黒く塗りつぶした背景に星を降らせることにより、背景がスクロールしているように見せるプログラムを紹介する。

NKC_BackStar.cppの組み込み

一定時間ごとに星を降らすプログラムをソースファイルで用意したので、それを組み込んで利用する方法を紹介する。

1.ソースファイルの準備

NKC_BackStar.lzhをダウンロードして解凍すると「NKC_BackStar.cpp」「NKC_BackStar.h」が現れる。それをプロジェクトのフォルダに配置し、VCを開いて、プロジェクトに追加する作業を行う。

2.星画像ファイルの準備

星を降らせるので、星の画像ファイルを用意して、プロジェクトのフォルダに配置する。サンプルとしてstar.pngを用意したので、これを利用する。
今回は動作確認のため、32×32の大きさの画像を用意したが、実際は相当小さな画像にしたほうがよいだろう。

3.NKC_BackStar.cppの修正

用意する星画像ファイルによって、ファイル名や星の大きさが変わるため、NKC_BackStar.cppを修正する。修正する場所は次のとおり。

//=============================================================================
//  背景に星を降らせるスクリプト
//  Copyright NKC Game Staff(←自分の名前) 
//-----------------------------------------------------------------------------
#include "NKC_Common.h"

// マクロ
#define SCROLLMODE  1       // スクロールモード(1:縦スクロール 0:横スクロール)
#define STAR_WIDTH  32      // 星の幅
#define STAR_HEIGHT 32      // 星の高さ
#define STAR_MAX    50      // 描画する星の最大数
#define STAR_TIMING 200     // 新たな星が現れる間隔(ミリ秒)

// 構造体
typedef struct _STAR {
    TLVERTX Vertex[4];  // ポリゴン
    float mx, my;       // 移動量
    bool visible;       // 表示中かどうか
} STAR, *LPSTAR;

// グローバル変数
/* 他のソースからも利用されるもの */

/* 自ソースでのみ利用するもの */
static LPDIRECT3DTEXTURE8 gl_TXStar = NULL; // 星用テクスチャ
static STAR Star[STAR_MAX];     // 星データ
static DWORD gl_StarDrawTime;   // 星が生成された時間
static char* FileName1 = "star.png" // 星画像ファイル名

// プロトタイプ宣言
/* 自ソースでのみ使用するもの */
static void SetStarData(LPSTAR, float, float);

//-----------------------------------------------------------------------------
// 関数名 : InitStar()
// 機能概要: 初期化処理
//-----------------------------------------------------------------------------
void InitStar(void)
{
    HRESULT hr;
    char buff[80];
    int i;

    // 星用テクスチャの生成
    hr = D3DXCreateTextureFromFileEx(
        gl_lpD3ddev,
        FileName1,                      // ファイル名
        0,
        0,
        0,
        0,
        D3DFMT_A1R5G5B5,                // 色抜きを可能に
        D3DPOOL_MANAGED,
        D3DX_FILTER_LINEAR,
        D3DX_FILTER_LINEAR,
        D3DCOLOR_ARGB(255, 0, 0, 0),    // 透過色の指定(黒)
        NULL,
        NULL,
        &gl_TXStar                      // テクスチャ名
    );
    if ( FAILED(hr) ) {
        wsprintf(buff, "%s をテクスチャとして読み込めませんでした", FileName1);
        MessageBox(hWnd, buff, "ERROR", MB_OK);
        return;
    }

    // 星データの初期化
    for ( i=0 ; i < STAR_MAX ; i++ ) Star[i].visible = false;

    // 時間のクリア
    gl_StarDrawTime = gl_nowTime;

}
・
・
・

《解説》

スクロールモード(SCROLLMODE)
縦スクロール(星が上から下へ流れる)か横スクロール(星が右から左へ流れる)かを指定する。
星の幅と高さ(STAR_WIDTH、STAR_HEIGHT)
星画像の幅と高さを指定する。この値を元に、ポリゴンの大きさの設定などが行われる。
描画される星の最大数(STAR_MAX)
画面上に最大いくつの星を表示できるかを指定する。星の移動スピードと発生間隔を考慮し、なるべく小さな値にしたほうが良い。
星の出現間隔(STAR_TIMING)
星が出現する間隔をミリ秒で指定する。この値が大きいと星は少ししか描画されず、小さいと大量の星が描画される。
星画像ファイル名
星用テクスチャ作成時に読み込むファイル名を指定。
透明色
星画像の透明色を指定。

4.NKC_Common.hの修正

NKC_BackStar.cppを利用できるよう、NKC_Common.hからNKC_BackStar.hをインクルードする。

//-----------------------------------------------------------------------------
// 共通ヘッダ・ファイル
//  Copyright NKC Game Staff(←自分の名前) 
//-----------------------------------------------------------------------------
・
・
・
// 自作ソース・ファイルの組み込み
#include "NKC_DGraphics.h"
#include "NKC_Public.h"
#include "NKC_BackStar.h"
#include "Start.h"
#include "Game.h"
#include "Enemy.h"

5.乱数ジェネレーターの初期化

このプログラムは、ランダム関数(rand())を利用している。よって、基本プログラムに乱数ジェネレーターを初期化する処理がない場合は追加しておく。

//-------------------------------------------------------------------------------------------------
//      メイン関数(エントリーポイント)プログラムはここから始まる
//-------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode)
{
    MSG msg;		// メッセージ構造体変数
    HRESULT hr;

    //表示するウィンドウの定義、登録、表示
    if ( !InitApp(hThisInst, nWinMode) )	// InitApp関数を呼び出し、
        return (FALSE);						// 正常に終了すれば次にメッセージループへ

    // DirectX8の初期化
    hr = InitDX8();
    if ( FAILED(hr) ) return (FALSE);

    // 描画の設定
    InitRender();

    // 乱数ジェネレーターの初期化
    srand(timeGetTime());

    // ゲームループ
    while ( TRUE ) {
    // メッセージがあるかどうか
        if ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
            // メッセージを取得し、WM_QUITかどうか
            if ( !GetMessage(&msg, NULL, 0, 0) ) break;
            TranslateMessage(&msg);  //キーボード利用を可能にする
            DispatchMessage(&msg);  //制御をWindowsに戻す
        } else if ( g_appActive ) {
            // ゲームメイン処理
            if ( FAILED( UpdateFrame() ) ) break;
            Sleep(1);
        } else {
            WaitMessage();
        }
    }

    // DirectX8オブジェクトの削除
    ReleaseD3D();

    return msg.wParam;
}

6.確認

ここまでの修正を行ったら一度ビルドして、エラーが出ないことを確認する。

使い方

では実際に、星を降らせる処理を追加する方法を解説する。今回は、ゲーム画面において、星を降らせるようにする。

1.初期化処理

星を降らせるための初期化処理を行う。初期化処理はNKC_BackStar.cpp内に用意したInitStar()関数で行えるため、この関数を呼び出せばよい。
例えば次のように呼び出す。

//-----------------------------------------------------------------------------
// 関数名 : GameInit()
// 機能概要: ゲーム画面初期化処理
//-----------------------------------------------------------------------------
void GameInit(void)
{

    //--------------------------------------------------- 各変数の初期化
    // ゲーム画面で共通して使用するテクスチャの作成
    CreateGameTexture();
    // ポリゴンの初期化
    /* 背景 */
    InitStar();
    /* 自キャラ */
    InitVertex(MyChara.Vertex, 273.0f, 193.0f, 367.0f, 287.0f, 255);// 表示位置
    SetRect(&MyChara.HitRect, 10, 10, 10, 10);                   // 当たり判定矩形
    MyChara.MoveX = 2.0f;                                        // 移動量(X方向)
    MyChara.MoveY = 2.0f;                                        // 移動量(Y方向)

    //--------------------------------------------------- フレームナンバーセット
    g_FrameNo = GAME_FRAME;

}

2.背景描画処理

初期化をしたら、あとはゲーム画面処理において、星を背景として描画すればよい。星の描画処理はNKC_BackStar.cpp内に用意したDrawStar()関数で行えるため、この関数を呼び出せばよい。
例えば次のように呼び出す。

//-----------------------------------------------------------------------------
// 関数名 : GameFrame()
// 機能概要: ゲーム画面処理
//-----------------------------------------------------------------------------
void GameFrame(void)
{
    //--------------------------------------------------- 前処理

    //--------------------------------------------------- 描画
    DrawStar(); // 背景
    MyCharaDraw(); // 自機

    //--------------------------------------------------- 移動処理
    MyCharaMove(); // 自機

    //--------------------------------------------------- 当たり判定


#ifdef DEBUG
    //--------------------------------------------------- デバッグ用
    // F10を押したらスタート画面に戻る
    if ( gl_KeyTbl[VK_F10] & 0x80 ) {
        ReleaseGameTexture();
        g_FrameNo = START_INIT;
    }
#endif

}

3.背景開放処理

ゲーム終了時、星のテクスチャを開放しなければならない。星の開放処理はNKC_BackStar.cpp内に用意したReleaseStar()関数で行えるため、この関数を呼び出せばよい。
例えば次のように呼び出す。

//-----------------------------------------------------------------------------
// 関数名 : GameFrame()
// 機能概要: ゲーム画面処理
//-----------------------------------------------------------------------------
void GameFrame(void)
{
    //--------------------------------------------------- 前処理

    //--------------------------------------------------- 描画
    DrawStar(); // 背景
    MyCharaDraw(); // 自機

    //--------------------------------------------------- 移動処理
    MyCharaMove(); // 自機

    //--------------------------------------------------- 当たり判定


#ifdef DEBUG
    //--------------------------------------------------- デバッグ用
    // F10を押したらスタート画面に戻る
    if ( gl_KeyTbl[VK_F10] & 0x80 ) {
        ReleaseStar();
        ReleaseGameTexture();
        g_FrameNo = START_INIT;
    }
#endif

}

4.確認

以上の修正を行ったらビルド、実行し、ゲーム画面で星が表示されるかを確認する。

プログラム解説

このプログラムは非常にシンプルで、星の出現場所を乱数で決定し、一定時間ごとに出現させるだけである。背景として表示するので一切の当たり判定は必要なく、画面の外に出たら表示しない(visibleがtrueなら表示、falseなら非表示)ようにすることにより、配列を再利用している。

既存のプログラムにこのような処理を追加するのは容易であるが、いろんなゲームで使える技術であるため、あえて1つのソースにした。こうすれば、毎回プログラムしなおす必要がなくなるため、効率よくゲームを作成できる。
また、例えば星の流れるスピードを、早いものと遅いものを用意して、よりリアルに見せるといった改造も、ゲーム処理とは切り離して行うことができる。
ゲームに再開発や作り直しはつき物である。なるべく修正がしやすいように工夫しながらプログラミングを行おう。このようなプログラムを常に心がけると、デバッグだけではなく、仕様変更にも比較的柔軟に対応できるようになる。



NEXT(一枚絵を背景にしてスクロール)