0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Unity]2D牧場ゲームを作ってみる その4[キャラクターの移動・会話処理を切り分け]

Last updated at Posted at 2022-02-14

前置き

  • 前回の記事で、他のキャラクターに話しかけたときにメッセージを表示をするように実装しました。

  • 今回作成するものは大きく分けて以下の2つになります。

    • 主人公のキャラクターが会話している時は移動処理をしない。
    • 会話が終了したら移動処理に切り替えるようにする。
  • 前回までの実装した動きは以下になります。

    • 会話中にキーを押しているため、ずっと右に進んでいますね…。
    • 会話中は移動しないように修正していきます。

GameProject_1_2022-02-12_00-42-20.gif

今回作成するもの

  • 1.キャラクターの移動・会話処理の切り分けスクリプトMoveAndTalkCharaの追加
  • 2.メッセージ表示のスクリプトMessageCharactorの変更
  • 3.フィールドオブジェクトの基本処理のスクリプトFieldObjectBase.csの変更
  • 4.キー操作にあわせアニメーションに状態をわたすスクリプトAnimationStateController.csの変更

1.キャラクターの移動・会話処理の切り分けスクリプトMoveAndTalkChara.csの追加

  • 新規にMoveAndTalkChara.csを作成しました。このスクリプトは主人公のキャラクターの移動と会話処理を切り分けるものとなります。
  • 1-1~1-4で説明をした後、1-5でMoveAndTalkChara.csの全体を載せます。

1-1.キャラクターの状態を列挙型で作成

  • キャラクターが移動している状態、会話している状態を列挙型で作成し、キャラクターがその状態を保持できるようにします。
  • 移動している状態はnormal、会話している状態はtalkと設定します。他の状態を作成する時は、CharacterStateに追加していきましょう。
  • キャラクターの状態をcharacterStateに保持するようにします。
    public enum CharacterState{
        normal,
        talk
    }
    private CharacterState characterState;

1-2.Updateメソッドで行動処理を分ける

  • Updateメソッドで、行動処理をわけます。
  • キャラクターが移動している状態ではMove()、会話している状態ではTalk()と呼び出すようにします。
  • animationStateController.~は4のAnimationStateController.csで説明します。
    void Update(){


        if(characterState == CharacterState.normal){
            animationStateController.MoveAnimation();
            Move();
        }else if(characterState == CharacterState.talk){
            animationStateController.NoMoveAnimation();
            Talk();
        }
        
    }

1-3.MoveとTalkメソッド

  • UpdateメソッドでMoveとTalkメソッドを呼び出しているのでその中身を記述します。
  • MoveではMoveController.csのコードを設定します。そのためMoveController.csは不要になるため、主人公のキャラクターのInspectorからチェックを外しましょう。
  • Talkは会話中に何かしら処理を入れたい時に入れましょう。
    void Move(){
        // 入力を取得
        input = new Vector2(
            Input.GetAxis("Horizontal"),
            Input.GetAxis("Vertical"));

        if (input == Vector2.zero) {
            return;
        }
        rigidBody.position += input * SPEED * Time.deltaTime;

        
    }

    void Talk(){
        
    }

1-4.主人公の状態の取得と設定の処理

  • 主人公の状態を取得したり、状況を切り替える必要があるので、そのための処理を記述します。
    // 状態確認メソッド
    public CharacterState GetState(){
        return characterState;
    }

    // 状態変更メソッド
    public void SetState(CharacterState setState){
        characterState = setState;
    }

1-5.MoveAndTalkChara.csの全体

  • 1~1から1~4で説明したコードをまとめたいと思います。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class MoveAndTalkChara:MonoBehaviour{

    public float SPEED = 0.5f;
    private Rigidbody2D rigidBody;
    private Vector2 input;
    public enum CharacterState{
        normal,
        talk
    }
    private CharacterState characterState;
    AnimationStateController animationStateController;
    Animator animator;
    
    void Start(){
        this.rigidBody = GetComponent<Rigidbody2D>();
        characterState = CharacterState.normal;
        this.animator = GetComponent<Animator>();

        animationStateController = GameObject.Find("char_crol_0").GetComponent<AnimationStateController>();
    }
    void Update(){


        if(characterState == CharacterState.normal){
            animationStateController.MoveAnimation();
            Move();
        }else if(characterState == CharacterState.talk){
            animationStateController.NoMoveAnimation();
            Talk();
        }
        
    }

    void Move(){
        // 入力を取得
        input = new Vector2(
            Input.GetAxis("Horizontal"),
            Input.GetAxis("Vertical"));

        if (input == Vector2.zero) {
            return;
        }
        rigidBody.position += input * SPEED * Time.deltaTime;

        
    }

    void Talk(){
        
    }

    // 状態確認メソッド
    public CharacterState GetState(){
        return characterState;
    }

    // 状態変更メソッド
    public void SetState(CharacterState setState){
        characterState = setState;
    }
}

2.メッセージ表示のスクリプトMessageCharactor.csの変更

  • MessageCharactor.csに3つのコードを追加しました。
    • moveAndTalkChara.SetState(MoveAndTalkChara.CharacterState.talk);
      • 会話をする時に、talkに設定
    • moveAndTalkChara.SetState(MoveAndTalkChara.CharacterState.normal);
      • 移動する時に、normalに設定
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

public class MessageCharactor : FieldObjectBase {

    // セリフ : Unityのインスペクタ(UI上)で会話文を定義する 
  // (次項 : インスペクタでscriptを追加して、設定をする で説明)
    [SerializeField]
    private List<string> messages;
    MoveAndTalkChara moveAndTalkChara;

    void Start(){
        moveAndTalkChara = GameObject.Find("char_crol_0").GetComponent<MoveAndTalkChara>();
    }

    // 親クラスから呼ばれるコールバックメソッド (接触 & ボタン押したときに実行)
    protected override IEnumerator OnAction() {
        for (int i = 0; i < messages.Count; ++i) {
            moveAndTalkChara.SetState(MoveAndTalkChara.CharacterState.talk);

            // 1フレーム分 処理を待機(下記説明1)
            yield return null;

            // 会話をwindowのtextフィールドに表示
            showMessage(messages[i]);

            // キー入力を待機 (下記説明1)
            // yield return new WaitUntil(() => Input.anyKeyDown);
            yield return new WaitUntil(() => Input.GetKeyDown(KeyCode.Space));
        }

        moveAndTalkChara.SetState(MoveAndTalkChara.CharacterState.normal);

        yield break;
    }
}

3.フィールドオブジェクトの基本処理のスクリプトFieldObjectBase.csの変更

  • Fixedupdate()Update()に変更しただけになります。
  • 変更点は少ないですが、全体のコードは以下になります。
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

/**
 * フィールドオブジェクトの基本処理
 */
public abstract class FieldObjectBase : MonoBehaviour
{

    // Unityのインスペクタ(UI上)で、前項でつくったオブジェクトをバインドする。
  // (次項 : インスペクタでscriptを追加して、設定をする で説明)
    public Canvas window;
    public Text target;

    // 接触判定
    private bool isContacted = false;
    private IEnumerator coroutine;


    // colliderをもつオブジェクトの領域に入ったとき(下記で説明1)
    private void OnTriggerEnter2D(Collider2D collider) {
        isContacted = collider.gameObject.tag.Equals("Player");
    }

    // colliderをもつオブジェクトの領域外にでたとき(下記で説明1)
    private void OnTriggerExit2D(Collider2D collider) {
        isContacted = !collider.gameObject.tag.Equals("Player");
    }

    private void Update() {
        if (isContacted && coroutine == null && Input.GetButton("Submit") && Input.anyKeyDown) {
            coroutine = CreateCoroutine();
            // コルーチンの起動(下記説明2)
            StartCoroutine(coroutine);
        }
    }

    /**
     * リアクション用コルーチン(下記で説明2)
     */
    private IEnumerator CreateCoroutine() {
        // window起動
        window.gameObject.SetActive(true);

        // 抽象メソッド呼び出し 詳細は子クラスで実装
        yield return OnAction();

        // window終了
        this.target.text = "";
        this.window.gameObject.SetActive(false);

        StopCoroutine(coroutine);
        coroutine = null;
    }

    protected abstract IEnumerator OnAction();

    /**
     * メッセージを表示する
     */
    protected void showMessage(string message) {
        this.target.text = message;
    }
}

4.キー操作にあわせアニメーションに状態をわたすスクリプトAnimationStateController.csの変更

  • UpdateメソッドをMoveAnimationに変更しましょう。
  • 移動しない、会話の時はNoMoveAnimationを呼び出します。
    public void MoveAnimation() {
        if (Input.anyKeyDown) {
            Vector2? action = this.actionKeyDown();
            if (action.HasValue) {
                // キー入力があればAnimatorにstateをセットする
                setStateToAnimator(vector: action.Value);
                return;
            }
        }
        // 入力からVector2インスタンスを作成
        Vector2 vector = new Vector2(
            (int)Input.GetAxis("Horizontal"),
            (int)Input.GetAxis("Vertical"));

        // キー入力が続いている場合は、入力から作成したVector2を渡す
        // キー入力がなければ null
        setStateToAnimator(vector: vector != Vector2.zero? vector : (Vector2?)null);

    }

    public void NoMoveAnimation(){
        this.animator.speed = 0.0f; 
    }
  • 2つのメソッドを追加しました。あまり変更点はないです。
  • 全体のコードは以下になります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/**
 * キャラの向き状態を変更するController
 */
public class AnimationStateController : MonoBehaviour {
    Animator animator;

    void Start() {
        // Animatorを取得する
        this.animator = GetComponent<Animator>();
    }

    /**
     * Update は MonoBehaviour が有効の場合に、毎フレーム呼び出されます
     * https://docs.unity3d.com/ja/current/ScriptReference/MonoBehaviour.Update.html
     */
    // void Update() {
    public void MoveAnimation() {
        if (Input.anyKeyDown) {
            Vector2? action = this.actionKeyDown();
            if (action.HasValue) {
                // キー入力があればAnimatorにstateをセットする
                setStateToAnimator(vector: action.Value);
                return;
            }
        }
        // 入力からVector2インスタンスを作成
        Vector2 vector = new Vector2(
            (int)Input.GetAxis("Horizontal"),
            (int)Input.GetAxis("Vertical"));

        // キー入力が続いている場合は、入力から作成したVector2を渡す
        // キー入力がなければ null
        setStateToAnimator(vector: vector != Vector2.zero? vector : (Vector2?)null);

    }

    public void NoMoveAnimation(){
        this.animator.speed = 0.0f; 
    }

    /**
     * Animatorに状態をセットする
     *    
     */
    private void setStateToAnimator(Vector2? vector) {
        if (!vector.HasValue) {
            this.animator.speed = 0.0f;
            return;
        }

        Debug.Log(vector.Value);
        this.animator.speed = 1.0f;
        this.animator.SetFloat("x", vector.Value.x);
        this.animator.SetFloat("y", vector.Value.y);

    }

    /**
     * 特定のキーの入力があればキーにあわせたVector2インスタンスを返す
     * なければnullを返す   
     */
    private Vector2? actionKeyDown() {
        if (Input.GetKeyDown(KeyCode.UpArrow)) return Vector2.up;
        if (Input.GetKeyDown(KeyCode.LeftArrow)) return Vector2.left;
        if (Input.GetKeyDown(KeyCode.DownArrow)) return Vector2.down;
        if (Input.GetKeyDown(KeyCode.RightArrow)) return Vector2.right;
        return null;
    }
}

完成

GameProject_1_2022-02-13_21-52-46.gif

次に作成するもの(仮)

  • アイテムの持ち上げ関係

参考にしたサイト

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?