この章で使用するプログラムおよび画像ファイル(解凍すること)
これまでで、何とか機能別にソース分割ができた。しかし、関数の場所は確かにソースごとに管理できるようになったが、インクルードファイル、マクロ文、構造体、プロトタイプ宣言など、各ソースで行わなければならない作業が多く、また、面倒である。
ここでは、その面倒な作業を軽減する便利なテクニックを紹介する。
現在の各ソース・ファイルのヘッダ部分は次のようになっている。
//-------------------------------------------------------------------------------------------------
// 問題番号:Exer007
// 問題内容:ゲームを作りやすいプログラム
// Copyright NKC Game Staff(←自分の名前)
//-------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <windows.h> // WindowsAPIを使用可能にする
#include <windowsx.h>
#include <d3d8.h> // DirectX8ヘッダファイル
#include <d3dx8.h> // D3DXヘッダファイル
#include "NKC_DGraphics.h"
#include "Start.h"
#include "Game.h"
// マクロ
#define WINMODE FALSE // ウィンドウモードの指定(TRUE:ウィンドウモード/FALSE:フルスクリーン)
#define SCREEN_WIDTH 640 // ウィンドウの幅
#define SCREEN_HEIGHT 480 // ウィンドウの高さ
/* ゲームの状態を識別する(フレーム番号) */
#define START_INIT 0
#define START_FRAME 1
#define GAME_INIT 10
#define GAME_FRAME 11
/* 頂点フォーマット(基本形)*/
#define FVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
// 構造体の宣言
/* 頂点構造体 */
typedef struct _TLVERTEX {
float x, y, z; //位置情報
float rhw; //頂点変換値
D3DCOLOR color; //頂点カラー
float tu, tv; //テクスチャ座標
} TLVERTX, *LPTLVERTEX;
// グローバル変数
/* 他ソースも利用するもの */
HWND hWnd; // ウィンドウハンドル
BOOL g_appActive = FALSE; // ウィンドウの状態
BYTE g_FrameNo = START_INIT; // フレーム選択用
BYTE gl_KeyTbl[256]; // キーボードの状態を格納
RECT gl_rcScreen = {0, 0, 640, 480}; // ウィンドウ領域
/* 自ソースでのみ利用するもの */
static char szWinName[] = &Exer007&; // ウィンドウクラス用文字列
static char szWinTitle[] = &ゲームを作りやすいプログラム&; // ウィンドウクラス用文字列
// プロトタイプ宣言
/* 自ソースで宣言されているもの */
LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM); // Windows関数
BOOL InitApp(HINSTANCE, int); // ユーザー関数
BOOL UpdateFrame(void); // ゲームメイン処理
void InitVertex(LPTLVERTEX, float, float, float, float, int); // 頂点情報格納
void Move(LPTLVERTEX, float, float); // 移動処理
void MoveCheck(RECT, LPTLVERTEX); // 移動範囲の制限
bool HitCheck(LPTLVERTEX, LPTLVERTEX); // 当たり判定処理
bool HitCheck2(LPTLVERTEX, RECT, LPTLVERTEX, RECT); // 当たり判定用矩形を用いた当たり判定処理
//============================================================================= // DirectX Graphics関係の自作関数群 // Copyright NKC Game Staff(←自分の名前) //----------------------------------------------------------------------------- #include <stdio.h> #include <d3d8.h> // DirectX8ヘッダファイル #include <d3dx8.h> // D3DXヘッダファイル #include "NKC_DGraphics.h" // マクロ #define WINMODE FALSE // ウィンドウモードの指定(TRUE:ウィンドウモード/FALSE:フルスクリーン) #define SCREEN_WIDTH 640 // ウィンドウの幅 #define SCREEN_HEIGHT 480 // ウィンドウの高さ // グローバル変数 /* 他のソースで宣言されているもの */ extern HWND hWnd; // ウィンドウハンドル /* 他のソースからも利用されるもの */ LPDIRECT3DDEVICE8 gl_lpD3ddev = NULL; // Direct3DDevice8インターフェイス LPDIRECT3DTEXTURE8 gl_TXBack = NULL; // 背景用テクスチャ LPDIRECT3DTEXTURE8 gl_TXMyChara = NULL; // 自機用テクスチャ LPDIRECT3DTEXTURE8 gl_TXEnemy = NULL; // 敵用テクスチャ /* 自ソースでのみ利用するもの */ static LPDIRECT3D8 gl_lpD3d = NULL; // Direct3D8インターフェイス static D3DPRESENT_PARAMETERS gl_d3dpp; // ディスプレイパラメータ // プロトタイプ宣言 /* 自ソースでのみ使用するもの */
//=============================================================================
// スタート処理関係の自作関数群
// Copyright NKC Game Staff(←自分の名前)
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <windows.h> // WindowsAPIを使用可能にする
#include <windowsx.h>
#include <d3d8.h> // DirectX8ヘッダファイル
#include <d3dx8.h> // D3DXヘッダファイル
#include "NKC_DGraphics.h"
#include "Start.h"
// マクロ
/* ゲームの状態を識別する(フレーム番号) */
#define START_INIT 0
#define START_FRAME 1
#define GAME_INIT 10
#define GAME_FRAME 11
/* 頂点フォーマット(基本形)*/
#define FVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
// 構造体の宣言
/* 頂点構造体 */
typedef struct _TLVERTEX {
float x, y, z; //位置情報
float rhw; //頂点変換値
D3DCOLOR color; //頂点カラー
float tu, tv; //テクスチャ座標
} TLVERTX, *LPTLVERTEX;
// グローバル変数
/* WinMain.cppで宣言されているもの */
extern HWND hWnd; // ウィンドウハンドル
extern BYTE g_FrameNo; // フレーム選択用
extern BYTE gl_KeyTbl[256]; // キーボードの状態を格納
extern RECT gl_rcScreen; // ウィンドウ領域
/* 自ソースでのみ利用するもの */
static TLVERTX BackVertex[4]; // 背景用頂点情報配列
// プロトタイプ宣言
/* WinMain.cppに存在し、Start.cppから呼び出す関数 */
void InitVertex(LPTLVERTEX, float, float, float, float, int); // 頂点情報格納
/* 自ソース(Start.cpp)内でのみ利用するもの */
//=============================================================================
// ゲーム処理関係の自作関数群
// Copyright NKC Game Staff(←自分の名前)
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <windows.h> // WindowsAPIを使用可能にする
#include <windowsx.h>
#include <d3d8.h> // DirectX8ヘッダファイル
#include <d3dx8.h> // D3DXヘッダファイル
#include "NKC_DGraphics.h"
#include "Game.h"
// マクロ
/* ゲームの状態を識別する(フレーム番号) */
#define START_INIT 0
#define START_FRAME 1
#define GAME_INIT 10
#define GAME_FRAME 11
/* 頂点フォーマット(基本形)*/
#define FVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
// 構造体宣言
/* 頂点構造体 */
typedef struct _TLVERTEX {
float x, y, z; //位置情報
float rhw; //頂点変換値
D3DCOLOR color; //頂点カラー
float tu, tv; //テクスチャ座標
} TLVERTX, *LPTLVERTEX;
// グローバル変数
/* WinMain.cppで宣言されているもの */
extern HWND hWnd; // ウィンドウハンドル
extern BYTE g_FrameNo; // フレーム選択用
extern BYTE gl_KeyTbl[256]; // キーボードの状態を格納
extern RECT gl_rcScreen; // ウィンドウ領域
/* 自ソースでのみ利用するもの */
static TLVERTX BackVertex[4]; // 背景用頂点情報配列
static TLVERTX MyCharaVertex[4]; // 自機用頂点情報配列
static TLVERTX EnemyVertex[4]; // 敵用頂点情報配列
static RECT MyCharaHitRect; // 自機用当たり判定矩形
static RECT EnemyHitRect; // 敵機用当たり判定矩形
// プロトタイプ宣言
/* WinMain.cppに存在し、Game.cppから呼び出す関数 */
void InitVertex(LPTLVERTEX, float, float, float, float, int); // 頂点情報格納
void Move(LPTLVERTEX, float, float); // 移動処理
void MoveCheck(RECT, LPTLVERTEX); // 移動範囲の制限
bool HitCheck(LPTLVERTEX, LPTLVERTEX); // 当たり判定処理
bool HitCheck2(LPTLVERTEX, RECT, LPTLVERTEX, RECT); // 当たり判定用矩形を用いた当たり判定処理
/* 自ソース(Game.cpp)内でのみ利用するもの */
これらをよく見ると、多少の違いはあるが、かなりの部分で同じ記述を行っていることが分かる。ということは、共通部分を1つのヘッダ・ファイルにまとめ、そのヘッダ・ファイルをすべてのソース・ファイルからインクルードすれば、メンテナンスが容易になることが想像できる。
では実際に、(4)までに作成したプログラムに共通ヘッダ・ファイルを作成し、すべてのソースから利用する方法を紹介する。ダウンロードしたプログラムが正常に動作することを確認しておくこと。
各ソースから、共通部分を抜き出し、共通ヘッダ・ファイル(NKC_Common.h)に配置する(プロジェクトの追加で新規作成)。
//-----------------------------------------------------------------------------
// 共通ヘッダ・ファイル
// Copyright NKC Game Staff(←自分の名前)
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <windows.h> // WindowsAPIを使用可能にする
#include <windowsx.h>
#include <d3d8.h> // DirectX8ヘッダファイル
#include <d3dx8.h> // D3DXヘッダファイル
// マクロ
#define WINMODE FALSE // ウィンドウモードの指定(TRUE:ウィンドウモード/FALSE:フルスクリーン)
#define SCREEN_WIDTH 640 // ウィンドウの幅
#define SCREEN_HEIGHT 480 // ウィンドウの高さ
/* ゲームの状態を識別する(フレーム番号) */
#define START_INIT 0
#define START_FRAME 1
#define GAME_INIT 10
#define GAME_FRAME 11
/* 頂点フォーマット(基本形)*/
#define FVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
// 構造体の宣言
/* 頂点構造体 */
typedef struct _TLVERTEX {
float x, y, z; //位置情報
float rhw; //頂点変換値
D3DCOLOR color; //頂点カラー
float tu, tv; //テクスチャ座標
} TLVERTX, *LPTLVERTEX;
// グローバル変数
/* WinMain.cppで宣言されているもの */
extern HWND hWnd; // ウィンドウハンドル
extern BYTE g_FrameNo; // フレーム選択用
extern BYTE gl_KeyTbl[256]; // キーボードの状態を格納
extern RECT gl_rcScreen; // ウィンドウ領域
// プロトタイプ宣言
/* WinMain.cppで宣言されているもの */
void InitVertex(LPTLVERTEX, float, float, float, float, int); // 頂点情報格納
void Move(LPTLVERTEX, float, float); // 移動処理
void MoveCheck(RECT, LPTLVERTEX); // 移動範囲の制限
bool HitCheck(LPTLVERTEX, LPTLVERTEX); // 当たり判定処理
bool HitCheck2(LPTLVERTEX, RECT, LPTLVERTEX, RECT); // 当たり判定用矩形を用いた当たり判定処理
// 自作ソース・ファイルの組み込み
#include "NKC_DGraphics.h"
#include "Start.h"
#include "Game.h"
作成した共通ヘッダ・ファイル(NKC_Common.h)を、各ソースファイルからインクルードするとともに、余分なものを削除する。
//-------------------------------------------------------------------------------------------------
// 問題番号:Exer007
// 問題内容:ゲームを作りやすいプログラム
// Copyright NKC Game Staff(←自分の名前)
//-------------------------------------------------------------------------------------------------
#include "NKC_Common.h"
// グローバル変数
/* 他ソースも利用するもの */
HWND hWnd; // ウィンドウハンドル
BOOL g_appActive = FALSE; // ウィンドウの状態
BYTE g_FrameNo = START_INIT; // フレーム選択用
BYTE gl_KeyTbl[256]; // キーボードの状態を格納
RECT gl_rcScreen = {0, 0, 640, 480}; // ウィンドウ領域
/* 自ソースでのみ利用するもの */
static char szWinName[] = "Exer007"; // ウィンドウクラス用文字列
static char szWinTitle[] = "ゲームを作りやすいプログラム"; // ウィンドウクラス用文字列
// プロトタイプ宣言
/* 自ソースで宣言されているもの */
LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM); // Windows関数
BOOL InitApp(HINSTANCE, int); // ユーザー関数
BOOL UpdateFrame(void); // ゲームメイン処理
//=============================================================================
// DirectX Graphics関係の自作関数群
// Copyright NKC Game Staff(←自分の名前)
//-----------------------------------------------------------------------------
#include "NKC_Common.h"
// グローバル変数
/* 他のソースからも利用されるもの */
LPDIRECT3DDEVICE8 gl_lpD3ddev = NULL; // Direct3DDevice8インターフェイス
LPDIRECT3DTEXTURE8 gl_TXBack = NULL; // 背景用テクスチャ
LPDIRECT3DTEXTURE8 gl_TXMyChara = NULL; // 自機用テクスチャ
LPDIRECT3DTEXTURE8 gl_TXEnemy = NULL; // 敵用テクスチャ
/* 自ソースでのみ利用するもの */
static LPDIRECT3D8 gl_lpD3d = NULL; // Direct3D8インターフェイス
static D3DPRESENT_PARAMETERS gl_d3dpp; // ディスプレイパラメータ
// プロトタイプ宣言
/* 自ソースでのみ使用するもの */
//-----------------------------------------------------------------------------
// 関数名 : InitDX8()
// 機能概要: Direct Draw オブジェクトの生成
// 戻り値 : 正常終了のとき:DD_OK、異常終了のとき:エラーコード
//-----------------------------------------------------------------------------
HRESULT InitDX8(void)
{
・
・
・
//=============================================================================
// スタート処理関係の自作関数群
// Copyright NKC Game Staff(←自分の名前)
//-----------------------------------------------------------------------------
#include "NKC_Common.h"
// グローバル変数
/* 自ソースでのみ利用するもの */
static TLVERTX BackVertex[4]; // 背景用頂点情報配列
// プロトタイプ宣言
/* 自ソース(Start.cpp)内でのみ利用するもの */
//-----------------------------------------------------------------------------
// 関数名 : StartInit()
// 機能概要: スタート画面初期化処理
//-----------------------------------------------------------------------------
void StartInit(void)
{
・
・
・
//=============================================================================
// ゲーム処理関係の自作関数群
// Copyright NKC Game Staff(←自分の名前)
//-----------------------------------------------------------------------------
#include "NKC_Common.h"
// グローバル変数
/* 自ソースでのみ利用するもの */
static TLVERTX BackVertex[4]; // 背景用頂点情報配列
static TLVERTX MyCharaVertex[4]; // 自機用頂点情報配列
static TLVERTX EnemyVertex[4]; // 敵用頂点情報配列
static RECT MyCharaHitRect; // 自機用当たり判定矩形
static RECT EnemyHitRect; // 敵機用当たり判定矩形
// プロトタイプ宣言
/* 自ソース(Game.cpp)内でのみ利用するもの */
//-----------------------------------------------------------------------------
// 関数名 : GameInit()
// 機能概要: ゲーム画面初期化処理
//-----------------------------------------------------------------------------
void GameInit(void)
{
・
・
・
※以上の修正を行い、プログラムが正常に動作することを確認しよう。
ソース分割を行っただけではあまりきれいなプログラムにはならなかったが、共通ヘッダ・ファイルを作成したことによって、あれだけ煩雑だったヘッダ部分が相当シンプルになったことが分かるだろうか?
このように作成しておけば、各ソースファイルに関数やグローバル変数が増えたとしても、そのソースファイル自身と共通ヘッダ・ファイルのみを修正すればよいため、非常にメンテナンスがしやすくなっている。これならグループ(複数人)でゲームを開発しても、比較的容易にプログラムを結合できるだろう。
もちろんこのプログラムに問題がないわけではない。テクスチャ・オブジェクトと頂点情報配列をどこで作成し、管理しているかが分かりにくい。ここまでくれば、あとは自分のスタイルによって好きなように配置・管理すればよいだろう。
また、WinMain.cpp以外の各ソースには、それぞれに対応したヘッダ・ファイルを用意しているが、このヘッダ・ファイルをなくしてすべて共通ヘッダ・ファイルにプロトタイプ宣言を行うという考え方もある。確かにそうすればファイルが減るので便利かもしれない。しかし実際は、汎用性(他のゲーム製作でも利用できるように)を考え、ソースファイルとヘッダ・ファイルは一組で管理することが多い。C言語系のプログラマであれば、そのようにプログラムすることを心がけよう。
| BACK(ゲーム処理分割) | NEXT(開放処理のテクニック) |