前置き
-
前回の記事で、他のキャラクターに話しかけたときにメッセージを表示をするように実装しました。
-
今回作成するものは大きく分けて以下の2つになります。
- 主人公のキャラクターが会話している時は移動処理をしない。
- 会話が終了したら移動処理に切り替えるようにする。
-
前回までの実装した動きは以下になります。
- 会話中に
→
キーを押しているため、ずっと右に進んでいますね…。 - 会話中は移動しないように修正していきます。
- 会話中に
今回作成するもの
- 1.キャラクターの移動・会話処理の切り分けスクリプト
MoveAndTalkChara
の追加 - 2.メッセージ表示のスクリプト
MessageCharactor
の変更 - 3.フィールドオブジェクトの基本処理のスクリプト
FieldObjectBase.cs
の変更 - 4.キー操作にあわせアニメーションに状態をわたすスクリプト
AnimationStateController.cs
の変更
1.キャラクターの移動・会話処理の切り分けスクリプトMoveAndTalkChara.cs
の追加
- 新規に
MoveAndTalkChara.cs
を作成しました。このスクリプトは主人公のキャラクターの移動と会話処理を切り分けるものとなります。- 参考にしたサイト:Unityでキャラクターの移動と会話処理を切り分ける
- 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()
に変更しただけになります。- 変更理由は、
Fixedupdate()
だとキーを押しているのに入力されない、反応しない、反応する時としない時があるためです。 - 【Unity】 FixedUpdate と Input.GetKeyDown
- 変更理由は、
- 変更点は少ないですが、全体のコードは以下になります。
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;
}
}
完成
次に作成するもの(仮)
- アイテムの持ち上げ関係