現在、龍神録プログラミングの館を参考にSTGを作成しているのですが、第12章を参考に敵の行動パターンをいろいろと作成してみたのですが、
関数ポインタの部分で躓いております。
関数ポインタ事態を使うのが初めてで調べながらやってみたのですがヘッダーで定義した関数ポインタをcppファイルでどうやって使えばいいのかわからないです。
下記が自分なりに書いてみたコードです
Enemy.h
#ifndef ENEMYH
#define ENEMYH
//-----------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <iostream>
#include "DxLib.h"
#include <Math.h>
using namespace std;
#define ENEMY_MODEL_KIND (3)
#define ENEMY_MAX (30)
#define ENEMY_ORDER_MAX (500) //敵の出現情報最大数
#define ENEMY_MOVEX_MIN (252)
#define ENEMY_MOVEX_MAX (385)
#define ENEMY_MOVEZ_MIN (177)
#define ENEMY_MOVEZ_MAX (300)
#define ENEMY_PATTERN_MAX (11)
#define PI 3.1415926535898
#define PI2 (PI*2)
//------------------------------------------------------------
class CEnemy
{
public:
//敵の情報の構造体
typedef struct
{
int Flag; //敵のフラグ
int Count; //敵のカウンター
int Pattern; //敵の移動パターン
int Muki; //敵の向き
int Kind; //敵の種類
int Hp; //敵のHP
int MaxHp; //敵の最大HP
int Item_n[6]; //落とすアイテム
int ModelHandle[ENEMY_MODEL_KIND]; //敵のモデルの格納ハンドル
int Model;
VECTOR Pos; //敵の座標
float VX; //速度X成分
float VZ; //速度Z成分
float Spd; //スピード
float Angle; //角度
int BulletTime; //弾幕開始時間
int BulletKind; //弾幕の種類
int BulletKind2; //弾幕の種類
int Color; //色
int State; //状態
int WaitTime; //待機時間
int Wait; //停滞時間
}ENEMY_PARAM;
//CSVファイルから読み取った敵データを格納するための構造体
typedef struct
{
int Count;
int Pattern;
int Kind;
float PosX;
float PosZ;
float Speed;
int BulletTime;
int BulletKind;
int Color;
int Hp;
int BulletKind2;
int Wait;
int Item_n[6];
}ENEMY_ORDER;
enum ENEMY_KIND{ENEMY0, ENEMY1, ENEMY2};
private:
ENEMY_PARAM tEnemyParam[ENEMY_MAX];
ENEMY_ORDER tEnemyOrder[ENEMY_ORDER_MAX];
void EnemyPattern0(int EnemyCount);
void EnemyPattern1(int EnemyCount);
void EnemyPattern2(int EnemyCount);
void EnemyPattern3(int EnemyCount);
void EnemyPattern4(int EnemyCount);
void EnemyPattern5(int EnemyCount);
void EnemyPattern6(int EnemyCount);
void EnemyPattern7(int EnemyCount);
void EnemyPattern8(int EnemyCount);
void EnemyPattern9(int EnemyCount);
void EnemyPattern10(int EnemyCount);
int EnemyNumberSearch();
public:
CEnemy();
~CEnemy();
int LoadEnemy(int EnemyNum, string FileName);
void UnLoadEnemy(int EnemyNum);
void LoadEnemyOrder();
void EnemyEntery(int StageCount);
void EnemyAction();
void EnemyDrow(int EnemyNum);
float Rang(float Angle);
void (CEnemy::*EnemyPattern[ENEMY_PATTERN_MAX])(int);
};
#endif
#include "Enemy.h"
CEnemy::CEnemy()
{
memset(tEnemyParam, 0, sizeof(ENEMY_PARAM) * ENEMY_MAX);//敵データの初期化
for(int ii = 0; ii < ENEMY_MAX; ii++)
{
tEnemyParam[ii].Pos.y = -280.0f;
}
memset(tEnemyOrder, 0, sizeof(ENEMY_ORDER) * ENEMY_ORDER_MAX);
}
//------------------------------------------------------------
CEnemy::~CEnemy()
{}
//------------------------------------------------------------
void (CEnemy::*CEnemy::EnemyPattern[ENEMY_PATTERN_MAX])(int) =
{
&CEnemy::EnemyPattern0, &CEnemy::EnemyPattern1, &CEnemy::EnemyPattern2,
&CEnemy::EnemyPattern3, &CEnemy::EnemyPattern4, &CEnemy::EnemyPattern5,
&CEnemy::EnemyPattern6, &CEnemy::EnemyPattern7, &CEnemy::EnemyPattern8,
&CEnemy::EnemyPattern9, &CEnemy::EnemyPattern10,
};
//------------------------------------------------------------
int CEnemy::LoadEnemy(int EnemyNum, std::string FileName)
{
for(int ii = 0; ii < ENEMY_MAX; ii++)
{
//SetUseASyncLoadFlag(TRUE);
switch (EnemyNum)
{
case ENEMY0:
tEnemyParam[ii].ModelHandle[ENEMY0] = MV1LoadModel(FileName.c_str());
break;
case ENEMY1:
tEnemyParam[ii].ModelHandle[ENEMY1] = MV1LoadModel(FileName.c_str());
break;
case ENEMY2:
tEnemyParam[ii].ModelHandle[ENEMY2] = MV1LoadModel(FileName.c_str());
break;
}
//SetUseASyncLoadFlag(FALSE);
if(tEnemyParam[ii].ModelHandle[EnemyNum] == -1)
{
return -1;
}
//MV1SetScale(tPlayerParam.PlayerModel[ModelNum], VGet(1, 1, 1));
//読み込み成功
}
return 1;
}
//------------------------------------------------------------
void CEnemy::UnLoadEnemy(int EnemyNum)
{
for(int ii = 0; ii < ENEMY_MAX; ii++)
{
if(tEnemyParam[ii].ModelHandle[EnemyNum] != 0)
{
MV1DeleteModel(tEnemyParam[ii].ModelHandle[EnemyNum]);
}
}
}
//------------------------------------------------------------
void CEnemy::LoadEnemyOrder()
{
int Line;
int Number;
int fp;
char FileName[32] = {"EnemyState/storyH0.csv"};
int input[64];
char inputc[64];
fp = FileRead_open(FileName); //ファイルの読み込み
if(fp == NULL)
{
printfDx("read error\n");
return;
}
for(int ii = 0; ii < 2; ii++) //最初の2行は飛ばす
{
while(FileRead_getc(fp) != '\n');
}
Line = 0;
Number = 0;
while(1)
{
for(int ii = 0; ii < 64; ii++)
{
inputc[ii] = input[ii] = FileRead_getc(fp); //1文字取得する
if(inputc[ii] == '/') //スラッシュがあれば
{
while(FileRead_getc(fp) != '\n'); //開業までループ
ii = 1; //カウンタを最初に戻す
continue;
}
if(input[ii] == ',' || input[ii] == '\n') //カンマか改行なら
{
inputc[ii] = '\0'; //そこまでを文字列とする
break;
}
if(input[ii] == EOF) //ファイルの終わりなら
{
goto EXFILE; //終了
}
}
switch(Number)
{
case 0:
tEnemyOrder[Line].Count = atoi(inputc);
break;
case 1:
tEnemyOrder[Line].Pattern = atoi(inputc);
break;
case 2:
tEnemyOrder[Line].Kind = atoi(inputc);
break;
case 3:
tEnemyOrder[Line].PosX = atoi(inputc);
break;
case 4:
tEnemyOrder[Line].PosZ = atoi(inputc);
break;
case 5:
tEnemyOrder[Line].Speed = atoi(inputc);
break;
case 6:
tEnemyOrder[Line].BulletTime = atoi(inputc);
break;
case 7:
tEnemyOrder[Line].BulletKind = atoi(inputc);
break;
case 8:
tEnemyOrder[Line].Color = atoi(inputc);
break;
case 9:
tEnemyOrder[Line].Hp = atoi(inputc);
break;
case 10:
tEnemyOrder[Line].BulletKind2 = atoi(inputc);
break;
case 11:
tEnemyOrder[Line].Wait = atoi(inputc);
break;
case 12:
tEnemyOrder[Line].Item_n[0] = atoi(inputc);
break;
case 13:
tEnemyOrder[Line].Item_n[1] = atoi(inputc);
break;
case 14:
tEnemyOrder[Line].Item_n[2] = atoi(inputc);
break;
case 15:
tEnemyOrder[Line].Item_n[3] = atoi(inputc);
break;
case 16:
tEnemyOrder[Line].Item_n[4] = atoi(inputc);
break;
case 17:
tEnemyOrder[Line].Item_n[5] = atoi(inputc);
break;
}
Number++;
if(Number == 18)
{
Number = 0;
Line++;
}
}
EXFILE:
FileRead_close(fp);
}
//------------------------------------------------------------
void CEnemy::EnemyPattern0(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == 0)
{
tEnemyParam[EnemyCount].VZ = -0.5f; //下がってくる
}
if(tEnemyParam[EnemyCount].Count == 40)
{
tEnemyParam[EnemyCount].VZ = 0.0f; //止まる
}
if(tEnemyParam[EnemyCount].Count == 40 + tEnemyParam[EnemyCount].Wait) //登録された時間だけ停滞する
{
tEnemyParam[EnemyCount].VZ = 0.5f; //上がっていく
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern1(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == 0)
{
tEnemyParam[EnemyCount].VZ = -0.5f; //下がってくる
}
if(tEnemyParam[EnemyCount].Count == 40)
{
tEnemyParam[EnemyCount].VZ = 0; //止まる
}
if(tEnemyParam[EnemyCount].Count == 40 + tEnemyParam[EnemyCount].Wait) //登録された時間だけ停滞する
{
tEnemyParam[EnemyCount].VX = -0.3f; //左へ
tEnemyParam[EnemyCount].VZ = -0.4f; //下がっていく
tEnemyParam[EnemyCount].Muki = 0; //左向きセット
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern2(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == 0)
{
tEnemyParam[EnemyCount].VZ = -0.5f; //下がる
}
if(tEnemyParam[EnemyCount].Count == 40)
{
tEnemyParam[EnemyCount].VZ = 0.0f; //停滞する
}
if(tEnemyParam[EnemyCount].Count == 40 + tEnemyParam[EnemyCount].Wait)
{
tEnemyParam[EnemyCount].VX = 0.3f; //右へ
tEnemyParam[EnemyCount].VZ = -0.4f; //下がる
tEnemyParam[EnemyCount].Muki = 2; //右向きセット
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern3(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == 0)
{
tEnemyParam[EnemyCount].VZ = -0.7f;
}
if(tEnemyParam[EnemyCount].Count == 30)
{
tEnemyParam[EnemyCount].Muki = 0;
}
if(tEnemyParam[EnemyCount].Count < 100)
{
tEnemyParam[EnemyCount].VX -= 0.7f / 100.0f;
tEnemyParam[EnemyCount].VZ += 0.4f / 100.0f;
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern4(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == 0)
{
tEnemyParam[EnemyCount].VZ = -0.7f;
}
if(tEnemyParam[EnemyCount].Count == 30)
{
tEnemyParam[EnemyCount].Muki = 2;
}
if(tEnemyParam[EnemyCount].Count < 100)
{
tEnemyParam[EnemyCount].VX += 0.7f / 100.0f;
tEnemyParam[EnemyCount].VZ -= 0.7f / 100.0f;
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern5(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == 0)
{
tEnemyParam[EnemyCount].VX -= 0.3f;
tEnemyParam[EnemyCount].VZ = -0.4f;
tEnemyParam[EnemyCount].Muki = 0;
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern6(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == 0)
{
tEnemyParam[EnemyCount].VX += 0.3f;
tEnemyParam[EnemyCount].VZ = -0.4f;
tEnemyParam[EnemyCount].Muki = 2;
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern7(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == tEnemyParam[EnemyCount].Wait)
{
tEnemyParam[EnemyCount].VX =-0.1f;
tEnemyParam[EnemyCount].VZ =+0.08f;
tEnemyParam[EnemyCount].Muki = 0;
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern8(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == tEnemyParam[EnemyCount].Wait)
{
tEnemyParam[EnemyCount].VX =+0.1f;
tEnemyParam[EnemyCount].VZ =+0.08f;
tEnemyParam[EnemyCount].Muki = 2;
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern9(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == tEnemyParam[EnemyCount].Wait)
{
tEnemyParam[EnemyCount].VZ = 0.3f;
}
}
//------------------------------------------------------------
void CEnemy::EnemyPattern10(int EnemyCount)
{
if(tEnemyParam[EnemyCount].Count == 0)
{
tEnemyParam[EnemyCount].VZ = -0.6f;
}
if(tEnemyParam[EnemyCount].Count == 40)
{
tEnemyParam[EnemyCount].VZ = 0.0f;
}
if(tEnemyParam[EnemyCount].Count > 40)
{
if(tEnemyParam[EnemyCount].Count % 60 == 0)
{
int rng = cos(tEnemyParam[EnemyCount].Angle) < 0 ? 0 : 1;
tEnemyParam[EnemyCount].Spd = 0.7 + Rang(2);
tEnemyParam[EnemyCount].Angle = Rang(PI/4) + PI * rng;
tEnemyParam[EnemyCount].Muki = 2 - 2 * rng;
}
tEnemyParam[EnemyCount].Spd *= 0.55f;
}
if(tEnemyParam[EnemyCount].Count >= 40 + tEnemyParam[EnemyCount].Wait)
{
tEnemyParam[EnemyCount].VZ += 0.008f;
}
}
//------------------------------------------------------------
int CEnemy::EnemyNumberSearch()
{
for(int ii = 0; ii < ENEMY_MAX; ii++)//フラグの立っていないEnemyを探す
{
if(tEnemyParam[ii].Flag == 0)
{
return ii; //使用可能番号を返す
}
}
return -1; //全部埋まっていたらエラーを返す
}
//------------------------------------------------------------
void CEnemy::EnemyEntery(int StageCount)
{
int Number = 0;
for(int ii = 0; ii < ENEMY_ORDER_MAX; ii++)
{
//現在の瞬間がオーダーの瞬間なら
if(tEnemyOrder[ii].Count == StageCount)
{
if((Number = EnemyNumberSearch()) != -1)
{
tEnemyParam[Number].Flag = 1;
tEnemyParam[Number].Count = 0;
tEnemyParam[Number].Pattern = tEnemyOrder[ii].Pattern;
tEnemyParam[Number].Muki = 1;
tEnemyParam[Number].Kind = tEnemyOrder[ii].Kind;
tEnemyParam[Number].Pos.x = tEnemyOrder[ii].PosX;
tEnemyParam[Number].Pos.z = tEnemyOrder[ii].PosZ;
tEnemyParam[Number].Spd = tEnemyOrder[ii].Speed;
tEnemyParam[Number].BulletTime = tEnemyOrder[ii].BulletTime;
tEnemyParam[Number].BulletKind = tEnemyOrder[ii].BulletKind;
tEnemyParam[Number].BulletKind2 = tEnemyOrder[ii].BulletKind2;
tEnemyParam[Number].Color = tEnemyOrder[ii].Color;
tEnemyParam[Number].Wait = tEnemyOrder[ii].Wait;
tEnemyParam[Number].Hp = tEnemyOrder[ii].Hp;
tEnemyParam[Number].MaxHp = tEnemyOrder[ii].Hp;
tEnemyParam[Number].VX = 0;
tEnemyParam[Number].VZ = 0;
tEnemyParam[Number].Angle = 0;
for(int jj = 0; jj < 6; jj++)
{
tEnemyParam[Number].Item_n[jj] = tEnemyOrder[ii].Item_n[jj];
}
MV1SetPosition(tEnemyParam[Number].ModelHandle[ENEMY0], tEnemyParam[Number].Pos);
}
}
}
}
//------------------------------------------------------------
void CEnemy::EnemyAction()
{
for(int ii = 0; ii < ENEMY_MAX; ii++)
{
//敵のフラグがオンだったら
if(tEnemyParam[ii].Flag == 1)
{
EnemyPattern[tEnemyParam[ii].Pattern](ii);
tEnemyParam[ii].Pos.x += cos(tEnemyParam[ii].Angle) * tEnemyParam[ii].Spd;
tEnemyParam[ii].Pos.z += sin(tEnemyParam[ii].Angle) * tEnemyParam[ii].Spd;
tEnemyParam[ii].Pos.x += tEnemyParam[ii].VX;
tEnemyParam[ii].Pos.z += tEnemyParam[ii].VZ;
tEnemyParam[ii].Count++;
tEnemyParam[ii].Model = tEnemyParam[ii].Muki * 3 + (tEnemyParam[ii].Count % 18) / 6;
//敵が画面外から外れたら消す
if(tEnemyParam[ii].Pos.x < 248 || tEnemyParam[ii].Pos.x > 390 || tEnemyParam[ii].Pos.z < 170 || tEnemyParam[ii].Pos.z > 325)
{
tEnemyParam[ii].Flag = 0;
}
MV1SetPosition(tEnemyParam[ii].ModelHandle[ENEMY0], tEnemyParam[ii].Pos);
}
}
}
//------------------------------------------------------------
void CEnemy::EnemyDrow(int EnemyNum)
{
VECTOR POS;
for(int ii = 0; ii < ENEMY_MAX; ii++)
{
if(tEnemyParam[ii].Flag == 1)
{
MV1DrawModel(tEnemyParam[ii].ModelHandle[tEnemyParam[ii].Kind]);
}
POS = MV1GetPosition(tEnemyParam[ii].ModelHandle[EnemyNum]);
}
}
//------------------------------------------------------------
float CEnemy::Rang(float Angle)
{
return (-Angle + Angle * 2 * GetRand(10000) / 10000.0f);
}
error C2761: 'void (__thiscall CEnemy::* CEnemy::EnemyPattern[11])(int)' : メンバ関数の再宣言はできません。
fatal error C1903: 直前のエラーを修復できません。コンパイルを中止します。
どうか関数ポインタについて詳しくご教授いただけたらと思います。