投稿記事

satofumi 2022/10/18 20:00

NPC をコーディングして領地運営するゲーム開発(道の作り方の仕様変更)

今回はタイル間の移動を速くする要素である道についてです。

今までの道の仕様と雰囲気

今までの仕様だと、タイルに建物を追加すると隣りにある建物や道との間に道を自動で作っており、道が多くなってしまっていました。


この見た目には違和感を覚えたので修正します。

修正後の道の仕様

道については「あまり連結しすぎない」「でもプレイヤーが道を追加できる」を実現するために、以下のような仕様にしました。

  • 城塞と敵の城塞との間には最短経路で通路を作り、これを「街道」と呼ぶ。
    • 街道の上には建物を建築できないようにする。
  • キャラクターがある回数だけタイルの間を移動すると、そこに「道」を作る。
    • 「道」が作られるまでの移動回数は、タイルの移動コストが高いほど多くする。

この仕様にすることで、キャラクターが何回も通ると自然に道が作られるし、キャラクターの移動を制御して道を作ることもできます。
道があると移動が2倍くらい早いので、最短経路を求めるときに既存の道があればキャラクターはそこを通りがちなので、新たな道は必要以上に追加されにくいです。

ある目的地まで道を動的に作る Lua スクリプトの例

function createRoads(from, to)
   -- from から to までの最短経路の Grid 配列を受け取る。
   local route = world:route(from, to)

   -- from の位置まで移動する。
   character:move(from)
   
   --- from から to までで、道がない場所を探す。
   for k, to in ipairs(route) do
      -- 道がなければ、道ができるまで往復させる。
      while not world:roadExists(from, to) do
         character:move(to)
         character:move(from)
      end
   end
end


return function()
   local keep = world:keep()
   local kitchen = world:buildings(Buildings.Kitchen)[1]
   
   -- 要塞とキッチンとの間に道を作らせる。
   createRoads(keep:grid(), kitchen:grid())
end

まとめと今後の予定

今回は道の作られ方の仕様を変更しました。
今後も気付いたことは少しずつでも改善していきます。

satofumi 2022/10/11 20:00

NPC をコーディングして領地運営するゲーム開発(9月末の開発状況)

今回は9月末までのスクリーンショットや動画を貼り付けた、いわゆる開発状況の報告記事です。
進捗を簡単にまとめると「機能はだいたい実装した。エフェクトや UI の作り込みはまだ。アイテムや建物のデータ登録はテストで使う一部のみ終わっている」という状況です。

今回は開発状況についての最初の報告なので、全体的に広く浅くの説明をします。

タイトル画面


機能は実装ずみ、設定パネルも実装済みで言語切り替えも動作します。
アイテムやステージ、シナリオを共有できる Workshop 機能は未実装なのと、ちょっとしたエフェクトを追加したいと考えています。

主人公キャラの見た目の変更


ここで変更した見た目が、主人公の見た目として扱われます。
これも機能は実装ずみです。

ステージ選択


機能は実装済みです。ワールドに複数のステージがあって、ステージを選択するとゲームが始まる仕組みです。体験版では「生産」「探索」「防衛」の3つのチュートリアルを学ぶためのワールドを遊べるようにします。
製品版までにどういうワールドを追加するかは検討中です。

ゲーム画面


ステージを選択するとゲーム画面に移り、ちょっとした会話シーンがあってからゲームが開始します。


画面左上の目標を実現するために、エディタでスクリプトを編集したり、API ドキュメントを参照したり、ヘルプを見たり、といったことが行なえます。

そして、Lua スクリプトを記述したら F5 キーを押して世界を再実行し、どんな感じで動作するかを眺めたりデバッグしたりします。

生産の例(実行速度 x4)

探索の例(実行速度 x1)

防衛の例(途中の実行速度 x64)

まとめと今後の予定

今のところ「最低限の機能があってゲームとして遊べなくはない」という状態で、開発全体から見ると折り返し地点の手前くらいの位置にいるつもりです。
引き続き実装していきます。

satofumi 2022/10/04 20:00

NPC をコーディングして領地運営するゲーム開発(タワーディフェンス的な防衛について)

前回の記事で「探索」について説明したので、今回は敵軍が攻めてくる要素である「防衛」について解説します。

防衛について

防衛とは、敵軍が定期的に敵の拠点から攻めてくるのを撃退する要素です。撃退できずに味方の城塞が壊されるとゲームオーバーです。(城塞のダメージは「修理資材」で回復できます)


敵軍を攻撃させるために、弓を持った領民を城塞や砦に配置すると敵軍を攻撃できるようにします。敵が進軍中かは Lua スクリプト経由で検出できるようにするので、その情報を使って領民を普段の仕事から防衛に切り替えるようなプレイを想定しています。

敵が侵攻してきたら防衛を指示するコード

   local militia = Character:new(edict)
   militia:setScript('militia')

   while world:beforeEnemyArmyAttack() > 0 do
      -- 敵が攻めてくるまでの秒数がゼロより大きければ待ち続ける。
      coroutine.yield()
   end
   
   -- キャラクターにメッセージを送信して行動を切り替えさせる。
   militia:setOrder('defense')

こういう敵の侵攻を監視するスクリプトを指令を出すための edict.lua スクリプトに記述しておき、敵が攻めてきたらキャラクターに防衛('defense') のメッセージを送り、防衛用の行動に分岐できるようにします。
それから、敵軍が攻めてくる道の脇に砦を建設して防衛できるようにします。敵軍と砦が隣接すると、敵軍は移動をやめて互いに攻撃し合うようにします。

ゲームにおける防衛の役割

防衛には大きく2つの目的があります。

1つ目は「ゲームプレイを安定させないこと」です。敵は侵攻を繰り返すごとにじわじわと強くしていく予定です。なので、次の侵攻を防ぐためには味方も少しでいいので強化する必要があります。なんというか「ここまで強化すれば絶対大丈夫」みたいな状態になることは避け「そろそろ防衛しづらくなってきたので、なんか強化するかな」と考えてプレイできることを目指しています。

2つ目は、ゲームプレイにバリエーションを持たせたいからです。例えば城塞に弓を持たせた領民を配置するときにも、普段は農耕をしている領民に防衛させるのか、弓の訓練をさせ続けた兵士に防衛させるかなどをプレイヤーに決めてほしいと思っています。

まとめと今後の予定

今回は防衛について解説しました。次回はスキルについて考えていることを記述します。

satofumi 2022/09/27 20:00

NPC をコーディングして領地運営するゲーム開発(冒険者パーティのダンジョン探索について)

このゲームの主な要素である「収集」「加工」「探索」「防衛」のうち、今回は冒険者パーティを編成してダンジョンの敵を倒す「探索」について解説します。

探索の役割

探索とは4人までのキャラクターを編成して、敵が待ち受けるダンジョンを探索させる機能です。ゲームはなるべくシンプルにしたいので、冒険者パーティは1つしか作れないようにします。


戦闘はダンジョンを攻略するか冒険者パーティが全滅するまで自動進行します。

冒険者パーティにキャラクターを追加して探索させるスクリプト

   -- キャラクターを冒険者パーティに追加する。
   local party = Party:new(edict)
   party:assign(swordsman)
   party:assign(spearman)

   while true do
      -- 最も近いダンジョンを検索させる。
      local dungeons = world:dungeons()
      if #dungeons <= 0 then
         break
      end
      local dungeon = dungeons[1]

      -- ダンジョンを探索させる。
      -- メンバー全員が集合して探索が開始されるまでブロックされる。
      -- メンバーは集合する前に装備を変更したり体力を回復したりできる。
      party:explore(dungeon)
   end

探索の目的は、運搬とクラフトだけだと地味になりがちなゲームに「ダンジョンを攻略する」というわかりやすい目標を追加することだったり、「戦闘シーンは見ていて楽しいよね」という意味合いがあります。

どんな展開になるか

ダンジョン攻略では複数の敵グループと戦闘して、最後の敵を倒すとダンジョンが解放されるようにします。ダンジョンは鉱山や森林の上にあって、解放することでそこから資源を収集できるようになります。

また、探索についてはダンジョン攻略に失敗してもキャラクターやアイテムのロストはなくし、がんがん冒険者を出撃させられるようにします。

そしてダンジョン攻略のためにより強い装備品のクラフトを目指したり、冒険者強化のために高価な料理の作成を目指すことがプレイヤーの目標になることを狙っています。

まとめと今後の予定

今回は「探索」要素である、冒険者パーティを編成してダンジョン探索するあたりについて記述しました。戦闘についてはスキル要素の追加も検討しており、また内容が確定したら記事にしていくつもりです。次回は最後のメイン要素であるタワーディフェンス要素の「防衛」について解説します。

satofumi 2022/09/20 20:00

NPC をコーディングして領地運営するゲーム開発(装備アイテムと料理アイテムの効果について)

このゲームは複数の NPC の行動を Lua スクリプトで記述していろんな仕事をさせるゲームなわけですが、今回はその仕事をするのに必要な装備アイテムと、仕事をして空腹になったときに食べる料理アイテムについての記事になります。

装備アイテムの効果とクラフト

このゲームで NPC が行うべきタスクは大きく分類すると「収集」「加工」「探索」「防衛」なのですが、どのタスクでも専用のアイテムを装備している必要があります。
例えば坑道で収集(採掘)するにはつるはし、ダンジョンを探索するには攻撃力の高い武器の装備が望ましい、といった具合です。

つるはしを装備して鉱山に移動して採掘する Lua スクリプトの記述

character:get(Items.Pickaxe)
character:equip()

local mine = world:buildings(Tiles.Mine)[1]
character:move(mine)
character:action()

この装備アイテムが必要な制限によって、場合によってはそのタスクに従事できる NPC の制限をすることや、タスクに従事できる NPC の数を急に増減できないことを狙っています。

料理アイテムの効果とクラフト

このゲームの NPC には満腹度のパラメータがあり、満腹度がゼロのときにはタスクを実行することができません。そして、時間経過で減る満腹度を回復させるのが料理アイテムです。

キッチンに移動してパンを取って食べる Lua スクリプトの記述

local kitchen = world:buildings(Tiles.Kitchen)[1]
while kitchen:count(Items.Bread) <= 0 do
   coroutine.yield()
end
character:move(kitchen:grid())
character:get(Items.Bread)
character:eat()

この料理アイテムは複数の種類を用意します。そして、勝利を食べると食べた NPC のパラメータに経験値が入って能力値が増加する仕組みを考えています。
例えば、肉料理を食べると STR(ちから)に、果物系の料理を食べると INT(賢さ)に経験値が入るといった具合です。

また、今のところ主人公は領主という設定なのですが、領主のパラメータの1割を全ての NPC のパラメータへの追加ボーナス値として加算する予定です。
なので、領主のパラメータを増加させるために、高級だけどコストのかかる料理をたくさん食べさせるような展開を考えています。

まとめと今後の予定

今回は、装備アイテムと料理アイテムについて解説しました。
次回は冒険者パーティを編成して、ダンジョンを「探索」させるあたりについて記述します。

1 2 3 4 5 6 7

月別アーカイブ

限定特典から探す

記事を検索