無料でネットを楽しもう無料ゲームプレイレポート無料C++総合環境DirectXゲームプログラミング初心者C++ホームページ作成のコツゲーム質問掲示板ゲームリンク

無料C++










18.汎用化
汎用化をする必要はありません。
ただ、ゲームツクールのようにプログラムが組むために必要です。
どんなものかを解説するために、ひとつ汎用化をします。
汎用化とは、簡単に言うと、再利用を前提として設計するってことです。
言葉で説明するのは難しいです。
今まで作ってきたクラス(部品)の動作を、理解できてると思うので、
今まで作ったクラスを例に、汎用化していきます。

シューティング 敵 クラス の汎用化
前のページで説明しましたが、メインプログラムから切り離されていない部分があります。
汎用化の第一は、切り離すことです。
簡単に言えば定数やグローバル変数に頼らないクラスにするということです。
下は、前のページのものです
ShootingEnemy.h
//----------------------------------------------------------------
//敵の表示クラス
#include "DxLib.h"
//切り離されてない部分です
//そのうち切り離しましょう
#define MINI_RANGE_X 160 //画面の大きさと位置 横最小座標
#define MINI_RANGE_Y 0 //画面の大きさと位置 横最小座標
#define MAX_RANGE_X 480 //画面の大きさと位置 横最大座標
#define MAX_RANGE_Y 480 //画面の大きさと位置 横最大座標
class MoveEnemy
{
     private:   //変数
         int ENEMY_SIZE;
         int graph; //画像ハンドル(車のハンドルと同じ意味。操作する部分)
         int position_x; //座標X
         int position_y; //座標Y
         int has_enemy;
     public:    //関数
         MoveEnemy()
         {
             ENEMY_SIZE=50;
             graph=LoadGraph("Enemy.png");
             position_x=320;
             position_y=-50;
             has_enemy=FALSE;
         }
         //
         int MoveEnemyFall();

         //敵の表示
         int drawEnemy(); //描画        
};
変更したものを、下に書きます。
ShootingEnemy.h

//----------------------------------------------------------------
//敵の表示クラス
#include "DxLib.h"

class MoveEnemy
{
     private:   //変数
         int MINI_RANGE_X;    //最小有効範囲X座標
         int MINI_RANGE_Y;    //最小有効範囲Y座標
         int MAX_RANGE_X;    //最大有効範囲X座標
         int MAX_RANGE_Y;    //最大有効範囲Y座標

         int ENEMY_SIZE;       //キャラクターの大きさ
         int graph; //画像ハンドル(車のハンドルと同じ意味。操作する部分)
         int position_x;     //座標X
         int position_y;     //座標Y
         int has_enemy;   //敵の有無を示すフラグ
     public:    //関数
         //初期化(コンストラクタ)
         //[引数]移動範囲を入れる (最小X,最小Y,最大X,最大Y
         //                                    敵キャラサイズ,
         //                                    敵初期位置X,敵初期位置Y)
         MoveEnemy(int init_MINI_RANGE_X=160,  int init_MINI_RANGE_Y=0,
                           int init_MAX_RANGE_X=480, int init_MAX_RANGE_Y=480,
                           int init_ENEMY_SIZE=50,
                           int init_position_x=320,int init_position_y=-50)
         {
             MINI_RANGE_X=init_MINI_RANGE_X;
             MINI_RANGE_Y=init_MINI_RANGE_Y;
             MAX_RANGE_X=init_MAX_RANGE_X;
             MAX_RANGE_Y=init_MAX_RANGE_Y;

             ENEMY_SIZE=init_ENEMY_SIZE;
             graph=LoadGraph("Enemy.png");
             position_x=init_position_x;
             position_y=init_position_y;
             has_enemy=FALSE;
         }
         //敵の行動パターン1 上から下に移動
         int MoveEnemyFall();

         //敵の表示
         int drawEnemy(); //描画        
};

構築子(コンストラクタ)

構築子は、実体を作ったときに最初に一度だけ自動的に実行される関数です。
クラス名と同じ名前に()を付けます。
戻り値はありませんが、引数を持つことができます。
その引数を使って、初期化できます。
下記がその例です。

         MoveEnemy(int init_MINI_RANGE_X=160,  int init_MINI_RANGE_Y=0,
                           int init_MAX_RANGE_X=480, int init_MAX_RANGE_Y=480,
                           int init_ENEMY_SIZE=50,
                           int init_position_x=320,int init_position_y=-50)

デフォルト引数

デフォルト引数は、C++で新しく使えるできるようになった機能です。
すべての自作関数で使用することができます。

MoveEnemy()はコンストラクタですが、関数の一種です。
()内で、MoveEnemy()だけで使えるローカル変数を宣言しています。
そのローカル変数に、初期値を入れておくことができます。

[ 例 ]
メイン関数上にある
MoveEnemy M;  //実体化
により、自動的にコンストラクタ()内の値が初期値に設定されます。

MoveEnemy M(150,10,460,460,60,330,-60);
すると、それぞれの変数の初期値に設定されます。

設定が、クラス内をいじらなくても、メイン関数上でできるようになります。
暮らす内部を気にしなくていい、この設定が、汎用化(ブラックボックス化)です。

上では、すべての初期値をコンストラクタで定義しています。
オブジェクトを作るときに、引数の初期値を設定することで、自由に初期化がおこなえます。
ここまでするのは大げさですが、[ 例 ]ということで。

汎用化済み シューティング 敵 クラス
ShootingEnemy.h
//----------------------------------------------------------------
//敵の表示クラス
#include "DxLib.h"

class MoveEnemy
{
     private:   //変数
         int MINI_RANGE_X;    //最小有効範囲X座標
         int MINI_RANGE_Y;    //最小有効範囲Y座標
         int MAX_RANGE_X;    //最大有効範囲X座標
         int MAX_RANGE_Y;    //最大有効範囲Y座標
         int ENEMY_SIZE;       //キャラクターの大きさ
         int init_position_x;     //X座標の敵位置の初期値
         int init_position_y;     //
Y座標の敵位置の初期値    
         int graph; //画像ハンドル(車のハンドルと同じ意味。操作する部分)
         int position_x;     //座標X
         int position_y;     //座標Y
         int has_enemy;   //敵の有無を示すフラグ

     public:    //関数
         //初期化(コンストラクタ)
         //[引数]移動範囲を入れる (最小X,最小Y,最大X,最大Y
         //                                    敵キャラサイズ,
         //                                    敵初期位置X,敵初期位置Y)
         MoveEnemy(int init_MINI_RANGE_X=160,  int init_MINI_RANGE_Y=0,
                           int init_MAX_RANGE_X=480, int init_MAX_RANGE_Y=480,
                           int init_ENEMY_SIZE=50)
         {
             MINI_RANGE_X=init_MINI_RANGE_X;
             MINI_RANGE_Y=init_MINI_RANGE_Y;
             MAX_RANGE_X=init_MAX_RANGE_X;
             MAX_RANGE_Y=init_MAX_RANGE_Y;
             ENEMY_SIZE=init_ENEMY_SIZE;
             graph=LoadGraph("Enemy.png");
             init_position_x=(init_MAX_RANGE_X-init_MINI_RANGE_X)/2+init_MINI_RANGE_X;
             init_position_y=init_MINI_RANGE_Y-init_ENEMY_SIZE;
             has_enemy=FALSE;
         }
         //敵の行動パターン1 上から下に移動
         int MoveEnemyFall();

         //敵の表示
         int drawEnemy(); //描画        
};

ShootingEnemy.cpp
//敵 移動パターン1 上から落ちてくる
//
#include "ShootingEnemy.h"
int MoveEnemy::MoveEnemyFall()
{
     if(has_enemy==FALSE)
         {
         position_x=MINI_RANGE_X+ENEMY_SIZE/2+
             GetRand(MAX_RANGE_X-MINI_RANGE_X- ENEMY_SIZE );
         has_enemy=TRUE;
         }
     if(has_enemy==TRUE)position_y+=5;
     if(MAX_RANGE_Y<position_y)
     {
         has_enemy=FALSE;
         position_y=init_position_y;
     }
}
//-----------------------------------------------------------------
//敵の表示
int MoveEnemy::drawEnemy()
{
     DrawGraph( position_x-ENEMY_SIZE/2,position_y-ENEMY_SIZE/2,graph,TRUE);
     return 0;
}

-50をinit_position_yに変更。これにより、画像サイズが変わってもクラス内を変更する必要がなくなります。
汎用化済み シューティング 敵 クラス [ 説明 ]
init_position_x=(init_MAX_RANGE_X-init_MINI_RANGE_X)/2+init_MINI_RANGE_X;
敵の位置の初期値の設定。
(範囲の最大-範囲の最小)/2で、範囲の真ん中を計算。
範囲の最小をプラスすることで、モニター上の座標を計算。

この文章は、特別必要ではありませんが、敵のボスなど、真ん中に表示する場合が多そうので、先に設定しておきます。使いたい時すぐ使える定数です。

init_position_y=init_MINI_RANGE_Y-init_ENEMY_SIZE;
敵が上から出てくることを想定して、定数を作りました。

上の設定により、int init_position_x=320,int init_position_y=-50を削除しました。
MoveEnemy(int init_MINI_RANGE_X=160,  int init_MINI_RANGE_Y=0,
                           int init_MAX_RANGE_X=480, int init_MAX_RANGE_Y=480,
                           int init_ENEMY_SIZE=50)

追記 構築子(コンストラクタ)
コンストラクタは日本語で、構築子と訳されています。
クラスにかかわると、見たこともないようなこんな単語が並びます。
構築子と書いていれば、何をするものか結構わかりやすいですよね。
でも、どの本を読んでも、コンストラクタという言葉を覚えさせようとしているようです。
今、この単語を覚えていないと、どの本も読めないようになっています。
カタカナは読みにくいもので、読み間違いも発生しやすいのに;;。
クラスを難しいものだと思わせようとしているように少なからず思います。

追記 汎用化
まだまだこれから、汎用化を推進することもできます。
汎用化は、たいした作業ではありません。なれれば簡単です。
なれることが大切です。
今までのソースをいじったり、ソースを見ながら一から作ることでなれていきましょう。

このあたりまで読んだ方は、2〜3冊のC++の本を買うことをお勧めします。
私のソースは、実行はできますが、お手本になるようなソースではありません。
また、このページのC++の説明は他の本にはありません。少し変です。
なぜなら、特定のコンパイラやエディタ・ライブラリを対照に解説していますので、一般的なC/C++の解説書とは根本的に違いがあります。

私なりに、初心者の方に解りやすいように、説明しただけで、細かい部分は省略しています。
片寄ったプログラムを書くようにならないように。
また、細部を理解するために、本が不可欠です。

ホームページへ
このページのトップへ