【開発日誌 #1】疑似3Dダンジョン描画
はじめに
今回は疑似3Dダンジョン仕組みを、できるだけわかりやすく書いてみます。
まず、ゲームの中を歩き回っているダンジョンの実態はこれです。
MAP_1F = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 1, 0, 1, 1, 0, 1],
...
]1 が壁、0 が通路。ただの数字の表です。プレイヤーはこのマス目の上を「座標」として動いています。
視界データの取り方
プレイヤーが今どこを向いているかに応じて、「前方4マス分、横5列分」のを調べます。
左2 左1 中 右1 右2
3歩先: ? ? ? ? ?
2歩先: ? ? ? ? ?
1歩先: ? ? ? ? ?
0歩先: ? ? (自分) ? ?このマス目ごとに "wall" "open" "door" のどれかを返します。これが描画の材料になります。デバッグ中はコンソールにこんな感じで表示されて、マス目の状態を確認できます。
--- 視界 pos=(2,3) 向き=北 ---
左2 左1 中 右1 右2
depth3: █ █ ░ █ █
depth2: █ ░ ░ ░ █
depth1: █ ░ ░ ░ █
depth0: █ █ — █ █「奥行き」の正体は固定座標
画面には「消失点」に向かって収束する4本の線が引かれています。

プレイヤーがどこを向いても、どこを歩いても、この枠の形は1ピクセルも変わりません。変わるのは「その場所が壁かどうか」の判定だです。
つまり、奥行きをリアルタイムで計算して描いているのではなく、それそれぞれのマスが壁なのか床なのかを座標から取得してそれぞれにあった絵を条件に応じて塗り分けているわけです。
初めてこの仕組みが分かった時、ウィザードリィもこうやって作ってたのかと少し感動しました。
壁を描く順番
描画の順番はこうなっています。
まず天井と床(背景)
3歩先の正面壁
2歩先の正面・側面
1歩先の側面
真横の壁(距離0)
1歩先の正面壁(最前面)
手前の壁を最後に描くことで、奥の壁が自然に重なって消えるので正しくダンジョンが描画されます。
炎の揺らぎ演出
最後に小ネタ。
ダンジョン内でかすかに壁の色が揺れているのは、Pyxelのパレット置き換え機能を使っています。
if self.flicker_mode == 1:
pyxel.pal(9, 13) # オレンジを明るく
elif self.flicker_mode in [2, 3, 4]:
pyxel.pal(9, 4) # オレンジを暗く4フレームに1回、ランダムにオレンジ色の番号を明るいものと暗いものに切り替えるだけ。コード5行で炎が揺れます。Pyxelの制約を逆手に取った、お気に入りの部分です。

まとめ
疑似3Dダンジョンの仕組みをまとめると:
マップは2次元配列(ただの数字の表)
視界は「前方4マス×横5列」のチェック
奥行きは固定座標で最初から決まっている
遠い順に描いて手前の壁で上書きする
次回からは基本的にはその日に作業した部分について書いていこうと思います。よければフォローして見ていてもらえると励みになります。
いいなと思ったら応援しよう!
もし記事が参考になったり、開発を応援してもいいと思ってくれた方がいたら、noteのサポートをいただけると次の記事を書く原動力になります。もちろん読んでくれるだけで十分嬉しいです。