この記事はデッキ構築型ハクスラローグライクカードバトルゲーム「呪術迷宮」の作り方講座の第4回です。
前回はカードオブジェクトのUIを作成しました。今回はカードをタップして移動させたり、手札からフィールドにカードを出すための機能を開発します。
前回の記事:
今回はプレイヤーの操作によって自由にカードを移動させます。
新たにカードを移動させるための処理を実装し、タップして好きなところまで移動。
指やマウスを離したら元いた場所に戻る処理も作ります。
また、DoTweenを使ってシンプルにカードアニメーションを実装する方法も習得していきましょう。
カードバトル処理をまとめるマネージャクラスを作成
プレイヤーが操作するカードのオブジェクトは画面上に何枚も同時に出現することになります。そのため、それらのオブジェクトを生成したりまとめて管理するためのクラスが必要になってきます(この講座ではマネージャクラスと呼称します)。
カードの移動処理についてもカード用のマネージャクラス内で実装していきますが、ある程度規模の大きいシーンになってくると「マネージャのマネージャ」が存在した方が全体の制御を行いやすくなります。
よって、まず最初にシーン全体を管理するBattleManagerクラスを新規に作成していきましょう。
スクリプトの作成場所はAssets/Scripts/Battle以下ですが、今後もマネージャクラスは複数作っていきますので更にManagersというフォルダを用意してその中に作成しても良いでしょう。
続けてカード用のマネージャクラスも作成しておきます。Field Area全体を管理してもらうことになるので名前はFieldManagerとしました。
まずはマネージャクラスの基本的な構造・扱い方を説明します。
FieldManager.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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// フィールド管理クラス /// </summary> public class FieldManager : MonoBehaviour { // オブジェクト・コンポーネント参照 private BattleManager battleManager; // 戦闘画面マネージャ // 初期化処理 public void Init (BattleManager _battleManager) { // 参照取得 battleManager = _battleManager; Debug.Log ("FieldManager.cs : 初期化完了"); } // Update void Update() { } } |
Unity標準機能の特殊メソッドであるStartを使用せず、代わりにInitというメソッドを自作してそこで初期化処理を行います。今後必要になる場合に備えて、戦闘画面全体のマネージャクラスであるBattleManagerへの参照を取得しています。
このInitを全体マネージャが呼び出すことになります。
BattleManager.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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 戦闘画面マネージャクラス /// </summary> public class BattleManager : MonoBehaviour { // 管理下コンポーネント public FieldManager fieldManager; // フィールド管理クラス // Start void Start() { // 管理下コンポーネント初期化 fieldManager.Init (this); Debug.Log ("BattleManager.cs : 初期化完了"); } // Update void Update() { } } |
先ほどのFieldManagerの参照はInspectorから設定し、それをもとにStart内にてInitを呼び出しています。Initを呼び出す時は自身への参照をthisで渡しています。
今後新しくマネージャクラスを作成した際も全てこのBattleManagerクラスがそれぞれの参照を取得し、初期化を行います。
以上2つのスクリプトを実行するため、シーン内にオブジェクトを作成してアタッチしていきます。
マネージャクラスをアタッチする専用の空オブジェクト、Managersを新規作成します。UIではないのでCanvasの外に作成してOKです。
そしてBattleManager、FieldManagerを順番にアタッチします。
まだBattleManagerコンポーネントのfieldManagerパラメータが未設定ですので、FieldManagerコンポーネントをドラッグ&ドロップして参照を設定します。
これで実行を行うと2つ分の初期化処理が順番に呼び出されていることが確認できます。
FieldManager側の初期化処理をStartではなく自作メソッドに変更した理由が「順番に」を実現するためにあります。
シーン内にStartメソッドを呼び出すコンポーネントが複数あった場合、それらがどの順番で呼び出されるかというのは基本的にスクリプト内からは予測できません。
これは初期化処理の順番が大事なゲームを作る場合に致命的になってしまいます。
エディター上でExecutionOrderというものを設定すればある程度コントロール可能ですがあまり推奨される設定ではありません。
スクリプト内で初期化の順番を制御するためにマネージャクラスはこのような実装にしていきます。
補足:publicとprivate
Inspectorから設定を行うためにBattleManagerの11行目、fieldManager変数(フィールド)はpublic属性で宣言されています。publicで宣言した変数はInspectorから値を変更できるようになり、他のクラスからも変数の値に対して読み取り・変更を行うことができます。
反対にprivateで宣言を行うとInspectorに表示されず、他のクラスから直接触ることも出来なくなります。一見ただ機能を制限するだけですが、無暗にpublicを多用するとプログラム全体の保守性・視認性などが低下するため一般にはほとんどの変数はprivateで宣言するべきとされています。
privateな変数であっても[SerializeField]属性を付与するとInspectorからの設定のみ行えるようになります。例えば以下のような形です。
1 |
[SerializeField] private FieldManager fieldManager = null; // フィールド管理クラス |
この講座ではシンプルな実装をメインに行うため今後もpublic変数を使用していきますが、自信のある方はぜひprivateへの置き換えにもチャレンジしてみてください。
Unityで手札カードオブジェクトを作成しよう
以降はFieldManagerクラスとCardクラスを拡張していき、「カードをドラッグ操作で移動できる」機能を実装していきましょう。ゲームの実行中にオブジェクトをプレハブから新規作成する方法も学びます。
これで実行すればカードのドラッグ操作が有効になっていることが確認出来ます。もしエラーが発生する場合はスクリプトのミス、Inspectorでの設定忘れを確認してください。
Unityでカードの移動アニメーションを作成する(DOTween)
今後頻繁に使用することになるDOTweenによるアニメーション・非同期処理の実装方法についてこの段階で学んでおきましょう。
このゲームではカードをドラッグした後、何もない場所に置かれたら元居た位置に戻るという処理が必要になります。今回はその戻るという処理をアニメーションにて実装してみます。
複数存在するDOTweenの機能の中で「少しずつ移動」「少しずつ色変更」などのシンプルなアニメーションはTweenという型を使って実装します。RectTransformに対してDOMoveというメソッドを呼び出せばそれだけで簡単に実現してくれます。
Card.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 61 62 63 64 65 66 67 68 69 70 71 72 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using DG.Tweening; /// <summary> /// カード処理クラス /// </summary> public class Card : MonoBehaviour, IPointerDownHandler, IPointerUpHandler { // オブジェクト・コンポーネント参照 private FieldManager fieldManager; // フィールド管理クラス public RectTransform rectTransform; // オブジェクトのRectTransform // 各種変数 private Vector2 basePos; // 基本座標(ドラッグ終了後に戻ってくる座標) private Tween moveTween; // 移動Tween // 初期化処理 public void Init (FieldManager _fieldManager) { // 参照取得 fieldManager = _fieldManager; // 変数初期化 basePos = Vector2.zero; } // Update(毎フレーム1回ずつ実行) void Update() { } /// <summary> /// 基本座標までカードを移動させる /// </summary> public void BackToBasePos () { const float MoveTime = 0.4f; // カード移動アニメーション時間 // 既に実行中の移動アニメーションがあれば停止 if (moveTween != null) moveTween.Kill (); // 指定地点まで移動するアニメーション(DOTween) moveTween = rectTransform .DOMove (basePos, MoveTime) // 移動Tween .SetEase (Ease.OutQuart); // 変化の仕方を指定 } /// <summary> /// タップ開始時に実行 /// IPointerDownHandlerが必要 /// </summary> /// <param name="eventData">タップ情報</param> public void OnPointerDown (PointerEventData eventData) { // ドラッグ開始処理 fieldManager.StartDragging (this); } /// <summary> /// タップ終了時に実行 /// IPointerUpHandlerが必要 /// </summary> /// <param name="eventData">タップ情報</param> public void OnPointerUp (PointerEventData eventData) { // ドラッグ終了処理 fieldManager.EndDragging (); } } |
- 変数をconstで宣言すると定数となり、実行中に変化されない数値となります。
- DOTweenの機能の呼び出しには「using DG.Tweening;」が必要です。
- DOMoveなどで実行したアニメーションへの参照はTween型変数にて保存が可能です。Tween.Kill()を呼び出せば該当アニメーションの途中終了が可能です。
47~49行目でカードのRectTransformに対して移動アニメーション処理であるDOMoveを呼び出して開始しています。
DOMoveの第1引数に移動先の座標、第2引数にアニメーション全体にかかる時間(秒単位)をfloat型で入力しています。
更にSetEaseという処理をDOMoveに対して追加で呼び出すことによって、対象アニメーションがどのような変化の仕方をするのか設定することが出来ます(後述)。
FieldManager.cs内 EndDragging()
1 2 3 4 5 6 7 8 9 10 11 |
/// <summary> /// カードのドラッグ操作を終了する /// </summary> public void EndDragging () { // カードを元の位置に戻す draggingCard.BackToBasePos (); // 後処理 draggingCard = null; } |
動作確認のため、とりあえずドラッグ操作終了時に上記のアニメーションを再生する設定にしました。
これで実行すれば、カードの移動中に手を離した時カードが画面中央にアニメーションしながら戻るようになっています。
先ほどのSetEaseにて「Ease.OutQuart」というEaseを指定したため、移動を開始する瞬間に高いスピードで目標地点に近づき、近づいたら減速するというようなアニメーションになっています。
Easeには標準で沢山の種類が用意されており、例えばEase.Linearを指定すると加減速なしで機械的な移動になります。
他にも面白い所ではEase.OutBackにすると「目標地点を一旦通り越して元に戻る」という動きになります。
今回はEase.OutQuartを使いますが、今後アニメーションの種類によって適宜使い分けていきます。ちなみにSetEaseを使わなかった場合、基本的にEase.OutQuadと同じ動きになります。
その他のEaseについては公式のドキュメントを参照してください。
まとめ
カードオブジェクトの作成と手札、フィールド等を行き来できるようタップ処理等、基本的なカードUI操作処理の実装が完了しました。
また、DOTweenによるアニメーションの実装についても学びました。今後もアニメーション・非同期処理は多用していきますので少しずつ慣れていきましょう。
カードごとの名前や効果などの表示、効果の発動処理等についてはやらなければならない準備がまだ数多くあります。少しずつステップアップしながら実現していきましょう。
次の記事:
コメント