ゲーム化!tomo_manaのブログ

ゲーム化!tomo-manaのブログ

Unityでゲームを作る方法について紹介しています

Unity学習#10 (Unity 2019.4.1f1) フェードイン・アウト#2~ワープ処理との結合

画面のフェードイン・アウトが思ったよりコード量があるので、前回と今回の2回の記事に分けました。今回は第9回で作ったフェードイン・アウト処理と第8回のワープ処理をくっつけます。

フェードイン・アウトのインタフェース(第9回)

前回のフェードイン・アウト処理を参照するためには、以下を追加します。

コード

private FadeManager fader;

// 処理
if ( fader.IsFading() == false ){
    fader.FadeIn();
}

ただし、フェードイン・アウトの処理を行う間、ワープ処理は待つ必要があるので、ワープ処理内に状態を持たせる必要があります。

ワープの状態

状態遷移図

キャラクターがワープポイントに衝突した時、ワープポイントはフェードアウトを待ってワープします。ワープした後、フェードインを待ってワープポイントは再びキャラクターが衝突してくるのを待ちます。
これを状態遷移図にすると以下になります。

1) 衝突待ち
↓ 衝突
2) フェードアウト
↓ 完了
3) ワープ
↓ 完了※
4) フェードイン
↓ 完了
1) 衝突待ち
※実際は、3) ワープ処理は、同一平面での座標移動の場合は「待ち」が発生しないので、今回は状態でなく処理の一部にします。今後、マップの読み込みなどで時間がかかる場合は「待ち」にする可能性があるかもしれません。

状態遷移表

イベントと状態を整理して、状態遷移表を作ります。

f:id:tomo_mana:20200728083203p:plain
ワープの状態遷移表

ワープの修正

状態定義

状態を列挙体で定義します。
コード

    enum WarpState {
        Idle,
        Triggered,
        FadeOut,
        FadeIn
    }
    private WarpState state;

イベント処理の追加

今回は、イベントが「衝突」以外はすべて「フェード処理完了」になるので、Update() 関数の中で一つのif文にまとめています。

コード

public class Warp : MonoBehaviour
{
    // ワープ中の状態
    enum WarpState {
        Idle,
        Triggered,
        FadeOut,
        FadeIn
    }
    private WarpState state;
    
    // Start is called before the first frame update
    void Start()
    {
        state = WarpState.Idle;
    }
    
    // Update is called once per frame
    void Update()
    {
        if( state != WarpState.Idle ){
            if( fader.IsFading() == false ){
                // 次の処理へ
                switch( state ){
                    case WarpState.Triggered:
                        state = WarpState.FadeOut;
                        break;
                    case WarpState.FadeOut:
                        state = WarpState.FadeIn;
                        break;
                    case WarpState.FadeIn:
                        state = WarpState.Idle;
                        break;
                    default:
                        break;
                }
            }
        }
    }
    
    void OnTriggerEnter2D (Collider2D other) {
        if( state == WarpState.Idle )
        {
            state = WarpState.Triggered;
        }
    }
}

衝突時の処理からワープ処理をくくりだす

isTriggerで使うことができたCollider2Dを直接使えなくなる(参照が変わる)ため、ワープポイントにぶつかったキャラクターCollider2Dをワープポイントは覚えておかなければなりません。

コード(修正前)

public class Warp : MonoBehaviour
{
    private Vector3 target;  // ← ワーク
    
    void OnTriggerEnter2D (Collider2D other) {
        target = other.gameObject.transform.position;
        target.x = warpPoint.x;
        target.y = warpPoint.y;
        other.gameObject.transform.position = target;
    }
}

コード(修正後)

public class Warp : MonoBehaviour
{
    private Collider2D target;  // ← ワープポイントに衝突したCollider(キャラクター)を保持
    private Vector3 v;  // ワーク

    // ワープ処理    
    void WarpTarget()
    {
        v = target.gameObject.transform.position;
        v.x = warpPoint.x;
        v.y = warpPoint.y;
        target.gameObject.transform.position = v;
    }
    
    void OnTriggerEnter2D (Collider2D other) {
        target = other;
        WarpTarget();
    }
}

状態遷移処理の実装

下準備ができたので、いよいよ状態・イベントにフェードイン・アウトとワープ処理を追加します。

コード

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

public class Warp : MonoBehaviour
{
    public Vector2 warpPoint;
    private Collider2D target;  // ← ワープポイントに衝突したCollider(キャラクター)を保持
    private Vector3 v;
    
    private FadeManager fader;
    
    // ワープ中の状態
    enum WarpState {
        Idle,
        Triggered,
        FadeOut,
        FadeIn
    }
    private WarpState state;
    
    // Start is called before the first frame update
    void Start()
    {
        state = WarpState.Idle;
    }
    
    // ワープ処理
    void WarpTarget()
    {
        v = target.gameObject.transform.position;
        v.x = warpPoint.x;
        v.y = warpPoint.y;
        target.gameObject.transform.position = v;
    }
    
    // Update is called once per frame
    void Update()
    {
        if( state != WarpState.Idle ){
            if( fader.IsFading() == false ){
                // 次の処理へ
                switch( state ){
                    case WarpState.Triggered:
                        fader.FadeOut();
                        state = WarpState.FadeOut;
                        break;
                    case WarpState.FadeOut:
                        WarpTarget();
                        fader.FadeIn();
                        state = WarpState.FadeIn;
                        break;
                    case WarpState.FadeIn:
                        state = WarpState.Idle;
                        break;
                    default:
                        break;
                }
            }
        }
    }
    
    void OnTriggerEnter2D (Collider2D other) {
        if( state == WarpState.Idle )
        {
            target = other;
            state = WarpState.Triggered;
        }
    }
}

ワープ時に、フェードアウト・インがかかるようになり、いい雰囲気になりました。

エフェクトの着脱

ワープのエフェクトを元に戻すことはさほど大変ではない(コードを戻すだけ)ですが、今後、特定のワープに他のエフェクトを付けたい場合のため、FadeManagerをプログラムの外に出して、付け替えができるようにします。
コード

public class Warp : MonoBehaviour
{
    [SerializeField] FadeManager fader;

    void OnTriggerEnter2D (Collider2D other) {
        if( state == WarpState.Idle )
        {
            target = other;
            if( fader == null ){
                WarpTarget();
            } else {
                state = WarpState.Triggered;
            }
        }
    }
}

※実際に他のエフェクトを作った場合は、FadeManager は Interface にしないといけないと思いますが、そのうちに考えます。

これからやること

なんかそれっぽくなってきて、心に火がついてきました。ここからはどの順番でやるか選択していく必要があります。まず面白さの追求より基本のエンジンを観察していくので、以下のようにします。(面白さ=ゲームバランスは後から追求します)

(1) 基本:

  • ステータス画面(HP、速度だけ)
  • 戦闘画面

 絶対勝つ戦闘(クリアのデバッグ
 絶対負ける戦闘(ゲームオーバーのデバッグ
 ゲームオーバーの定義

  • キャラクターエンカウント(当たり判定の利用)
  • ボスエンカウント(当たり判定→戦闘→フラグ設定)
  • マルチシーン(タイトル、ゲーム、エンディング)

(2) シナリオの発生:

  • イベントフラグ(ダンジョンクエストの解放、ボス戦の解放)

(3) ゲームバランス(駆け引き)の追求:

  • ランダムエンカウント
  • 会話の発生(当たり判定の利用)
  • アイテムの追加―アイテム屋(回復、速度UP、速度DOWN、攻撃UP、攻撃DOWN、効果をはじく)
  • 武器の追加(攻撃UP+アイテム効果付与)
  • 貨幣の追加

※今回はマップをシングルシーンで作成しましたが、マルチシーンで作成する方法は全部作ってから挑戦します。

  • ランダムダメージ

 ランダムダメージ
 会心の一撃、痛恨の一撃

(4) 長編化

  • マルチシーン(シーン間のマップ移動、シーン間のデータ共有)
  • ロード・セーブ