今回質問したいのは敵のショットの描画についてです。
龍神録の第13章を参考に敵のショットのプログラムを組んでみたのですが、敵の弾が描画されず、どのように修正したらよいかわからず
困っております。
一応デバッガを使ってみてみたところ敵の構造体を格納するEnemyInfoとプレイヤーの構造体を格納するPlayerInfoと弾の画像のハンドルを格納している
BulletImageが「エラーです。シンボルが見つかりません」「エラーです。式を評価できません」となっておりこれではないかなと思っております。
ただ、これがどのようにしたら修正できるのかがわかりません。
以下がコードとなります。
Bullet.h
#ifndef BULLETH
#define BULLETH
#include <stdio.h>
#include <string.h>
#include <iostream>
#include "DxLib.h"
#include "Enemy.h"
#include "Model.h"
using namespace std;
//敵1匹が持つ弾の最大数
#define SHOT_BULLET_MAX (1000)
//一度に画面に表示できる敵の弾幕の最大数
#define SHOT_MAX (30)
//ショットの種類の最大数
#define SHOT_KND_MAX (1)
//効果音の種類の最大数
#define SE_MAX (100)
class CBullet
{
public:
//弾に関する構造体
typedef struct
{
int Flag;
int Kind;
int Count;
int Color;
int State;
int Till; //少なくとも消さない時間
int Effect; //エフェクトの種類
VECTOR Pos;
float Angle;
float Speed;
float BaseAngle[1]; //ベースの角度
float RemSpd; //一時記憶スピード
}BULLET_PARAM;
typedef struct
{
int Flag;
int Kind;
int Count;
int Number;
float BaseAngle[1]; //ベース角度
float BaseSpeed[1]; //ベーススピード
BULLET_PARAM tBullet[SHOT_BULLET_MAX];
}SHOT_PARAM;
private:
SHOT_PARAM tShot[SHOT_MAX];
CEnemy::ENEMY_PARAM* EnemyInfo;
CModel::PLAYER_PARAM PlayerInfo;
int BulletImage[10][10]; //弾の画像
public:
CBullet();
~CBullet();
void LoadBullet();
void SetPlayerParam(CModel::PLAYER_PARAM player);
void SetEnemyParam(CEnemy::ENEMY_PARAM* enemy);
//空いている弾を探す
int ShotSearch(int ShotNumber);
//n番目のショットを登録した敵と自機との角度を返す
float Shotatan2(int ShotNumber);
void ShotMain();
void ShotBulletPattern000(int ShotNumber);
void ShotCalc(int ShotNumber);
void DrawShot();
void (CBullet::*ShotBulletPattern[SHOT_KND_MAX])(int);
};
#endif
#include "Enemy.h"
#include "Bullet.h"
CBullet::CBullet()
{
memset(tShot, 0, sizeof(SHOT_PARAM) * SHOT_MAX);
for(int ii = 0; ii < SHOT_MAX; ii++)
{
for(int jj; jj < SHOT_BULLET_MAX; jj++)
{
tShot[ii].tBullet[jj].Pos.y = -280.0f;
}
}
ShotBulletPattern[0] = &CBullet::ShotBulletPattern000;
}
CBullet::~CBullet()
{}
//----------------------------------------------------------------
void CBullet::LoadBullet()
{
LoadDivGraph("./Bullet/b0.png" , 5 , 5 , 1 , 76 , 76 , BulletImage[0]) ;
LoadDivGraph("./Bullet/b1.png" , 6 , 6 , 1 , 22 , 22 , BulletImage[1]) ;
LoadDivGraph("./Bullet/b2.png" , 10 , 10 , 1 , 5 , 120 , BulletImage[2]) ;
LoadDivGraph("./Bullet/b3.png" , 5 , 5 , 1 , 19 , 34 , BulletImage[3]) ;
LoadDivGraph("./Bullet/b4.png" , 10 , 10 , 1 , 38 , 38 , BulletImage[4]) ;
LoadDivGraph("./Bullet/b5.png" , 3 , 3 , 1 , 14 , 16 , BulletImage[5]) ;
LoadDivGraph("./Bullet/b6.png" , 3 , 3 , 1 , 14 , 18 , BulletImage[6]) ;
LoadDivGraph("./Bullet/b7.png" , 9 , 9 , 1 , 16 , 16 , BulletImage[7]) ;
LoadDivGraph("./Bullet/b8.png" , 10 , 10 , 1 , 12 , 18 ,BulletImage[8]) ;
LoadDivGraph("./Bullet/b9.png" , 3 , 3 , 1 , 13 , 19 , BulletImage[9]) ;
}
//----------------------------------------------------------------
void CBullet::SetEnemyParam(CEnemy::ENEMY_PARAM* enemy)
{
EnemyInfo = enemy;
}
//----------------------------------------------------------------
void CBullet::SetPlayerParam(CModel::PLAYER_PARAM player)
{
PlayerInfo = player;
}
//----------------------------------------------------------------
float CBullet::Shotatan2(int ShotNumber)
{
return atan2(PlayerInfo.PlayerPos.z - EnemyInfo[tShot[ShotNumber].Number].Pos.z, PlayerInfo.PlayerPos.x - EnemyInfo[tShot[ShotNumber].Number].Pos.x);
}
//----------------------------------------------------------------
//空いている弾を探す
int CBullet::ShotSearch(int ShotNumber)
{
for(int ii = 0; ii < SHOT_BULLET_MAX; ii++)
{
if(tShot[ShotNumber].tBullet[ii].Flag == 0)
{
return ii;
}
}
return -1;
}
//----------------------------------------------------------------
void CBullet::ShotMain()
{
for(int ii = 0; ii < SHOT_MAX; ii++)
{
//フラグが立っていて、設定した種類が間違っていなければ(オーバーフロー対策)
if(tShot[ii].Flag != 0 && 0 <= tShot[ii].Kind && tShot[ii].Kind < SHOT_KND_MAX)
{
(this->*ShotBulletPattern[tShot[ii].Kind])(ii); //.kndの弾幕計算関数を呼ぶ関数ポインタ
ShotCalc(ii); //ii番目の弾幕を計算
tShot[ii].Count++;
}
}
}
//----------------------------------------------------------------
//1発だけ、自機に向かって直線移動
void CBullet::ShotBulletPattern000(int ShotNumber)
{
int BulletNumber;
if(tShot[ShotNumber].Count == 0) //弾幕が始まって0カウント目
{
//敵が倒されていなくて、探した登録可能な弾番号が有効なら
if(tShot[ShotNumber].Flag != 2 && (BulletNumber = ShotSearch(ShotNumber)) != -1)
{
tShot[ShotNumber].tBullet[BulletNumber].Kind = EnemyInfo[tShot[ShotNumber].Number].BulletKind2;
tShot[ShotNumber].tBullet[BulletNumber].Angle = Shotatan2(ShotNumber);
tShot[ShotNumber].tBullet[BulletNumber].Flag = 1;
tShot[ShotNumber].tBullet[BulletNumber].Pos.x = EnemyInfo[tShot[ShotNumber].Number].Pos.x;
tShot[ShotNumber].tBullet[BulletNumber].Pos.z = EnemyInfo[tShot[ShotNumber].Number].Pos.z;
tShot[ShotNumber].tBullet[BulletNumber].Color = EnemyInfo[tShot[ShotNumber].Number].Color;
tShot[ShotNumber].tBullet[BulletNumber].Count = 0;
tShot[ShotNumber].tBullet[BulletNumber].Speed = 0.5f;
}
}
}
//----------------------------------------------------------------
void CBullet::ShotCalc(int ShotNumber)
{
int Max = 0;
//敵が倒されたら
if(EnemyInfo[tShot[ShotNumber].Number].Flag != 1)
{
tShot[ShotNumber].Flag = 2; //それ以上ショットを登録しない
}
//ShotNumber番目の弾幕データの弾を計算
for(int ii = 0; ii < SHOT_BULLET_MAX; ii++)
{
//その弾が登録されていたら
if(tShot[ShotNumber].tBullet[ii].Flag > 0)
{
tShot[ShotNumber].tBullet[ii].Pos.x += cos(tShot[ShotNumber].tBullet[ii].Angle) * tShot[ShotNumber].tBullet[ii].Speed;
tShot[ShotNumber].tBullet[ii].Pos.z -= sin(tShot[ShotNumber].tBullet[ii].Angle) * tShot[ShotNumber].tBullet[ii].Speed;
tShot[ShotNumber].tBullet[ii].Count++;
if(tShot[ShotNumber].tBullet[ii].Pos.x < 248 || tShot[ShotNumber].tBullet[ii].Pos.x > 390 ||
tShot[ShotNumber].tBullet[ii].Pos.z < 170 || tShot[ShotNumber].tBullet[ii].Pos.z > 325)
{
tShot[ShotNumber].tBullet[ii].Flag = 0;
}
}
}
//現在表示中の弾が一つでもあるか調べる
for(int ii = 0; ii < SHOT_BULLET_MAX; ii++)
{
if(tShot[ShotNumber].tBullet[ii].Flag > 0)
{
return;
}
}
if(EnemyInfo[tShot[ShotNumber].Number].Flag != 1)
{
tShot[ShotNumber].Flag = 0; //終了
EnemyInfo[tShot[ShotNumber].Number].Flag = 0;
}
}
//----------------------------------------------------------------
void CBullet::DrawShot()
{
SetDrawMode(DX_DRAWMODE_BILINEAR);//線形補完描画
for(int ii = 0; ii < SHOT_MAX; ii++)
{
if(tShot[ii].Flag > 0)
{
for(int jj = 0; jj < SHOT_BULLET_MAX; jj++)
{
if(tShot[ii].tBullet[jj].Flag != 0)
{
if(tShot[ii].tBullet[jj].Effect == 1)
{
SetDrawBlendMode(DX_BLENDMODE_ADD, 255);
}
DrawBillboard3D(tShot[ii].tBullet[jj].Pos, tShot[ii].tBullet[jj].Pos.x + PLAYER_MOVEX_MIN,
tShot[ii].tBullet[jj].Pos.z, 1.0f, tShot[ii].tBullet[jj].Angle + PI/2, BulletImage[tShot[ii].tBullet[jj].Kind][tShot[ii].tBullet[jj].Color], TRUE);
if(tShot[ii].tBullet[jj].Effect == 1)
{
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
}
}
}
}
}
SetDrawMode(DX_DRAWMODE_NEAREST); //描画形式を戻す
}
#include "DxLib.h"
#include "Input.h"
#include "Stage.h"
#include "Camera.h"
#include "Model.h"
#include "Enemy.h"
#include "Bullet.h"
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define ISLAND (0)
#define MIKU (0)
#define BACK (1)
#define SCREENWIDTH (1280)
#define SCREENHIGH (720)
#define SCREENBIT (32)
const int MaxStage = 2;
typedef struct CAMERA_DATA;
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
ChangeWindowMode(TRUE);
SetGraphMode(SCREENWIDTH ,SCREENHIGH ,SCREENBIT); // 画面モードの設定
// DXライブラリ初期化処理
if( DxLib_Init() < 0 )
{
// エラーが発生したら直ちに終了
return -1 ;
}
SetDrawScreen( DX_SCREEN_BACK );
int StageCount = 0;
CInput* input = new CInput();
//カメラの設定
CCamera* camera = new CCamera();
CCamera::CAMERA_DATA CameraInfo;
//カメラはZ軸が画面上方向になるよう第7、8、9引数のうちZ軸の第9引数を1.0にする(通常はY軸が上方向なので第8引数が1.0)
camera->CameraInit(320.0f, -110.0f, 220.0f, 320.0f, -280.0f, 240.0f, 0.0f, 0.0f, 1.0f);
CameraInfo = camera->GetCameraParam();
camera->CameraSet(CameraInfo);
//モデルの初期設定
CModel* model = new CModel();
CModel::PLAYER_PARAM PlayerInfo;
model->LoadFile(MIKU, "PlayerModel/Miku/Miku.mv1"); //キャラクターのモデルの読み込み
model->SetPlayerRoll(MIKU, 90.0f, 0.0f, 0.0f); //プレイヤーモデルの初期回転値
model->SetPlayerPos(MIKU, 320.0f, -280.0f, 177.0f); //プレイヤーモデルの初期位置
PlayerInfo = model->GetPlayerParam(); // 描画先を裏画面にする
//古いアニメーション情報を削除
model->EraseAnimInfo(PlayerInfo);
//アニメーション情報を初期化
model->InitAnime(PlayerInfo.NowAnimNum, PlayerInfo.PlayerModel[MIKU], 0);
PlayerInfo.AnimeState = CModel::WAIT;
model->SetAnimeInfo(PlayerInfo);
//敵の設定
CEnemy* enemy = new CEnemy();
CEnemy::ENEMY_PARAM* EnemyState;
enemy->LoadEnemyOrder();
enemy->LoadEnemy(CEnemy::ENEMY0, "Enemy/enemy1.x");
//弾の設定
CBullet* bullet = new CBullet();
bullet->LoadBullet();
//2D読み込み
int SideBar = LoadGraph("Graphic/Dammy.png");
while(ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && input->gpUpdateKey() == 0)
{
input->UpdatePad();
//キャラの移動
/*if(input->TriggerPad & PAD_INPUT_RIGHT)
{
PlayerInfo.PlayerPos.x -= 10;
}
else if(input->TriggerPad & PAD_INPUT_LEFT)
{
PlayerInfo.PlayerPos.x += 10;
}
else if(input->TriggerPad & PAD_INPUT_UP)
{
PlayerInfo.PlayerPos.z += 10;
}
else if(input->TriggerPad & PAD_INPUT_DOWN)
{
PlayerInfo.PlayerPos.z -= 10;
}
else if(input->Key1[KEY_INPUT_RETURN] != 0)
{
PlayerInfo.PlayerPos.y += 10;
}
else if(input->Key1[KEY_INPUT_BACK] != 0)
{
PlayerInfo.PlayerPos.y -= 10;
}
else if(input->Key1[KEY_INPUT_SPACE] != 0)
{
break;
}
model->SetPlayerPos(MIKU, PlayerInfo.PlayerPos.x, PlayerInfo.PlayerPos.y, PlayerInfo.PlayerPos.z);*/
model->SetMoveAngle();
model->MovePlayerModel();
model->DrawModel(MIKU);
enemy->EnemyEntery(StageCount);
enemy->EnemyAction();
enemy->EnemyDrow(CEnemy::ENEMY0);
PlayerInfo = model->GetPlayerParam();
EnemyState = enemy->GetEnemyParam();
bullet->SetPlayerParam(PlayerInfo);
bullet->SetEnemyParam(EnemyState);
bullet->ShotMain();
bullet->DrawShot();
DrawGraph(0, 0, SideBar, TRUE);
DrawGraph(1000, 0, SideBar, TRUE);
DrawFormatString(100, 340, 0x666666,"X %f Y %f Z %f", PlayerInfo.PlayerPos.x, PlayerInfo.PlayerPos.y, PlayerInfo.PlayerPos.z);
StageCount++;
}
model->UnLoadModel(MIKU);
delete model;
WaitKey(); // キー入力待ち
DxLib_End(); // DXライブラリ終了処理
return 0;
}
どうかよろしくお願い致します。