見出し画像

ゲームメイン(2)

前回引き続き、関数lookの処理を説明していきます。

前回の主人公に対する処理

関数lookはまず前回の主人公がいた座標の周辺をクリアする処理を実行します。具体的にはフロアを空白文字で書き直します。

次のソースコードは主人公の周辺を空白文字で描画している実装部分です。

--- misc.c ---
56: getyx(cw, oldy, oldx);
57: if (oldrp != NULL && (oldrp->r_flags & ISDARK) && off(player, ISBLIND))
58: {
59:     for (x = oldpos.x - 1; x <= oldpos.x + 1; x++)
60:        for (y = oldpos.y - 1; y <= oldpos.y + 1; y++)
61:            if ((y != hero.y || x != hero.x) && show(y, x) == FLOOR)
62:                mvwaddch(cw, y, x, ' ');
63: }

変数oldrpは前回の関数lookを呼び出した際の主人公が存在していたフロアです。NULLの場合は主人公が通路にいたということになります。

前回の主人公がいた場所が通路だった場合、前回の主人公がいた部屋がdark roomsだった場合、あるいは前回の主人公のステータスが盲目だった場合は、フロアの描画がされていないので、この処理は行われません。無駄な描画をしないという設計です。

変数oldposは前回の関数lookを呼び出した際の主人公がいた座標です。この座標周辺8カ所をクリアします。

クリアするのはフロアに指定された文字'.'のみです。このため、外壁などが存在する場合は外壁が表示されたままとなり、アイテムがあればアイテムが表示されたままとなります。

クリアすべき文字を得るために呼び出しているのが関数showです。

関数show

関数showは指定した座標にある描画すべき文字を返します。

トラップであれば検出フラグを参照し、検出されているトラップは文字'^'を、未検出であれば文字'.'を返します。

ミミックであれば変装している文字を返し、不可視の忍び寄りは可視フラグを参照し、可視できれていれば文字'I'を、不可視であれば見えないようにしています。

次のソースコードは関数showの実装部分です。

--- move.c ---
210: /*
211:  * show:
212:  *	returns what a certain thing will display as to the un-initiated
213:  */
214: 
215: show(y, x)
216: register int y, x;
217: {
218:     register char ch = winat(y, x);
219:     register struct linked_list *it;
220:     register struct thing *tp;
221: 
222:     if (ch == TRAP)
223:         return (trap_at(y, x)->tr_flags & ISFOUND) ? TRAP : FLOOR;
224:     else if (ch == 'M' || ch == 'I')
225:     {
226:         if ((it = find_mons(y, x)) == NULL)
227:             msg("Can't find monster in show");
228:         tp = (struct thing *) ldata(it);
229:         if (ch == 'M')
230:             ch = tp->t_disguise;
231:         /*
232:          * Hide invisible monsters
233:          */
234:         else if (off(player, CANSEE))
235:             ch = mvwinch(stdscr, y, x);
236:     }
237:     return ch;
238: }

今回の主人公に対する処理

前回の主人公に対する処理が終ったら、今回の主人公に対する処理を実行します。


コンピュータの処理コストが高かった時代では、毎回画面すべてを再描画すると処理が重くなり、ゲームになりませんでした。そこで差分描画ということを行い、画面を更新する必要のある部分だけを書き直すということをしています。

次のソースコードは、今回の主人公に対する処理を行うためのループ開始部分です。68行目はマルチステートメントになっていて、とても気づきにくいのですが、if文のあとにfor文があり、2重ループ構造になっています。

--- misc.c ---
64: inpass = ((rp = roomin(&hero)) == NULL);
65: ey = hero.y + 1;
66: ex = hero.x + 1;
67: for (x = hero.x - 1; x <= ex; x++)
68:     if (x >= 0 && x < COLS) for (y = hero.y - 1; y <= ey; y++)
69:     {
70:         if (y <= 0 || y >= LINES - 1)
71:             continue;

前回の主人公に対する処理では座標が画面範囲内に収まっているのかをチェックしていませんでしたが、今回の主人公に対する処理ではチェックを行っています。なぜ、このように処理が非対称となっているのか。その理由はわかりません。

部屋にはかならず外壁が存在するので画面外にはみ出して処理を実行させることはありませんから、もしかしたら開発初期に通路が画面端まで生成されるようになっていて、その名残としてあるのかもしれません。

モンスターの再描画文字の設定

72行目からはモンスターを再描画するための文字キャラクタを設定しています。

モンスターを描画しているウィンドウはmvに英大文字が描かれていれば、そこにモンスターがいるという判定をしているのは効率的ですね。

77行目で判定している変数wakeupは、再描画されたモンスターを起こすかどうかをフラグ値として保持しています。キーボード入力の前処理ではTRUEが設定され、後処理ではFALSEが設定されます。

キーボードを押したタイミングというのはプレイヤーが主人公を動かすアクションをしたということですから、その際にモンスターを起こしているということになります。

81行目以降は次の描画に備え、再描画すべき文字キャラクタを設定しています。

通常、床は文字'.'で描画されていますが、トラップが検出されている場合(過去に主人公がトラップに引っかかった、あるいはアイテムにより検出済みとなった)は文字'^'を描画する必要があります。

そこで構造体thingのメンバt_oldchへ床あるいはトラップの文字キャラクタを設定します。

85行目ではdark roomsの判定を行い、dark roomsの場合は空白文字を再描画用の文字キャラクタへ設定しています。

次のソースコードはモンスターの再描画をするための文字キャラクタを設定している部分です。

--- misc.c ---
72: if (isupper(mvwinch(mw, y, x)))
73: {
74:     register struct linked_list *it;
75:     register struct thing *tp;
76: 
77:     if (wakeup)
78:         it = wake_monster(y, x);
79:     else
80:         it = find_mons(y, x);
81:     tp = (struct thing *) ldata(it);
82:     if ((tp->t_oldch = mvinch(y, x)) == TRAP)
83:         tp->t_oldch =
84:         (trap_at(y,x)->tr_flags&ISFOUND) ? TRAP : FLOOR;
85:     if (tp->t_oldch == FLOOR && (rp->r_flags & ISDARK)
86:         && off(player, ISBLIND))
87:         tp->t_oldch = ' ';
88: }

次回はドアや壁を描画する部分について説明していきます。

この記事が気に入ったら、サポートをしてみませんか?気軽にクリエイターを支援できます。

記事を気に入っていただけて良かったです!
2
Cプログラミングの話題を中心としたマガジンを作成しています。完成したマガジンは電子書籍にまとめなおしてAmazonで販売しています。 Amazon著者ページ https://amzn.to/2IIHyv0

この記事が入っているマガジン

コードリーディング - rogue -

  • 39本
コードリーディング - rogue -
コメントを投稿するには、 ログイン または 会員登録 をする必要があります。