rogue: メッセージを3行表示
rogue のメッセージは単行で表示される。メッセージは何か行動を起こす度に出力されるのでスペースキーを押して、次のメッセージへと切り替えていく。このスペースキーでの切り替えは、ゆっくり読める所は良いのだけど、実際は頻繁に押さなくてはならなくてすごく煩わしい。
では、なぜ、頻繁に押さなければならないかというと、画面が1行と狭くてメッセージが収まりきらないからなので、広くすれば解決できると思うので、やってみる。
画面の構成と文字の出力
rogueは画面をcursesで描画していて、1つの全画面(window)にステータス、マップ、メッセージを描いている。対して、メッセージの改良は、複数行で表示したいし、いずれ過去ログを見れるようにもしたい。となると、独立したwindowにした方が制御しやすそうなのと、更に好みのバッファサイズにするとなると、curses の pad がぴったりくるので、メッセージをpadで描画するようにする。
msg_win = newpad(MSG_PAD_NLINES, MSG_PAD_COLS); wmove(msg_win, MSG_PAD_BOT, 0); scrollok(msg_win, TRUE); idlok(msg_win, TRUE);
ちょこちょこ書いたけど、必須なのは newpad() のみ。
次に、padでのメッセージの出力。これは、vw_printw()など window* を指定できる関数で行い、画面に反映するために prefresh() を呼べば出力できる。
vw_printw(msg_win, fmt, args); prefresh(msg_win, MSG_PAD_VIEW_TOP,0,VIEW_MSG_TOP,VIEW_MSG_LEFT,VIEW_MSG_BOT,VIEW_MSG_RIGHT);
このコードに切り替える事で、3行表示できるようになって改行毎に自動スクロールされるようになった。
画面更新されない
しかし、i (inventory)とか o (option) キーで別画面を表示した後、ゲーム画面に戻すとメッセージが消えてしまうという事が起こった。
色々いじってみた結果、windowであれば refresh() 時に再描画されるけど、padは再描画されない事で消えてしまっていたので、refresh() 後に prefresh() を追加することで表示できるようになった。
command.c:command(void) if (!((running || count) && jump)) + { refresh(); /* Draw screen */ + prefresh(msg_win, MSG_PAD_VIEW_TOP, 0, VIEW_MSG_TOP, VIEW_MSG_LEFT, VIEW_MSG_BOT, VIEW_MSG_RIGHT); + }
refresh -> prefresh の順でないと表示されなくて、これに気付くのに時間がかかった。
最後、スクショ。
Level: 1 Gold: 53 Hp: 10(12) Str: 16(16) Arm: 4 ------ |....+###### |....| # ---+-------------------- |....| # |............@.........| |....| #####+.............B........| ------ |......................| ------------------------ you found 53 gold pieces You barely miss the bat The bat has injured you