現場レベルのゲーム制作が、すべてここで学べます。
この講座は3Dダンジョン探索型RPGの作り方について説明しています。今回はその第7回目になります。
前回はアクターとエネミーが戦闘中に使用するスキルの実装を行いました。
前回の記事:

ここからはこのゲームの戦闘システムにおいて重要になるCTB(カウントタイムバトル)の実装に着手していきます。
カウントタイム表示用UIを作成し、各キャラクターの行動速度順にUIを並び替えていく処理を実装します。3DダンジョンRPGに関わらず、UIを何かのパラメータ順で並び替えていく手法など応用性の高いテクニックをここで習得していきましょう。
カウントタイムバトルについて
戦闘に参加する全てのキャラクターの速度(speed)パラメータを参照し、速度の高いキャラクターほど先に行動できるターン制バトルを設計します。
カウントタイムバトルにおいてさらに特徴的なのはここにアクションポイントの概念が追加されることです。
これによって全てのキャラクターのターンが一巡しなくても、速度が十分に高いキャラクターであればより頻繁にターンが回ってくるようになります。単純に順番に行動するだけじゃないわけですね。
カウントタイムバトル仕様について
カウントタイムバトルの仕様について説明します。
まず、キャラクターは戦闘に参加するときに10000のカウントが与えられます。
そして誰かのカウントが0以下になるまで全キャラクターの残りカウントを、そのキャラクターの速度パラメータ分だけ減算することを順番に繰り返します。
最初に自身の残りカウントを0以下にしたキャラクターにターンが周ってきます。
アクターのターンでは「通常攻撃」や「スキル使用」などの行動を選びます。
エネミーターンの場合はそのエネミーに登録されているスキルの中からランダムに選ばれて使用されます。
各スキルの処理を終えたあとターンが終了し、そのキャラクターには再び10000のカウントが与えられます。
そして全キャラクターのカウントが速度パラメータ分だけ減算するループに戻ります。
次にカウントが0以下になったキャラクターにターンが周ってきます。
戦闘処理の流れとしてはこんな形です。
ゲーム中では戦闘画面の左上にカウントタイムUIをキャラクターの数だけ表示します。
各UIにはキャラクターの顔アイコン画像と残り行動値の表示を行います。
行動値は「残りカウント÷速度」で算出します。だいたい1~3ケタの数字になるので、最大5ケタの残りカウントをそのまま表示するよりプレイヤーに伝わりやすいです。(キャラクター同士の速度差も直感的に分かりやすくなります。)
カウントタイムUIは残り行動値の大きさに応じて自動的に並べ替えます。これにより、基本的に一番目に表示されているキャラクターに次のターンが回ってくることが視覚的にわかりやすくなります。
カウントタイムUI作成
まずはカウントタイムUIのプレハブから作成していきましょう。
CountTimeUIAreaオブジェクト以下に、ImageオブジェクトとしてCountTimeUIを作成します。
(前回までの配布用サンプルプロジェクトでCountTimeUIAreaがGameObject表記のままになっていたのでサンプルファイルを活用してる場合は「CountTimeUIArea」にリネームしてください)。
- RectTransform:Positionは(0,0)、サイズは(100, 44)
- Image – Source Image:Assets/Textures/GUIs/RoundWindow_A.png
- Image – Image Type:Slicedを選択、Pixel Per Unit Mulitilerは7
枠画像を表示したいのでRoundWindow_A.pngを選びましたが、画像ファイルが縦と横同じ長さで作られているのに対し、今回のUIオブジェクトはやや横長で作成します。
この場合、画像のレイアウトを崩すことなく表示できる機能として9 Sliceと呼ばれるものがあります。ここでは詳細を割愛しますが、画像を9つの領域に分割することで縦長・横長の表示にも対応できるというものです。
講座で配布している一部のサンプル画像については予めこの9 Sliceの設定を済ませていますので、それをUIとして画面に表示する際に[Image Type – Sliced]を選ぶことで設定を適用した表示に切り替える事ができます。
またPixels Per Unit Multipilerの値を変更することで、9 slice適用下での画像の形を変更することができます。例えば四隅が丸すぎる・角ばっているといった現象が起きた場合はこの値を表示することで改善できる場合があります。

(Image – CountTimeUI)キャラクター顔アイコン画像_CharaFaceIcon
カウントタイムUI内でキャラクターの顔アイコン画像を表示するImageオブジェクト、CharaFaceIconを作成します。
- RectTransform:Positionは(-6, 0)、サイズは(88, 44)
- Image – Source Image:Assets/Textures/ActorPicture/Face 以下の適当な画像(確認用)

(Image – CountTimeUI)キャラクター名表示UI背景_ActorNameBack
キャラクターの名前を表示するUIの背景として下側の一部を暗くするためのImageオブジェクト、ActorNameBackを作成します。
- RectTransform:Positionは(0, -16)、サイズは(100, 12)
- Image – Source Image:なし
- Image – Color:やや薄めの黒色

ここで気にしておくと良い点として、背景画像が角丸になっているのに対してこのImageUIは長方形で表示されます。したがって両側の隅が少しはみ出て表示されてしまっています。

これは後ろに表示されるImageオブジェクトに対してMaskコンポーネントを付与することで防ぐことができます。
Maskコンポーネントがあると子オブジェクトのUIに対して、自身が表示していない領域への表示を行わせないようになります。

(TextMeshPro – ActorNameBack)キャラクター名テキスト_ActorName
キャラクターの名前をテキストとして表示するTextMeshProオブジェクト、ActorNameを(ActorNameBackの子に)作成します。
- RectTransform:AnchorsをStrechにし、Left・Top・Right・Bottomを全て0
- TextMeshPro – Text:空欄もしくは任意の文字列(確認用)
- TextMeshPro – Font Asset:Assets/Fonts/MPLUS1p-Regular SDF
- TextMeshPro – Material Preset : MPLUS1p-Regular SDF_BlackShadow
- TextMeshPro – Font Size:12.5
- TextMeshPro – Alignment:中央揃え

(Image – CountTimeUI)残り行動値テキストUI背景_CountTextBack
キャラクターの残り行動値を表示するUIの背景として右上の一部を暗くするためのImageオブジェクト、CountTextBackを作成します。
- RectTransform:Positionは(30, 11)、サイズは(43, 22)
- Image – Source Image:Assets/Textures/GUIs/RoundWindow_A.png
- Image – Color:やや薄めの黒色
- Image – Image Type:Slicedを選択、Pixel Per Unit Mulitilerは16
- Image – Maskable:オフ(任意)

Maskableをオフにすることで、先ほど設定したMaskコンポーネントの影響を受けずに画像の表示を行うこともできます。お好みで設定変更してください。
(TextMeshPro – CountTextBack)残り行動値テキスト_CountText
残りの行動値をテキストとして表示するTextMeshProオブジェクト、CountTextを(CountTextBackの子に)作成します。
- RectTransform:AnchorsをStrechにし、Left・Top・Right・Bottomを全て0
- TextMeshPro – Text:空欄もしくは任意の文字列(確認用)
- TextMeshPro – Font Asset:Assets/Fonts/NotoSans_BlackShadow
- TextMeshPro – Font Size:21
- TextMeshPro – Alignment:中央揃え

カウントタイムUI処理スクリプト実装
このカウントタイムUIにキャラクター名とアイコン画像、残り行動値を表示設定するためのスクリプトとしてCountTimeUIを作成します。
CountTimeUI.cs (新規)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
using UnityEngine; using UnityEngine.UI; using TMPro; /// <summary> /// (Battle) CountTimeUIManager配下 /// カウントタイムUI処理クラス /// </summary> public class CountTimeUI : MonoBehaviour { // オブジェクト・コンポーネント [SerializeField] private RectTransform rectTransform = null; [SerializeField] private Image backgroundImage = null; // UI背景Image [SerializeField] private Image characterIconImage = null; // キャラクターアイコンImage [SerializeField] private TextMeshProUGUI nameText = null; // キャラクター名Text [SerializeField] private TextMeshProUGUI countText = null; // カウント表示Text // 現在の背景画像Color private Color nowBackgroundColor; // 定数定義 private static readonly Color BGColor_Actor = new Color (0.1f, 0.1f, 0.3f, 0.6f); // 背景画像Color(味方キャラクター) private static readonly Color BGColor_Enemy = new Color (0.3f, 0.1f, 0.1f, 0.6f); // 背景画像Color(敵キャラクター) // 初期化関数(CountTimeUIManager.csから呼出) public void Init (CharacterData characterData) { // UI初期化 nameText.text = characterData.characterName; // CharacterDataがアクターかエネミーかを判定し、立ち絵表示を行う if (characterData is ActorData) {// アクターデータの場合 // アクター表示用カラー設定 nowBackgroundColor = BGColor_Actor; backgroundImage.color = nowBackgroundColor; // アクター顔アイコン画像設定 characterIconImage.sprite = Data.instance.ActorFaceIconsRess[((ActorData)characterData).pictureID]; } else {// エネミーデータの場合 // エネミー表示用カラー設定 nowBackgroundColor = BGColor_Enemy; backgroundImage.color = nowBackgroundColor; // エネミー顔アイコン画像設定 characterIconImage.sprite = ((EnemyData)characterData).faceIconSprite; } } /// <summary> /// 残りカウントUI表示 /// </summary> public void SetCount (int count) { // 残りカウントUI表示 if (count < 0) count = 0; countText.text = count.ToString (); } } |
Initメソッド内において、このカウントタイムUIが担当するキャラクターはアクターなのかエネミーなのかを判別し、それによって表示色を変更しています。
判別についてはCharacterDataへの参照が渡されるので、それがActorDataクラスとして作成されているならアクターであると判定し、そうでなければエネミーである(EnemyDataクラスである)と判定します。
クラスが指定したものと同じであるかを取得する機能としてis演算子があります。今回のようにクラスの派生を行っている場合にはよく利用しますので少しずつ覚えていくと良いでしょう。
スクリプトのアタッチ・カウントタイムUIのプレハブ化
スクリプトを作成できたら、これをCountTimeUIオブジェクトにアタッチして各種参照へのセットをInspectorから行います。

RectTransformとBackGround Imageへの参照は同じオブジェクトから、残り3つはそれぞれのオブジェクトを対象にします。
ここまで実装できたらカウントタイムUIオブジェクトをプレハブ化し、シーン内にあったものは削除して完了です。

CountTimeUIAreaでの整列対応
この後CountTimeUIArea以下にカウントタイムUIプレハブのインスタンスを複数生成し、並べて表示させる処理をとります。
なのでCountTimeUIAreaオブジェクトにVertical Layout Groupコンポーネントをアタッチしておき、自動的にUIの整列が行われるようにしておきましょう。
- Vertical Layout Group – Padding:LeftとTopをそれぞれ6
- Vertical Layout Group – Spacing:4
- Vertical Layout Group – Child Alignment:Upper Left
- Vertical Layout Group – Use Child Scale:WidthとHeightをオン
- Vertical Layout Group – Child Force Expand:WidthとHeightをオフ

カウントタイムバトル進行処理
カウントタイムUIへの行動値などの表示、および速度がもっとも高いキャラクターに最初にターンが周ってくる事を確認できるまでの状態をスクリプトで実装していきます。
まずはカウントタイムシステム全体を管理するクラスとしてCountTimeManagerを作成します。
CountTimeManager.cs (新規)
まとめ

カウントタイムシステムによって速度パラメータをベースとしてキャラクターにターンを与える処理を実装しました。
次章からはターン中に行える行動を、まずは通常攻撃から実装していきます。
アクター側の通常攻撃から実装しますので、最初にターンを迎えるキャラクターがアクターキャラクターでない場合は各キャラクターの速度値を調整しておいてください。
Data.cs内でテスト用に作成しているアクターの速度の最低値は35なので、各エネミーの速度を35未満にすれば確実にアクターから行動させることができます。

次の記事:

現場レベルのゲーム制作が、すべてここで学べます。






コメント