vim-dungeons を公開 - Neovim の中だけで遊ぶ「不思議のダンジョン」風ローグライクを Lua で作った

vim-dungeons を公開 - Neovim の中だけで遊ぶ「不思議のダンジョン」風ローグライクを Lua で作った

作成日:
読了:9
更新日:
この記事を読む人におすすめPR / Amazonアソシエイト

当サイトは Amazon.co.jp を宣伝しリンクすることで紹介料を得る手段を提供する、Amazonアソシエイト・プログラムの参加者です。価格・在庫はリンク先の最新情報をご確認ください。

エディタは文章やコードを書く道具ですが、画面に文字を並べて更新できるなら、それはもう小さなゲーム機でもあります。そこで、Neovim のバッファの中だけで完結する「不思議のダンジョン」風のローグライク vim-dungeons を作って公開しましたhjkl で自動生成のダンジョンを潜り、ターン制で戦い、地下10階に眠る「Vimの聖典」を持ち帰るのが目標です。この記事では、何を作ったのか、どう遊ぶのか、そして実装で工夫した点を紹介します。

言語は純 Lua、依存はゼロ、動作要件は Neovim 0.10 以上(0.11 で動作確認)です。ライセンスは MIT です。

どんなゲームか

起動すると、専用バッファにダンジョンが描画されます。@ が自分、# が壁、. が床、> が階段、!$ がアイテムや金貨です。見た目はこんな雰囲気です。

B1F  Lv:1  HP:17/20  Hunger:95  G:0  Turn:35  Wpn:Club  Shd:-  Brc:-
#################.#######.......####%......!..##############
#################.#######.....................##############
#################.#######.....@.####..........##############
########...........##########.######..........##############
########......>.$.........................##################

いわゆるトルネコ・シレン系(Mystery Dungeon 系)の作法をひととおり踏襲しています。

  • ターン制: 自分が1歩動くと、敵も1歩動きます。じっくり考えて手を選べます。
  • 手続き的に生成されるフロア: 部屋と通路が毎回変わります。まれに「大部屋(フロア全体が1つの部屋)」や「1マスしか見えない迷路」といった特殊フロアも出ます。
  • 不思議のダンジョン式の視界: 部屋の中では部屋全体が見え、通路では周囲1マスだけが見えます。
  • 毎回シャッフルされる未識別アイテム: 巻物や腕輪は最初「青い巻物」のような仮の名前で落ちていて、使うか、店の値段で種類を推測して識別します。

目玉は「Vim 由来のギミック」

ただの移植ではつまらないので、Neovim で遊ぶ人がニヤリとする道具を入れました。ゲーム内アイテムが、そのまま Vim の操作のメタファーになっています。

  • f の巻物: 読むと1文字の入力を求められ、その文字が描かれているマス(敵やアイテム)へ一気にワープします。Vim の f モーション(行内で指定文字へジャンプ)そのものです。
  • :g//d の巻物: 視界内の敵にまとめて大ダメージを与えます。:g/パターン/d(該当行を一括削除)から取った「一掃」の巻物です。
  • :w! の巻物: 装備を強制的に上書き強化し、かかっている呪いを消します。:w!(強制書き込み)のイメージで、呪われた装備を「上書き保存」で直すわけです。

ゴールの「Vimの聖典(Tome of Vim)」や、ハードモードの「Neovimの奥義書(Secrets of Neovim)」も、この世界観に合わせた名前にしています。

主な要素

一通り「やり込める」ボリュームを目指しました。

  • 9種類の敵: 弱いスライムやコウモリから、2回行動する「2jうさぎ」、壁をすり抜ける「ggゴースト」、毒を持つ毒ヘビ、終盤のワイトやドラゴンまで。それぞれ出現階が決まっています。
  • ゴールの門番: 地下10階の聖典の上には、動かないが直線状に炎を吐くガーディアン・ドラゴン X(HP80)が居座ります。倒すまで聖典には手が届きません。
  • 識別と呪い: 装備は -1 から +3 の強化値を持ち(Club+2 のように表示)、マイナスの装備は呪われていて、着けると外せなくなります。前述の :w! の巻物で上書きできます。
  • 腕輪(パッシブ効果): ちから(攻撃+3)、毒消し(毒無効)、忍び足(同室の敵が起きない)、腹持ち(空腹半減)、よくみえ(隠し罠が見える)など。
  • : 通常フロアの一部に店主 K の店が出ます。商品を持つと「ツケ」になり、部屋を出るときに自動精算されます。払えずに出ようとすると、店主が高速で追ってくる強敵に変わります。売値で未識別品の種類を推測する「値段識別」も可能です。
  • 7種類の罠: とげ・毒矢・混乱・ワープ・落とし穴・大部屋・召喚。踏むまで隠れていて、発動すると ^ で見えるようになります。
  • 快適機能: ダッシュ移動、オート探索、投擲や杖のアニメーション、メッセージログ、中断セーブ。
  • やり込み要素: ハイスコア、13種類の実績、モンスター図鑑、25階のハードモード「The Abyss」、そして日付でシード固定される「デイリーチャレンジ」(その日は全員が同じダンジョン)。

試し方

lazy.nvim を使う場合は、コマンドで遅延ロードする設定を書くだけです。

{
  'printemps-tokyo/vim-dungeons',
  cmd = {
    'VimDungeons', 'VimDungeonsHard', 'VimDungeonsDaily',
    'VimDungeonsScores', 'VimDungeonsAchievements', 'VimDungeonsDex',
  },
}

インストールせずに、その場で試すこともできます。

git clone https://github.com/printemps-tokyo/vim-dungeons
nvim --cmd 'set rtp+=vim-dungeons' +VimDungeons

ゲーム内テキストは既定で英語です。日本語にするには次を設定します。

vim.g.vim_dungeons_lang = 'ja'

操作は hjkl(+斜め移動の yubn)で移動、> で階段を降り、i で持ち物、t で投げる、o でオート探索、? でヘルプです。まずは :VimDungeons で始めてみてください。

実装の話

「エディタの中でゲームを作る」と聞くと大掛かりに思えますが、要はバッファを1フレームごとに描き直しているだけです。モジュールは役割ごとに分かれています。

plugin/vim-dungeons.lua     ユーザーコマンド定義
lua/vimdungeons/game.lua    ゲーム状態・ターンエンジン・入力
lua/vimdungeons/dungeon.lua フロア生成(部屋・大部屋・迷路)
lua/vimdungeons/enemies.lua 敵の出現・戦闘・AI
lua/vimdungeons/items.lua   アイテム使用・投擲・杖・fジャンプ・値付け
lua/vimdungeons/render.lua  バッファ描画・フロート・アニメーション
lua/vimdungeons/data.lua    敵・アイテム・罠・ボスの定義
lua/vimdungeons/i18n.lua    多言語化(英語既定・日本語がソース)

設計で意識した点をいくつか挙げます。

  • ターンエンジン: 「プレイヤーが1手動いたら敵も1手動く」という原則をエンジンの中心に置いています。2回行動の敵や、店主が敵化したときの高速移動も、この1手の単位を増減させて表現しています。
  • フロア生成: 通常は部屋と通路を掘って繋ぎ、確率で大部屋や迷路といった特殊フロアに切り替えます。デイリーチャレンジは日付をシードにして生成を固定し、誰が遊んでも同じ地形になるようにしています。
  • 視界(FOV): 部屋にいる間は部屋全体を、通路では周囲1マスだけを可視にします。Mystery Dungeon 系の「通路は手探り」の緊張感は、この視界ルールから生まれます。
  • 識別システム: アイテムの見た目(色名など)は毎回シャッフルされ、使うか値段で種類が判明します。店の売値が種類ごとに違うことを利用した「値段識別」も成立します。
  • i18n: 日本語をソース文字列とし、英語へは翻訳テーブルで変換しています。テストは日本語ソース文字列を検証するため vim.g.vim_dungeons_lang = 'ja' を固定し、別のセクションで英訳の対応を確認しています。

テストは Neovim をヘッドレスで起動して回します。39セクションのスモークテストに加えて、BFS で経路を探索するボットが N 回自動プレイし、勝率・到達階・死因を集計するバランス測定を用意しました。手動では数百回の試遊が要る難易度調整を、ある程度は自動化しています。

# スモークテスト
nvim --headless --clean -l tests/smoke.lua
 
# バランス測定(30回自動プレイ、HARD=1 でハードモード)
RUNS=30 nvim --headless --clean -l tests/balance.lua

おわりに

vim-dungeons は、Neovim を「エディタとしての Lua ランタイム」として使い倒す実験でもあります。バッファ描画・ターン処理・手続き生成・視界計算・識別システムといった、ローグライクを構成する部品が一通り詰まっているので、「Neovim プラグインで何ができるか」「ローグライクはどう組み立てるか」を読むサンプルとしても使えると思います。

リポジトリは github.com/printemps-tokyo/vim-dungeons です。ソースは MIT ライセンスなので、フォークして自分好みの敵やアイテム、Vim ギミックを足してみるのも楽しいはずです。

Neovim の環境づくり自体に興味が出たら、Vim から Neovim へ移行して LazyVim で構築するNeovim 0.12 の新機能も合わせてどうぞ。