【プログラミング】CTBの実装方法

2017年09月19日

 微妙に需要がありそうなので、経験者としてCTB(カウントタイムバトル)の実装方法を解説してみます。

20140705_1.png

 参考:戦闘システム@ 行動順序システム

 内容はもろにプログラマ向けです。プログラムを組んだり、ツクールで自作システムを組んだりした人以外はピンとこないかもしれませんので、あらかじめお断りしておきます。

 なお、拙作ミスティックスターのCTBは、ツクール2000で実装していますが、アルゴリズム(処理手順)自体は汎用的に使えるはずです。ある程度の自由度がある開発環境ならば、流用可能です。

 作り方はいくつかありますが、まずは最も簡単な『素早さ加算方式』の実装方法から紹介します。

素早さ加算方式


 イメージとしては、FF7〜9のATBを思い浮かべてみれば、分かりやすいと思います。
 ATBゲージが満タンになったキャラが行動できるようになるアレですね。素早いキャラほど、ゲージが溜まる速度が上昇します。あれのリアルタイム性をなくしたものと思って頂ければ。
 ※FF4〜6は仕様が異なるので除外しています。興味がある人は調べてみてください。

  • 素早さ40のキャラ1
  • 素早さ50のキャラ2

 の二人がいた場合を想定すると……

  • キャラ1:40→ 80→120→160→……→ 800
  • キャラ2:50→100→150→200→……→1000

 というように、時間が立つごとに素早さ分だけゲージが増えていきます。
 ゲージ値が1000以上になったキャラがいれば、ターンが回ってきます。この場合はキャラ2の行動ターンが先に来ますね。
 ※もちろん、条件となるゲージ値は1000でも10000でも何でもいいです。ただし、あまり小さすぎると計算誤差が出るので注意です。

 キャラ2の行動が終われば、ゲージ値を−1000します。0にリセットしないのは、1000を超えた値が無駄にならないようにするため。毎回、ピッタリ1000になるわけではありませんので。

  • キャラ1:800→840→880→920→960→1000
  • キャラ2:  0→ 50→100→150→200→ 250

 後はこれの繰り返しです。
 その内に、素早さで勝るキャラ2が連続で行動するターンが発生します。それこそが、CTBの特色です。

 走る速さがバラバラな選手達が、何度もゴールを目指し、到達する度に最初から走り直すようなイメージでしょうか。
 ここで終わるなら、実のところCTBの実装は簡単です。一人ずつキャラの順番を処理すればよいという点では、ターン制よりも容易だと言えます。

 ところが、この『素早さ加算方式』には欠点があります。それは行動順序の予想が難しいことです。
 先程は計算が簡単な例で挙げましたが、これはどうでしょう?

  • 素早さ32のキャラ1 現在のゲージ値は300
  • 素早さ41のキャラ2 現在のゲージ値は150

  • キャラ1:300→332→364→……
  • キャラ2:150→191→232→……

 どちらが先にターンが回るか、即答できる人は少ないはずです。
 これが5人10人と増えていくと、もっと大変になります。
 CTBの実装に挫折する第一の関門はここでしょう。

 そんなわけで、『素早さ加算方式』では行動順序の表示が困難となります。
 そもそも、CTBとはFF10が呼称した方式であり、それに則れば順序表示がないものは厳密にCTBとは言えません。
 真のCTBを実装するためには、行動順序を把握できるような処理を考える必要があります。

WT減算方式


 ではどうするか――というと、もっと計算の簡単な形に変えてしまいます。
 『ゲージが溜まる速度』を比較するのではなく、『ゲージが溜まる時間』を比較すればよいのです。
 これは小学校レベルの知識で十分可能ですが、すんなりと思いつく人は意外と少ないと思います。自分も当初はここで詰まっていて、ある日ふと解決法を思いつきました。

 距離÷速さ=時間

 つまり……

 ゲージの長さ÷ゲージが溜まる速さ=ゲージが溜まる待ち時間(WT)

 となります。

  • 素早さ32のキャラ1: 1000÷32=31WTでゲージ満タン
  • 素早さ41のキャラ2: 1000÷41=24WTでゲージ満タン
  • 素早さ50のキャラ3: 1000÷50=20WTでゲージ満タン

 待ち時間(WT)が0になる度にターンが回ります。行動が終われば、再び元の待ち時間にリセットします。
 ※以降、待ち時間をWTと表記します。

 次の表は下に向かって時間が経過していくイメージです。

  キャラ1 キャラ2 キャラ3
↓ 31   24   20
↓ 11   04   00
↓ 07   00   16
↓ 00   17   09
↓ 22   08   00

 上記のように、各キャラのWTが遷移していきます。
 当然ながら、次に動くのはWTが最も小さなキャラです。どこを切り取っても、次に誰が行動するかは一目瞭然ですね。

 ※実際にCTBを実装する際には、『ゲージの長さ=1000』の部分にはもっと大きな値を設定することを勧めます。やはり小さすぎると計算誤差が出るためです。

 何のことはありません。既にタクティクスオウガなどでやっている手法です。
 タクティクスオウガではターンが回るまでの待ち時間(WT)をキャラが保有しており、レベルが上がる度に減少するようになっています。
 つまり、この方式は従来の素早さ方式をWT方式に変換しているだけとも言えます。

 ※タクティクスオウガのように最初からWTを使う方法でもよいのですが、プレイヤーには分かりにくいのが難点となります。また、ツールによっては実装自体が困難です。なんせ、レベルと共に減少するステータスなんてあまり見ませんので。

 ここで終わりたいところですが、そうはいきません。
 CTBの実装には第二の関門があります。

 今までの方法では、キャラ1とキャラ2のどちらが次に動くかが分かるようになりました。ですが、これではまだ二人の行動回数の差を表現することはできません。

20170919.png

 例:上の画像では、素早いキャラの順番が何度も表示されるようになっています。

  • キャラ1の素早さは25
  • キャラ2の素早さは20

 キャラ1が4回行動する間に、キャラ2は5回行動できる――ということは、何となく予想がつくと思います。
 しかしながら、その行動回数の差を画面上へ表示するにはどうすればよいでしょうか?

 例によって、まずは素早さをWTに変換します。

  • キャラ1:100 ÷ 25 = 4WT
  • キャラ2:100 ÷ 20 = 5WT

 これらが各キャラの基本WTとなります。
 これが減って0になれば行動。
 行動が終われば、またこの値にWTが戻ります。

 試しに、まずは人力で計算してみましょう。

  • 4WT後 → キャラ1のターン

 まずは最も早いキャラ1が動きます。これは簡単ですね。
 次に来るのはキャラ2か、あるいはキャラ1の二回目の行動か?
 人間なら直感的にキャラ2だと判断できますが、コンピュータはそうではありません。

  1. キャラ1の2回目の行動WT8 > キャラ2の1回目の行動WT5
  2. 従って、キャラ2の1回目の行動のほうが早い。

 というように、きちんと比較するよう指示せねばなりません。
 人数が増えてくると、それだけ手間も増えていきます。頭が痛くなるので考えたくもありません。

 もう少し、簡単な方法はないものか。
 というわけで、まずはキャラ1のターンだけを考えてみましょう。 
 10回まで行動順序を表示するシステムならば、10回分の行動を計算します。

  •  4WT後 → キャラ1のターン
  •  8WT後 → キャラ1のターン
  • 12WT後 → キャラ1のターン
  • 16WT後 → キャラ1のターン
  • 20WT後 → キャラ1のターン
  • 24WT後 → キャラ1のターン
  • 28WT後 → キャラ1のターン
  • 32WT後 → キャラ1のターン
  • 36WT後 → キャラ1のターン
  • 40WT後 → キャラ1のターン

 単なる掛け算なので、難しいことは何もありません。

 次にキャラ2がキャラ1のターンにどう割り込めるかを考えていきます。
 キャラ2のターンを同じように求めると……

  •  5WT後 → キャラ2のターン
  • 10WT後 → キャラ2のターン
  • 15WT後 → キャラ2のターン
  • 20WT後 → キャラ2のターン
  • 25WT後 → キャラ2のターン
  • 30WT後 → キャラ2のターン
  • 35WT後 → キャラ2のターン

 ちなみに40WT以降はどうあっても割り込めないので計算不要です。

 ここまでやれば後一歩。
 キャラ1のターンの隙間に、キャラ2のターンを挟んでいきます。
 具体的には、この二つをWT順でソート(並び替え)して合体させればよいでしょう。ソート後は表示に必要な10件までを保持します。

 より正確に書けば、
 『キャラクターID』と『WT』の組を構造体として保持し、『WT』をキーとして昇順でソートを行う。
 という感じになります。

 プログラム経験者以外にはわけわからんことを書いてる感じがしますが、そこはすみません。
 ただソート処理というのは、非常にありふれたものです。どの言語にせよ、ググればやり方はすぐに見つかるので、適当にパクってください。
 ツクールXP以降ではRuby、ツクールMVではJavaScriptなども使えるらしいので、問題ないかと思います。
 なお、ツクール2000でやるのは、それなりに大変でした。なんせ構造体も配列も何もない直接番地指定です。作者的にはもう二度と見たくないスパゲッティです。

 以下がソート結果です。

  •  4WT後 → キャラ1のターン
  •  5WT後 → キャラ2のターン
  •  8WT後 → キャラ1のターン
  • 10WT後 → キャラ2のターン
  • 12WT後 → キャラ1のターン
  • 15WT後 → キャラ2のターン
  • 16WT後 → キャラ1のターン
  • 20WT後 → キャラ1のターン
  • 20WT後 → キャラ2のターン
  • 24WT後 → キャラ1のターン

 ※20WTの時に、二人の行動がかぶっていますが、適当に優先順位をつけてください。普通にソートすれば、番号が若いキャラが優先されるはずです。

 これにて完了です。後はこの順番でキャラのアイコンなり名前なりを画面に出力するだけ。
 キャラ3以降が増えた場合も、同じように合体ソートすればよいだけなので問題ないでしょう。

 以上で解説終わりです。
 次はCTBを改造した新しい行動順序システムを発表したいと考えています。できれば、もう少し一般的に分かる内容で……。
posted by 砂川赳 at 09:47 | RPG制作講座 | このブログの読者になる | 更新情報をチェックする