のののーと

ライフワークとライスワークの割合

基本的なカードバトルをつくる

週末開発その3。お互いに5枚のカードを使って相手のライフを0にするゲーム。ゲームはこちら

BasicCardBattle | 無料ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

f:id:nonoui:20180128220207p:plain

※unity version 2017.2.1

いろんなカードをつくりたーい

今回のゲームには5つのカードを用いる。

  • アタック -> 相手に攻撃
  • ガード -> 攻撃を防御
  • バフ -> 攻撃力上昇
  • カウンター -> 反撃
  • リカバリー -> 回復

実装方法としては、共通処理をまとめた親クラスを作成し、各カードごとの効果を子クラスに書くといった感じ。 ガードとカウンターは相手が攻撃した時に発動するため、他のカードと発動タイミングが違う。 そのため、相手の攻撃時に実行するメソッドも親クラスに用意した。 よって、他のアタックカードとかでも相手の攻撃時に何もしないメソッドが実行されてしまうのはどうなんだろうか...

バフカード

効果が重複可能で継続性のあるものをつくる。 本ゲームのバフカードは3ターン攻撃力が1.8倍という効果である。連続で使用すると、 1.8×1.8倍が一時的にかかるといった感じ。

とりあえず倍率とカウントを保持するバフクラスなるものを用意する。

public class Buff {
    public float rate;
    public int count;

    public Buff(float _rate, int _count) {
        rate = _rate;
        count = _count;
    }

    public void CountDown() {
        count--;
    }
}

そして、各キャラにはバフリストなるものを持たせて、それに関するメソッドを用意する。 バフの更新は毎ターンのはじめに一度行う。私はLINQ初心者だけど、各バフのカウントを減らして、効果が切れたバフを排除する 処理を2行で書けるのは素直に感嘆の声を漏らしそうだ。しゅごぃ...

バフの最終的な倍率を取得する際もLINQ使って書ければ万々歳なんだけど、リストの中身が独自クラスの場合の書き方が分からなくて結局for文で書いてしまった... 以下の記事を参考にAggregateを使えば、なんとかできないだろうか...

[C#]要素をすべて掛ける(乗算する)

using System.Linq;

   List<Buff> attackBuffList = new List<Buff>();// 攻撃バフリスト

    //バフの追加
    public void AddBuff(float rate, int count) {
        attackBuffList.Add(new Buff(rate, count));
    }

    //バフの更新
    public void UpdateBuff() {
        attackBuffList.ForEach(buff => buff.CountDown());
        attackBuffList = attackBuffList.Where(buff => buff.count >= 0).ToList();
    }

    //バフの倍率を取得
    public float GetTotalBuff() {
        var rate = 1f;
        for (int n = 0; n < attackBuffList.Count; n++) {
            rate *= attackBuffList[n].rate;
        }

        return rate;
    }

    //最終的な攻撃力を取得
    public int GetAttacOnBuff() {
        return (int)(attack * GetTotalBuff());
    }

ただ、今回は攻撃力のみに対応させればよかったけど、 RPGみたいに幅広いパラメータに対応させるためにはもっと柔軟にする必要がありそう。 一つ一つにリストを用意する...のも...んー...

バトル展開

バトル展開が長引くとマンネリ化しそうなので、強引に終わりへともっていく。 アタックカードは使えば使うほど追加攻撃力が増え、 防御や回復といったカードは、発動するほど効果が下がるようにした。

また、先行後行が決められない場合は、 先行の権利(画面上部にあるオレンジ色の旗)をもっているキャラが先行となるようにした。 これがランダムで決まってしまうと運要素が強くなってしまうと思ったので。

以上!

本当はTCGみたいに沢山のカードがってのを作ってみたかったけど、まずは少数のカードからって感じで。 少数のカードだからルールもカードゲームってよりもじゃんけんに近い感じになってしまった。

当初は7枚カードで1ターンに3枚使う感じだったんだけど、ちょっと作り始めたところで今の自分では週末に終わらないと察し、 更にゲーム内容を縮小した。

COMの思考ルーチンについては別記事にメモしようと思う。 → メモしました。 nonoui.hatenablog.jp

余談

uGUIの画像やテキストを移動させるときに以下のスクリプトまたはそれを継承したスクリプトをアタッチして使った。 週末開発その2で使ったスクリプトだけど、 今回もそのまま流用できたため、その分時間に余裕ができた。

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

public class GuiParts : MonoBehaviour {
    [HideInInspector] public float width{get; private set;}
    [HideInInspector] public float height{get; private set;}
    RectTransform rectTrans;

    protected virtual void Awake () {
        rectTrans = GetComponent<RectTransform>();
        var size = GetComponent<RectTransform>().sizeDelta;
        width = size.x;
        height = size.y;
    }

    public void MovePosition(Vector2 pos, float duration) {
        StartCoroutine(Move(pos, duration));
    }
    public void MovePositionInTheMoment(Vector2 pos) {
        rectTrans.localPosition = pos;
    }

    public void TransParent(Transform parent) {
        transform.SetParent(parent);
    }

    IEnumerator Move(Vector2 idealPos, float duration) {
        var startPos = (Vector2)rectTrans.localPosition;
        var endPos = idealPos;
        var timer = 0f;
        var rate = 0f;

        while (rate < 1) {
            timer += Time.deltaTime;
            rate = Mathf.Clamp(timer/duration, 0f, 1f);

            rectTrans.localPosition = Vector2.Lerp(startPos, endPos, rate);
            yield return null;
        }
    }
}

ライセンス表記

ゲームで3Dモデルをつかったので。 © Unity Technologies Japan/UCL