下に貼ってありますReplay.cppの、CReplayPly::Exec()内のReadData()が問題の場所です。
再生の部分がうまくいきません。コメントに書いてありますが、何故か2回関数を呼ばないと自分の考える挙動になりません。
Exec()の一番下のDrawFormatString()を呼び出さないと半分しか読みません。C++初心者でひどいコードではありますが、原因を教えていただきたいです。よろしくお願いします。
以下、ソースコードです。
► スポイラーを表示
main.cpp
System.h
System.cpp
BaseReplay.h
BaseReplay.cpp
Replay.h
Replay.cpp
ReplayMgr.h
ReplayMgr.cpp
Key.h
Key.cpp
#include <crtdbg.h>
#include <DxLib.h>
#include <memory>
#include "system/System.h"
#include "replay/ReplayMgr.h"
#include "key/Key.h"
#define DBG_PRINT( str, ... ) {\
printfDx( str, __VA_ARGS__ );\
ScreenFlip();\
WaitKey();\
}
#define SAFE_DELETE( p ) {\
if( p ) {\
delete ( p );\
( p ) = nullptr;\
}\
}
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow )
{
using namespace std;
#if _DEBUG
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
{
// unique_ptr< CSystem > pSys( new CSystem );
CSystem* pSys = nullptr;
CReplayMgr* pRep = nullptr;
try {
pSys = new CSystem;
}
// DxLibの初期化
catch( const char* e ) {
DBG_PRINT( "Initialize Error!\n%s\n", e );
SAFE_DELETE( pRep );
return -1;
}
// new に失敗
catch( bad_alloc& b ) {
DBG_PRINT( "new ERROR!\n%s\n", b.what() );
return -1;
}
try {
int mode = eREPLAY_PLY;
pRep = new CReplayMgr( "../dat/Replay/003.rpy", mode );
}
// 読み込みに失敗( mode = REPLAY_PLY の時のみ )
catch( const char* e ) {
DBG_PRINT( "READ_ERROR!\n%s\n", e );
SAFE_DELETE( pRep );
return -1;
}
// new に失敗
catch( bad_alloc& b ) {
DBG_PRINT( "new ERROR!\n%s\n", b.what() );
return -1;
}
nsKeyInput::Init();
pRep->Init();
while( pSys->GetProc() ) {
nsKeyInput::Proc();
pRep->Exec();
}
pRep->Final();
SAFE_DELETE( pRep );
SAFE_DELETE( pSys );
}
return 0;
}
#pragma once
class CSystem
{
bool Init();
void Final();
public:
CSystem();
~CSystem();
bool GetProc();
};
#include <DxLib.h>
#include "System.h"
CSystem::CSystem()
{
if( !Init() ) {
throw ( const char* )"ライブラリの初期化に失敗しました.";
}
}
CSystem::~CSystem()
{
Final();
}
bool CSystem::Init()
{
if( ChangeWindowMode( TRUE ) ) return false;
if( DxLib_Init() || SetDrawScreen( DX_SCREEN_BACK ) ) {
Final();
return false;
}
return true;
}
void CSystem::Final()
{
DxLib_End();
}
bool CSystem::GetProc()
{
if( ScreenFlip() ) return false;
if( ProcessMessage() ) return false;
if( ClearDrawScreen() ) return false;
return true;
}
#pragma once
#include <string>
/*!
* リプレイのインターフェイス
*/
class IReplay
{
unsigned m_uReplayCnt;
protected:
std::string m_strFileName; // リプレイファイル名
bool SetFile( const std::string& FileName );
public:
IReplay();
void SetCount( unsigned uCnt ) { m_uReplayCnt = uCnt; } // これはここに置くべきかどうか悩んだ結果置いた
unsigned GetCount() { return m_uReplayCnt; } // 同上
virtual ~IReplay();
virtual void Exec() = 0; // リプレイの行動を抽象的に
};
#include "BaseReplay.h"
#include <string>
#include <fstream>
IReplay::IReplay() :
m_uReplayCnt( 0 ),
m_strFileName()
{
}
IReplay::~IReplay()
{
}
bool IReplay::SetFile( const std::string& FileName )
{
m_strFileName = FileName;
std::ifstream ifs( m_strFileName );
if( ifs.fail() ) return false;
return true;
}
#pragma once
#include "BaseReplay.h"
#include <fstream>
/*!
* リプレイの保存
*/
class CReplayRec : public IReplay
{
std::ofstream m_Ofs;
private:
void SaveData( std::ofstream& ofs, const unsigned uCnt, const int nKeyCode );
public:
CReplayRec();
CReplayRec( const std::string& FileName );
~CReplayRec();
void Exec() override; // ここでは保存する行動
};
/*!
* リプレイの再生
*/
class CReplayPly : public IReplay
{
int m_nKey;
unsigned m_uCnt;
std::ifstream m_Ifs;
private:
bool ReadData( std::ifstream& ifs, const unsigned& uCnt, const int& nKeyCode );
public:
CReplayPly();
CReplayPly( const std::string& FileName );
~CReplayPly();
void Exec() override; // ここでは再生する行動
};
#include <DxLib.h>
#include <string>
#include <fstream>
#include "Replay.h"
#include "../key/Key.h"
namespace
{
const static int csWhite = GetColor( 255, 255, 255 );
const static int csFontSize = 16;
};
#if _DEBUG
// デバッグ用のメッセージ.関数名と行数を表示
# define DBG_DRAWDATA DrawFormatString( 0, 0, csWhite, "Line:%d Func:%s()\n", __LINE__, __FUNCTION__ )
# define DBG_DRAWMES( cnt, code ) printfDx( "Frame:%u KeyCode:%d\n", (unsigned)cnt, (int)code )
#else
# define DBG_DRAWDATA ( void )0
# define DBG_DRAWMES( cnt, code ) ( void )0
#endif
// 保存するキーの番号
static const int csSaveKeyNo[] =
{
KEY_INPUT_LSHIFT, // 低速移動
KEY_INPUT_Z, // ショット
KEY_INPUT_X, // ボム
KEY_INPUT_UP, // 上
KEY_INPUT_LEFT, // 左
KEY_INPUT_RIGHT, // 右
KEY_INPUT_DOWN, // 下
};
/* ================= 録画 ================= */
CReplayRec::CReplayRec() :
m_Ofs()
{
}
CReplayRec::CReplayRec( const std::string& FileName )
{
if( !IReplay::SetFile( FileName ) ) {
std::ofstream ofs( m_strFileName, std::ios::out ); // ファイルを作成
}
m_Ofs.open( m_strFileName, std::ios::out | std::ios::binary );
}
CReplayRec::~CReplayRec()
{
m_Ofs.close();
}
void CReplayRec::SaveData( std::ofstream& ofs, const unsigned uCnt, const int nKeyCode )
{
ofs.write( ( char* )&uCnt, sizeof( unsigned ) );
ofs.write( ( char* )&nKeyCode, sizeof( int ) );
}
void CReplayRec::Exec()
{
DBG_DRAWDATA;
for( int i=0 ; i<KEY_INPUT_NUM ; i++ ) {
if( nsKeyInput::GetKeyState( ( unsigned )i ) > 1 ) { // 1フレーム以上押されていたら
for( int j=0 ; j<7 ; j++ ) {
if( i == csSaveKeyNo[j] ) { // 保存するキーか?
DBG_DRAWMES( IReplay::GetCount(), i );
SaveData( m_Ofs, IReplay::GetCount(), i );
}
}
}
}
}
/* =================再生 ================= */
CReplayPly::CReplayPly() :
m_uCnt( 0 ),
m_nKey( 0 ),
m_Ifs()
{
}
CReplayPly::CReplayPly( const std::string& FileName ) :
m_uCnt( 0 ),
m_nKey( 0 ),
m_Ifs()
{
if( !IReplay::SetFile( FileName ) ) {
throw ( const char* )"ファイルが見つからない";
}
m_Ifs.open( m_strFileName, std::ios::in | std::ios::binary ); //開く
ReadData( m_Ifs, m_uCnt, m_nKey ); // 初回の読み込み
}
CReplayPly::~CReplayPly()
{
m_Ifs.close();
}
bool CReplayPly::ReadData( std::ifstream& ifs, const unsigned& uCnt, const int& nKeyCode )
{
if( ifs.peek() == std::ios::traits_type::eof() ) {
return false;
}
ifs.read( ( char* )&uCnt, sizeof( unsigned ) );
ifs.read( ( char* )&nKeyCode, sizeof( int ) );
return true;
}
void CReplayPly::Exec()
{
DBG_DRAWDATA;
unsigned uTmpCnt = m_uCnt;
int nTmpKey = m_nKey;
DrawFormatString( 0, csFontSize*2, csWhite, "uTmpCnt:%d nTmpKey:%d", uTmpCnt, nTmpKey );
if( uTmpCnt == IReplay::GetCount() ) {
if( !ReadData( m_Ifs, m_uCnt, m_nKey ) ) {
clsDx();
printfDx( "読み込み終了\n" );
}
}
DrawFormatString( 0, csFontSize*1, csWhite, "GameCnt : %u" , IReplay::GetCount() );
DrawFormatString( 0, csFontSize*3, csWhite, "m_uCnt :%d m_nKey :%d", m_uCnt, m_nKey );
// この下の関数を呼ぶと思っている挙動になる
// でも、コメントアウトすると思っていない挙動になる
DrawFormatString( 0, csFontSize*4, csWhite, "%s", ReadData( m_Ifs, m_uCnt, m_nKey ) ? "true" : "false" );
}
#pragma once
#include "Replay.h"
enum
{
eREPLAY_REC,
eREPLAY_PLY,
};
class CReplayMgr
{
unsigned m_uCnt; // サンプル用のゲームカウント
int m_nMode;
IReplay* m_pExec;
std::string m_strFileName;
public:
CReplayMgr();
CReplayMgr( const std::string& Name, int Mode );
~CReplayMgr();
void Init();
void Exec();
void Final();
};
#include "ReplayMgr.h"
#include <string>
CReplayMgr::CReplayMgr() :
m_uCnt( 0 ),
m_pExec( nullptr ),
m_nMode( eREPLAY_REC ),
m_strFileName()
{
}
CReplayMgr::CReplayMgr( const std::string& Name, int Mode ) :
m_uCnt( 0 ),
m_pExec( nullptr ),
m_nMode( Mode ),
m_strFileName( Name )
{
}
CReplayMgr::~CReplayMgr()
{
Final();
}
void CReplayMgr::Init()
{
switch( m_nMode ) {
case eREPLAY_REC :
m_pExec = new CReplayRec( m_strFileName );
break;
case eREPLAY_PLY :
m_pExec = new CReplayPly( m_strFileName );
break;
default :
m_pExec = nullptr;
break;
}
}
void CReplayMgr::Exec()
{
// ここはゲームカウンタ取得関数をぶち込む
m_pExec->SetCount( m_uCnt );
m_pExec->Exec();
m_uCnt++;
}
void CReplayMgr::Final()
{
if( m_pExec ) {
delete m_pExec;
m_pExec = nullptr;
}
}
#pragma once
#define KEY_INPUT_NUM 256
namespace nsKeyInput
{
namespace
{
int nNowKey[ KEY_INPUT_NUM ];
};
void Init();
bool IsAvailableKeyCode( unsigned uKey );
bool Proc();
int GetKeyState( unsigned uKey );
};
#include <DxLib.h>
#include "Key.h"
void nsKeyInput::Init()
{
for( int i=0 ; i<KEY_INPUT_NUM ; i++ ) {
nNowKey[i] = 0;
}
}
bool nsKeyInput::IsAvailableKeyCode( unsigned uKey )
{
if( uKey > KEY_INPUT_NUM ) {
return false;
}
return true;
}
bool nsKeyInput::Proc()
{
char pTemp[ KEY_INPUT_NUM ] = {};
GetHitKeyStateAll( pTemp );
for( int i=0 ; i < KEY_INPUT_NUM ; i++ ) {
if( pTemp[i] != 0 ) {
nNowKey[i]++;
} else {
nNowKey[i] = 0;
}
}
return true;
}
int nsKeyInput::GetKeyState( unsigned uKey )
{
if( !nsKeyInput::IsAvailableKeyCode( uKey ) ) {
return -1;
}
return nNowKey[ uKey ];
}