NPC をコーディングして領地運営するゲーム開発(建築まわりの実装)
作っているゲームは、基本的には "Before We Leave" のような街づくりゲームです。
https://twitter.com/BalancingMonkey/status/1556832126489993217?s=20&t=HiYGCuborE2Dv289fWjsOA
大きく違うのは、作業を行うキャラクターの資材運搬から建築指示、ダンジョン探索の全てをプレイヤーが Lua スクリプトでコーディングする必要があるところです。そういうゲームにした理由は私が遊びたかったからです。
今回は、プレイヤーがどうやって建築を行うかについて書いていきます。
建築の流れ
プレイヤーが書くスクリプトには大きく2種類あり、キャラクター操作以外の指示を行う「布告用」と「キャラクター用」です。
建築は、この布告用のスクリプトに「この位置に建築してね」って記述した上でキャラクター用のスクリプトに「建築予定地があれば、要求される資材を運搬して建築する」というスクリプトを書けばオッケーです。
布告スクリプト(edict.lua)へのコーディング例
-- 鍛冶屋を (-1, 1) のグリッド位置に建築する。
world:build(Buildings.Blacksmith, Grid(-1, 1))
このスクリプトが実行されると、指定された場所に建築予定地が作られます。
いい感じですね。
建築する人(builder.lua)のスクリプトのコーディング例
そして、建築する人は
・建築予定地がフィールド上にあれば、
・建築に必要な資材を運んで、
・資材が全て揃ったら建築する。
という行動を行えばオッケーです。
実際にコードにすると、こんな感じです。
while true do
-- 建築を開始するために不足しているアイテム名を取得する。
local itemNames = buildOrder:requestedItemNames()
if #itemNames <= 0 then
-- 必要になる資材の運び込みが完了したら抜ける。
break
end
-- 必要になる資材が城塞にあると仮定して建築予定地に運搬する。
-- 本来は必要になる資材を適切に用意しなければならない。
local itemName = itemNames[1]
-- 城塞に移動して要求されたアイテムを取る。
character:move(keep)
character:get(itemName)
-- 建築予定地に移動してアイテムを納品する。
character:move(site)
character:put()
-- 疲れ切っていたら休憩する。
restIfTired(keep)
end
-- 建築に必要な資材を運び終えたので建築を開始する。
repeat
-- 建築を行う。建築中に疲れ切ったらこの処理は中断される。
character:work()
-- 疲れ切っていたら休憩する。
restIfTired(keep)
-- 建築予定地にあるタスクカードを取得する。
local buildCard = world:taskCard(site)
-- タスクカードがないか建築資材でなければ
-- 建築が完了したとみなして建築を終了する。
until not buildCard or buildCard:itemName() ~= Items.BuildingMaterials
急に難しくなった気がしましたか? はい、その通りです。開発者も難しいと思っていて「これをプレイヤーに書かせてもいいの? 大丈夫?」と悩んでいます。
ただ、ここのコードも1行ずつ見ていけば変な処理はありません。とりあえず、このまま開発を続けます。
建築する人が資材を建築予定地に運んでいる様子。
まとめと今後の予定
資材を運搬してクラフトするだけのスクリプトに比べると建築のスクリプトは急に小難しくなったので開発者としても悩んでいますが、とりあえずこのまま開発していきます。
おそらくですが、ゲーム自体の開発と同じくらい Lua スクリプトのコーディング方法のドキュメント作成が大変そうな気がしています。がんばります。