現在DxLibを使用したノベルゲームを作成しており、その中でバックログ表示の機能を作成しているのですが
どうしてもバグの解決ができないため、質問致します。
バックログは、1~3行のメッセージ(string)の塊を1件とします。
(下記 list<string> log_msgsのことで、listの中身は1~3件です。このlog_msgsをBacklogMessage型として扱います。)
バックログは、全体として上記の塊を100件まで保存します。
これを list<BacklogMesssage> a_log とします。
バックログは1画面にデフォルトで最新のものを10行まで表示し、これより古いものを表示するときは
画面の上下ボタンを押すことで、表示されるメッセージをずらしていきます。
バックログを表示するとき、まず最新のものから10行(string)を読み取り、その10行目のイテレータ
(a_log_it:どのメッセージの塊か、msg_it:メッセージの塊のうち、何行目か)を保存します。
ただし、10行を読み取る前にバックログが無くなってしまったら、無くなった位置までで検索を終了します。
次に、最新から10行目のイテレータから開始して、画面の上部から [最新から10行目]、[最新から9行目]…[最新から1行目] を描画します。
こうすることで、バックログが1行だけあっても10行以上あっても、デフォルトでは画面の上部から最新の10行までのみが表示されます。
下記のように実装しました。
量が多いため申し訳ありませんが該当の関数のみ載せます。
多くの場合は下記のコードで正常に動くのですが、バックログがある件数(すみません、これが不明です)のとき
初期表示時や上下ボタンを押したとき、 Expression: list iterators incompatible のエラーが発生してしまいます。
(一度表示してから、次のフレームでこの関数を再実行されたときに、表示箇所の
while(msg_it != log_msgs.end() && log_line_cnt < 10){
の行でエラーとなります。デバッガで見ると、log_msgsはちゃんと3件のstringが格納されたlistになっているのですが…)
どの行が間違っているのでしょうか。
長くなってしまい申し訳ありませんが、どなたかのお力をいただきたく、よろしくお願いします。
void Scene::doScenarioBacklog(
Window* window,
Config* config,
Input* input,
GraphicManager* g_manager,
SoundManager* s_manager,
Scenario* scenario,
CmdMessage* message)
{
//初回表示時に一度だけ表示するログを指す箇所の計算をする
static bool seeklog_flg = false; // falseの時のみ計算
//この関数は毎フレーム呼ばれるため、イテレータはstatic変数として保存する
static Backlog logs = message->getLog();
static list<BacklogMessage> a_log = logs.logs();
static list<BacklogMessage>::iterator a_log_it = a_log.end();
static list<string>::iterator msg_it;
static list<string> log_msgs;
// 10行をカウントしたら打ち止め
int log_line_cnt;
// バックログ画面初期時
if(!seeklog_flg){
logs = message->getLog();
a_log = logs.logs();
a_log_it = a_log.end();
log_line_cnt = 0;
//最新行のある塊から古い方へ順に進める
while(a_log_it != a_log.begin() && log_line_cnt < 10){
if(log_line_cnt < 10) a_log_it--;
log_msgs = *a_log_it;
msg_it = log_msgs.end();
//3行目から1行目に向かって進める
while(msg_it != log_msgs.begin() && log_line_cnt < 10){
log_line_cnt += 1;
msg_it--;
}
}
seeklog_flg = true;
}
//表示
//検索した、表示するログの先頭行を指すイテレータを別の変数に保存しておく
//(描画するためにイテレータを進める必要があり、
// 進めてしまうと次のフレームで表示ログの先頭行がわからなくなってしまうため)
list<BacklogMessage>::iterator tmp_a_log_it = a_log_it;
list<string>::iterator tmp_msg_it = msg_it;
list<string> tmp_log_msgs = log_msgs;
log_line_cnt = 0;
//検索した位置から最新に向かって10行を描画する
while(a_log_it != a_log.end() && log_line_cnt < 10){
log_msgs = *a_log_it;
while(msg_it != log_msgs.end() && log_line_cnt < 10){
DxLib::DrawStringToHandle(
BACKLOG_POINT_X,
BACKLOG_POINT_Y + (MESSAGE_FONT_SIZE + BACKLOG_LINE_SPACE) * log_line_cnt,
(*msg_it).c_str(),
color_white,
message->msgFontHandle());
msg_it++;
log_line_cnt += 1;
}
if(log_line_cnt < 10) a_log_it++;
if(a_log_it == a_log.end()) break;
log_msgs = *a_log_it;
if(log_line_cnt == 10) break;
msg_it = log_msgs.begin();
}
//次のフレームで正常に表示できるようにするため、表示用に進めたイテレータを元に戻す
log_msgs = tmp_log_msgs;
a_log_it = tmp_a_log_it;
msg_it = tmp_msg_it;
//上ボタン
DxLib::DrawBox(930, 200, 980, 250, color_white, TRUE);
//下ボタン
DxLib::DrawBox(930, 630, 980, 680, color_white, TRUE);
//上ボタン
//上ボタンを押すと、表示ログを一つ過去に戻す
//デフォルトでは最新から、表示:10~1行目だが、上ボタンを1度押すと11~2行目を描画する
if(Common::cursorIn(930, 980, 200, 250)){
//マウスボタンが押された時。押しっぱなしでも一度のみ反応する
if(input->getKeepMouseLeft()){
log_msgs = *a_log_it;
if(msg_it != log_msgs.begin()){
msg_it--;
}else{
if(a_log_it != a_log.begin()){
a_log_it--;
log_msgs = *a_log_it;
msg_it = log_msgs.end();
msg_it--;
}
}
}
}
//下ボタン
//上ボタンと逆の動作
if(Common::cursorIn(930, 980, 630, 680)){
if(input->getKeepMouseLeft()){
msg_it++;
log_msgs = *a_log_it;
if(msg_it == log_msgs.end()){
a_log_it++;
if(a_log_it == a_log.end()){
a_log_it--;
msg_it--;
}else{
msg_it = log_msgs.begin();
}
}
}
}
//右クリックで前画面に戻る
if(input->getKeepMouseRight() != 0){
seeklog_flg = false;
now_scene = eScene_scenario;
before_scene = eScene_scenario_backlog;
}
}