問題を自己解決できるようになり始めたのは大きな進歩です。
//tips
//レイヤーマスクとタグの違い
レイヤーとタグの違いは下記のようです。
タグ:
ゲームオブジェクトの種類をスクリプトから識別するためのもの。
ゲームオブジェクトを検索して取得したり、特定のタグのゲームオブジェクトに対してだけ処理を行ったりするとき便利。
オブジェクトをまとめて処理したい時に向いている。
FindGameObjectWithTagによるタグがついたオブジェクトの一括取得など。
レイヤー:
ゲームオブジェクトをグループ分けできるような機能。
特定のレイヤーが設定されたゲームオブジェクトだけをカメラに映したり、特定のレイヤーが設定されたゲームオブジェクト同士のみに対して衝突判定を行なったりすることができる。
・カメラに映らないオブジェクトを作るときはLayerで指定
・RayCastを使用したいときに指定
//ジャンプアクションをスクリプト化する
ジャンプをさせる際に、接地しているかの条件を組み込むと少しコードが複雑になる。
最初に接地判断をするために、地面のブロックをレイヤー化しておく必要があり、
public LayerMask blockLayer;
として、PlayerManagerに追加されることになる。
public class Manager: MonoBehaviour
{
・・・
private float jumpPower=400;
private bool goJump=false;
private bool canJump=false;
}
private bool goJump=false;でジャンプしたかどうか、private bool canJump=false;で接地しているかどうかを判断する。
void Update()
{
canJump=
Physics2D.Linecast(transform.position -(transform.right * 0.3f),transform.position - (transform.up * 0.1f),blockLayer)||
Physics2D.Linecast(transform.position +(transform.right * 0.3f),transform.position - (transform.up * 0.1f),blockLayer)|
}
Linecast()は始点と終点の線分上に特定のレイヤーに属するColliderが存在する場合trueを返す。
Physics2D.Linecast(始点,終点,レイヤーマスク,トリガーも対象にするか)で構成される。
transform.position -(transform.right * 0.3f)の意味は、
現在地transform.positionから右ベクトル0.3分(transform.right * 0.3f)を引くことになる(マイナスベクトルを足すと言い換えてもいい)ので、左に0.3分移動した座標を示します。
同様にtransform.position - (transform.up * 0.1f)の意味は、
現在地transform.positionから上ベクトル0.1分(transform.right * 0.1f)を引くことになる(マイナスベクトルを足すと言い換えてもいい)ので、下に0.1分移動した座標を示します。
これらから、canJumpはプレイヤーの足元を三角形に掘り下げて接地しているかどうかの衝突判定を行っていることがわかる。
if(goJump)
{
rbody.AddForce(Vector2.up * jumpPower);
goJump = false;
}
public void PushJumpButton()
{
if(canJump)
{
goJump = true;
}
}
//ボタン入力で決まった配置に移動するオブジェクトを作成
オブジェクトの移動をボタンの押された回数目に応じて変更する下記のスクリプトを作成したが、switch~caseの中身がランダムに表示されてしまうので、スクリプトでの制御からアニメーターでのtrigger制御に切り替えた。
スクリプト制御失敗コード
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyManager : MonoBehaviour
{
Vector3 MOVEX = new Vector3(1.0f, 0, 0);
Vector3 MOVEY = new Vector3(0, 1.0f, 0);
Vector3 MOVEZ = new Vector3(0, 0, 1.0f);
float step = 2f; // 移動速度
Vector3 target; // 入力受付時、移動後の位置を算出して保存
Vector3 prevPos; // 何らかの理由で移動できなかった場合、元の位置に戻すため移動前の位置を保存
private enum MoveType
{
FORWARD_1 = 0, // 前進1
UP = 1, // 左へ
FORWARD_2 = 2, // 前進2
Z = 3 // 右へ
}
private MoveType moveType = MoveType.FORWARD_1;
// Use this for initialization
void Start()
{
target = transform.position;
}
// Update is called once per frame
void FixedUpdate()
{
// ① 移動中かどうかの判定。移動中でなければ入力を受付
if (transform.position == target)
{
switch (moveType)
{
case MoveType.FORWARD_1:
SetTargetPosition();
moveType++;
break;
case MoveType.UP:
SetTargetPosition1();
moveType++;
break;
case MoveType.FORWARD_2:
SetTargetPosition2();
moveType++;
break;
case MoveType.Z:
SetTargetPosition3();
moveType=0;
break;
}
}
Move();
}
// ② 入力に応じて移動後の位置を算出
void SetTargetPosition()
{
prevPos = target;
if (Input.anyKeyDown)
{
target = transform.position + MOVEX;
return;
}
}
void SetTargetPosition1()
{
prevPos = target;
if (Input.anyKeyDown)
{
target = transform.position + MOVEY;
return;
}
}
void SetTargetPosition2()
{
prevPos = target;
if (Input.anyKeyDown)
{
target = transform.position + MOVEX;
return;
}
}
void SetTargetPosition3()
{
prevPos = target;
if (Input.anyKeyDown)
{
target = transform.position + MOVEZ;
return;
}
}
// ③ 目的地へ移動する
void Move()
{
transform.position = Vector3.MoveTowards(transform.position, target, step * Time.deltaTime);
}
}
アニメーターでの制御時に使用した成功コード
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMove : MonoBehaviour
{
public GameObject Enemy;
// Start is called before the first frame update
void Start()
{
AnimatorStateInfo stateInfo = Enemy.GetComponent<Animator>().GetCurrentAnimatorStateInfo(0);
}
// Update is called once per frame
void Update()
{
if (Input.anyKeyDown)
{
Enemy.GetComponent<Animator>().SetTrigger("first");
}
}
}
赤キューブを入力のたびに規定の位置に遷移させるループを作成している。
スクリプト失敗の要因として、
・enum内のmoveType数値がmoveType++ときちんと連動できていない可能性
・void FixedUpdate()の時間設定がおかしく、クリック数カウントがうまくいっていない可能性
の問題があり、ランダムにcaseが選ばれてしまっているのではないかと考えている。
こちらは別途、検証を行う。
問題をシンプルにして、キーを押したらカウントごとに、実行結果を変更する内容を書いて再確認したので、再度下記に準拠して失敗したスクリプトを見直していく。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Call : MonoBehaviour
{
// Start is called before the first frame update
int count = 0;
// Update is called once per frame
void Update()
{
if (Input.anyKeyDown)
{
count++;
if (count == 1)
{
Debug.Log("おはよう");
}
if (count == 2)
{
Debug.Log("こんにちは");
}
if (count == 3)
{
Debug.Log("こんばんは");
count = 0;
}
}
}
}
上記をもとに簡易化し、下記のコードで解決しました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyManager : MonoBehaviour
{
Vector3 MOVEX = new Vector3(1.0f, 0, 0);
Vector3 MOVEY = new Vector3(0, 1.0f, 0);
Vector3 MOVEZ = new Vector3(0, 0, 1.0f);
float step = 3.0f; // 移動速度
Vector3 target; // 入力受付時、移動後の位置を算出して保存
private int count = 0;
// Use this for initialization
void Start()
{
target = transform.position;
}
// Update is called once per frame
void Update()
{
if (Input.anyKeyDown)
{
count++;
if (count == 1)
{
target = transform.position + MOVEX;
}
if (count == 2)
{
target = transform.position + MOVEY;
}
if (count == 3)
{
target = transform.position + MOVEZ;
}
}
Move();
}
// ③ 目的地へ移動する
void Move()
{
this.transform.position = Vector3.MoveTowards(transform.position, target, step * Time.deltaTime);
}
}
void FixedUpdate()が問題点で入力のラグが起きており、Update()にあう形のスクリプトに変更できたのがポイントだった。