【Unity】カードゲームでドラッグ&ドロップによるカードプレイを実装する

Unity

現在、Unityでカードゲーム(トランプでなくTCGっぽいもの)を作成しています。

カードを手札からフィールドにプレイするときに、クリックで選択させるのではなくドラッグ&ドロップでプレイをするように実装しました。

ドラッグ&ドロップを実装するメリットについて

ドラッグ&ドロップでプレイするメリットとしては、カードをクリック→召喚と選択する場合と比較して、プレイヤー側の操作量が減ることです。

更に攻撃もドラッグ&ドロップで行えるようにすると、かなりスマートですね。選択肢式で実装すると、「アタックするカードを選ぶ」→「アタックする相手を選ぶ」という2段階になってしまいます。

また、配置する場所が重要になるタイプのカードゲームでは必須かなと思います。(自分の前のカードしか攻撃できないなど配置場所に意味があるタイプ)

デメリットとしては、手札や召喚時に効果を発揮するタイプの効果を実装しにくいという点ですね。手札時の効果を使う場合は結局、カードをクリックして使わせるという感じになってしまいます。

自分は次回作で、配置場所に意味を持たせるタイプのカードゲームを作りたいなと思っているので、このドラッグ&ドロップでカードを移動させる処理を実装しました。

そのコードについて、備忘のために記載しておこうと思います。

フィールドと手札の場を作る

これは、どんなタイプのゲームにするにも必要だと思いますが、フィールドの領域と手札の領域を作成します。自分は2Dでやっていますが、HorizontalLayOutGroupを使用することにしました。

HorizontalLayOutGroupを使用することで、カードを等間隔に並べることができます。

↓手前側を手札の領域、上の方のものをフィールドの領域に設定します。

↓オブジェクトには、HorizontalLayOutGroupを使用します。

フィールドに移動させるオブジェクト(カード)のスクリプト

次に、このフィールドに移動させるカードのオブジェクトにつけるスクリプトを作成します。

これは標準のIDragHandlerを使用しますが、気をつけなければいけない点としては

  • フィールドにドラッグされたらオブジェクトを移動する
  • フィールド以外の場所にドラッグされたらオブジェクトは移動しない
  • コストをオーバーしているときは移動しない

という実装をしなければいけない点です。

実際にカード側に実装したスクリプトは以下になります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class CardMove : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
    public new bool isMove;
    private Vector2 prevPos;
    public void OnBeginDrag(PointerEventData eventData)
    {
        prevPos = transform.position;
        GetComponent<CanvasGroup>().blocksRaycasts = false;
        isMove = false;
    }

    public void OnDrag(PointerEventData eventData)
    {
        transform.position = eventData.position;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (isMove)
        {
            if (コストが足りているか判定する)
            {
                transform.SetParent(Field);
            }
            else
            {
                transform.position = prevPos;
            }
        }
        else
        {
            transform.position = prevPos;
        }
        GetComponent<CanvasGroup>().blocksRaycasts = true;
    }
}

blocksRaycastsを一時的にfalseにして当たり判定をなくします。

OnBeginDragでisMoveというbooleanの変数にfalseを代入しています。この変数は後述するドラッグ完了処理が終わった時に、フィールドに配置されていればTrueにします。

そしてTrueでなければ、もともと保存しておいた場所に戻します。(予めカードの元の位置を記録しておく)

フィールド側にドロップされた時にフラグを立てるスクリプトを作る

次に、場に作成していたフィールド側(ドロップされるオブジェクト)似以下のスクリプトを記載します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class DropPlace : MonoBehaviour, IDropHandler
{
    public void OnDrop(PointerEventData eventData)
    {
        CardMove cm = eventData.pointerDrag.GetComponent<CardMove>();
        card.isMove = true;
    }
}

CardMoveというクラスは、前項で作成したカードオブジェクトに持たせるドラッグした際に呼び出されるクラスです。

ドロップの位置がフィールドであった場合には、上記クラスのisMove変数をtrueに変更します。

これでドラッグが完了したという判定になり、移動させる処理に移行させます。

参考にしたサイト

上記ですが、Unityゲームスタジオ スタジオしまづさんの動画をかなり参考にして作成させていただきました。

自分は文字だけなのでわかりにくい部分もあるかと思いますので、「オマエの説明よくわからねえ」という方は動画で公開されているものがおすすめです。

コメント

タイトルとURLをコピーしました