理想としては、下から最新のログを表示させていき上の方は古いログという感じです。また、ゲーム本体では十字キーでスクロールできるように考えていますので50行分のログデータを保持させています。
イメージとしては「elona」というゲームのログウィンドウに近い感じです。
下のコードは最低限の機能をピックアップした、数字のキー入力に対するログの発生とスペースキーによるログの表示量の変更です。
どう直せばよいかわからなくなってしまったので、間違っている点の指摘や、またそれを直していただければ嬉しいです。
環境はwindows8.1でvisual studio 2015です。
#include "DxLib.h"
#include <string>
#include <utility>
//ログの発生管理クラス
class CLog {
std::string LogMessage; //現在保持している全てのログ
bool LogFlag; //ログの表示する量を変更するフラグ
CLog() {
LogFlag = false;
}
public:
~CLog() {
std::string().swap(LogMessage); //解放
}
static CLog* Inst() {
static CLog Inst;
return &Inst;
}
//ログ追加
void AddLogMessage(const char* str) {
static int cnt = 0; //現在のカウントしている行数
LogMessage = std::string(str) + '\n' + LogMessage; //ログ追加
//50行超えれば1行分削除
if (cnt < 50)
cnt++;
else
LogMessage.erase(LogMessage.end() - LogMessage.rfind('\n'), LogMessage.end()); //削除
}
void ChangeLogMode() { //ログの表示するモードの変更
if (LogFlag)
LogFlag = false;
else
LogFlag = true;
}
//ログの内容の表示
void DrawLog() {
std::string StringBuf; //表示する用の文字列
size_t Position = 0; //現在の文字の位置
size_t OldPosition; //前回の文字の位置
if (!LogFlag) {
for (int i = 0; i < 6; ++i) { //6行分を確保
if (LogMessage.size() < Position) //探索する文字の位置がサイズを超えたときブレイク
break;
OldPosition = Position;
Position = LogMessage.find('\n', Position+1);
StringBuf = LogMessage.substr(OldPosition, Position) + StringBuf; //文字列の追加
}
}
else {
for (int i = 0; i < 15; ++i) { //15行分を確保
if (LogMessage.size() < Position) //探索する文字の位置がサイズを超えたときブレイク
break;
OldPosition = Position;
Position = LogMessage.find('\n', Position+1);
StringBuf = LogMessage.substr(OldPosition, Position) + StringBuf; //文字列の追加
}
}
DrawString(100, 50, StringBuf.c_str(), GetColor(255, 255, 255));
std::string().swap(StringBuf);
}
};
//キー入力管理クラス
class CKey {
char Key[256]; //現在の入力
char KeyBuf[256]; //前回の入力
CKey() {}
public:
~CKey(){}
static CKey* Inst() {
static CKey Inst;
return &Inst;
}
//キー入力の更新
bool KeyGet() {
std::swap(Key, KeyBuf); //スワップ
if (GetHitKeyStateAll(Key) == -1)
return false;
return true;
}
//キーを入力した瞬間
bool KeyTrigger(int KeyCode) {
if (Key[KeyCode] == 1 && KeyBuf[KeyCode] == 0)
return true;
return false;
}
};
//キーの入力処理
bool KeyCheck(){
CKey* Key = CKey::Inst();
CLog* Log = CLog::Inst();
//ログの追加
if (Key->KeyTrigger(KEY_INPUT_0))
Log->AddLogMessage("0キーを押した");
if (Key->KeyTrigger(KEY_INPUT_1))
Log->AddLogMessage("1キーを押した");
if (Key->KeyTrigger(KEY_INPUT_2))
Log->AddLogMessage("2キーを押した");
if (Key->KeyTrigger(KEY_INPUT_3))
Log->AddLogMessage("3キーを押した");
if (Key->KeyTrigger(KEY_INPUT_4))
Log->AddLogMessage("4キーを押した");
if (Key->KeyTrigger(KEY_INPUT_5))
Log->AddLogMessage("5キーを押した");
if (Key->KeyTrigger(KEY_INPUT_6))
Log->AddLogMessage("6キーを押した");
if (Key->KeyTrigger(KEY_INPUT_7))
Log->AddLogMessage("7キーを押した");
if (Key->KeyTrigger(KEY_INPUT_8))
Log->AddLogMessage("8キーを押した");
if (Key->KeyTrigger(KEY_INPUT_9))
Log->AddLogMessage("9キーを押した");
if (Key->KeyTrigger(KEY_INPUT_SPACE)) //スぺースキーでモード変更
Log->ChangeLogMode();
if (Key->KeyTrigger(KEY_INPUT_ESCAPE)) //エスケープキーで終了
return false;
return true;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
ChangeWindowMode(TRUE);
if (DxLib_Init() == -1)return -1;
SetDrawScreen(DX_SCREEN_BACK);
//メインループ
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && CKey::Inst()->KeyGet()) {
if (!KeyCheck()) //キーでのログの変更処理
break;
CLog::Inst()->DrawLog(); //ログの表示
}
DxLib_End();
return 0;
}