AnimationのBone&IKを勉強しました。
モーションも作れるようになってきたので、
いよいよ実際のアクションを作っていこうと思います。
アクションとしては、走る・ジャンプ・スライディング・登るを想定していて、
状況に合わせて、Animationを切り替えていければと考えています。
さて、アクションを切り替えるには?って事なんですが…
当然、床の上なら走るモーションです。
壁が来たら登るモーションに切り替えたいのですが、
どうすればいいかとなります。
ColliderのisTriggerで接触判定を出せば、壁と判断はできそうですが…
そうなんです、isTriggerを設定するとオブジェクトをすり抜けて行くんですよね。
(~ヘ~;)ウーン
なので、isTriggerを設定しなくても壁を認識させる必要があります。
そこで便利な物が用意されています。
レイキャスターです。
Rayとは、日本語なら光線の意味になるんですが、
Unityでは、見えない線と考えてもらうと分かりやすいかと思います。
このRayは、センサーの役割をします。
種類もいろいろあるのですが、
・Raycast 指定座標から指定方向へ一直線の線を飛ばします。
・Linecast 指定座標から指定座標まで線を張ります。
・Boxcast 箱型のRayを指定座標・指定方向・指定距離にセットします。
・Spherecast 球型のRayを指定座標・指定方向・指定距離にセットします。
Rayは、接触したCollider持ちのオブジェクト情報を取得するように出来ているらしいので、
これを使って、壁や床を判断するようにしていきます。
3Dと2Dでは、少し使い方が変わるそうですが、
基本的には、同じ使い方ができるようです。
あと2Dと3Dでは、互換性がないそうで、2Dのオブジェクトに対して
3DのRayは反応しない。逆もまた反応しないそうです。
ざっくりと説明しましたが、Rayについては情報が豊富なんで、
Google先生で検索してもらうと細かい部分は理解できるかと思います。
さて、早速Rayを設定してみようと思います。
使うタイプは、Linecastです。
まずプロジェクトを立ち上げて、オブジェクトを用意します。
2Dスプライトの円を追加します。
このスプライトにRigidbody2DとCircleCollider2Dをアタッチします。
これにRayを設定していきます。
まず、Rayなんですが透明なんでシーンViewでも見る事ができません。
可視化が不可能なんで、位置の確認が出来ないんですよ~(T-T) グスッ
なので、指定座標に線を引くコマンドを設定して位置決めをします。
RayTestスクリプトを用意して、
RayTest
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RayTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Debug.DrawLine(始点座標, 終点座標, 表示色);
}
}
Debug.Drawコマンドは、Rayを可視化すると説明されている事がありますが、
あくまで、シーンView上の指定座標に線を引くコマンドなんで、
Rayの座標とデバッグの座標が違えば、意味がなくなります。
なのでケロは、先に線を引いて位置だしをしてから、同じ座標にRayを張るようにしています。
さてRayを張るのに座標が必要と言う事で、
用意した球にRayを張るわけなんですが、球自体動くので、どう設定するか考え処になります。
そこで、ある本に書いてあったLinecastの張り方を使わせてもらおうと思います。
RayTest
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RayTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//Linecastの始点を求める
Vector2 underStart = transform.position - (transform.right * 0.5f) - (transform.up * 0.51f);
//Linecastの終点を求める
Vector2 underEnd = transform.position + (transform.right * 0.5f) - (transform.up * 0.51f);
//Linecastの座標デバッグ
Debug.DrawLine(underStart, underEnd, Color.blue);
}
}
このスクリプトを球にアタッチする前提で説明していきます。
Rayの座標は、球の座標から割り出さないといけないのですが、
参考にした本には、ベクトル計算を使うといいと書いてありました。
ベクトルは向きなんですが、transform.rightで右向き1ベクトルとなります。
この数値にオブジェクトの中心点から外周までの距離を掛けると
ベクトルが求められるようなので計算します。
オブジェクトの外周までの距離を調べるには、Colliderのサイズを見ると
分かり易いかと思います。
半径が0.5となっています。
なので、transform.right * 0.5fで計算すると球の外周までのベクトルが求められます。
このベクトルを球の座標から引いてやると、左側の座標が計算できます。
Linecastは、球の下に張りたいので、Y軸の座標も設定する必要があります。
なので、transform.up * 0.51fを引く事で下側の座標も設定しています。
これでRayの始点座標が計算できたので、終点座標の計算になります。
終点座標は、球の右側になるのでtransform.right * 0.5fを足してやります。
Y軸の計算は同じになります。
表示座標が計算できたので、Debug.DrawLineに座標を設定してPLAYします。
球の下に青い線が表示されました。
この位置にLinecastするわけですが、床と接触させる必要があるので、
Colliderより少し下に位置取りさせています。
これで床とのセンサー位置が決まったので、続いて壁用センサーの位置出しをします。
球は右方向に移動させるので、球の右側に用意します。
RayTest
void Update()
{
//床用のLinecast座標
Vector2 underStart = transform.position - (transform.right * 0.5f) - (transform.up * 0.51f);
Vector2 underEnd = transform.position + (transform.right * 0.5f) - (transform.up * 0.51f);
//壁用のLinecast座標
Vector2 rightStart = transform.position + (transform.right * 0.51f) + (transform.up * 0.5f);
Vector2 rightEnd = transform.position + (transform.right * 0.51f) - (transform.up * 0.5f);
//Linecastの座標デバッグ
Debug.DrawLine(underStart, underEnd, Color.blue);
Debug.DrawLine(rightStart, rightEnd, Color.green);
}
実行すると
こんな感じになります。
位置が決まったので、Linecastの設定をします。
Linecastは、特定のレイヤーに属するColliderと接触した時に
反応するそうなので、レイヤーも設定する必要があります。
まず、接触判断する為に床と壁を用意します。
2Dオブジェクトのスプライト→正方形で二つのオブジェクトを作ります。
それぞれにRigidbody2DとBoxCollider2Dをアタッチして、
ボディタイプを静的にして固定します。
続いて、レイヤーの編集を行います。
レイヤーを追加で、FloorとWallを作ります。
Floorは、元からあったような…
あれば、それを使ってもらってOKでっす。
続いて、追加したオブジェクトのレイヤーをそれぞれに対応したレイヤーに変更します。
床ならFloor、壁ならWallを選択。
準備完了でっす。スクリプトを作成します。
RayTest
public class RayTest : MonoBehaviour
{
public LayerMask floorLayer; //床レイヤー
public LayerMask wallLayer; //壁レイヤー
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//床用のLinecast座標
Vector2 underStart = transform.position - (transform.right * 0.5f) - (transform.up * 0.51f);
Vector2 underEnd = transform.position + (transform.right * 0.5f) - (transform.up * 0.51f);
//壁用のLinecast座標
Vector2 rightStart = transform.position + (transform.right * 0.51f) + (transform.up * 0.5f);
Vector2 rightEnd = transform.position + (transform.right * 0.51f) - (transform.up * 0.5f);
//Linecastを張る
RaycastHit2D underHit = Physics2D.Linecast(underStart, underEnd, floorLayer);
RaycastHit2D rightHit = Physics2D.Linecast(rightStart, rightEnd, wallLayer);
//床に接触してるか判断する
if (underHit) Debug.Log("着地");
//Linecastの座標デバッグ
Debug.DrawLine(underStart, underEnd, Color.blue);
Debug.DrawLine(rightStart, rightEnd, Color.green);
}
}
Physics2D.Linecast(始点座標, 終点座標, 対象レイヤーマスク)
このコマンドで張る事ができます。
指定したレイヤーマスクに接触するとtrueが返ってきます。
なので、レイヤーマスクを設定しておく必要があります。
publicな変数でレイヤーマスクを用意したので、RayTestコンポーネントの
レイヤーを設定しておきます。
これで準備が整いました。
球を空中に移動させてPLAYしてみます。
床に着地すれば、デバッグが表示されるはずです。
無事に表示できました。ヽ(´▽`)/~♪
上手く反応してくれたので、少し動きを追加してみます。
ついでに壁の接触判定も見たいので、スクリプトを少し変更します。
RayTest
public class RayTest : MonoBehaviour
{
public LayerMask floorLayer; //床レイヤー
public LayerMask wallLayer; //壁レイヤー
private Rigidbody2D ballRB; //球のRigidbody
private float moveSpeed = 0.0f; //球の移動速度
// Start is called before the first frame update
void Start()
{
ballRB = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
//床用のLinecast座標
Vector2 underStart = transform.position - (transform.right * 0.5f) - (transform.up * 0.51f);
Vector2 underEnd = transform.position + (transform.right * 0.5f) - (transform.up * 0.51f);
//壁用のLinecast座標
Vector2 rightStart = transform.position + (transform.right * 0.51f) + (transform.up * 0.5f);
Vector2 rightEnd = transform.position + (transform.right * 0.51f) - (transform.up * 0.5f);
//Linecastを張る
RaycastHit2D underHit = Physics2D.Linecast(underStart, underEnd, floorLayer);
RaycastHit2D rightHit = Physics2D.Linecast(rightStart, rightEnd, wallLayer);
//床に接触してるか判断する
if (underHit) moveSpeed = 2f;
//壁に接触したか判断する
if (rightHit) Debug.Log("動けない");
//Linecastの座標デバッグ
Debug.DrawLine(underStart, underEnd, Color.blue);
Debug.DrawLine(rightStart, rightEnd, Color.green);
}
void FixedUpdate()
{
ballRB.velocity = new Vector2(moveSpeed, ballRB.velocity.y);
}
}
床に着地したら右方向へ移動していくようにしました。
このままPLAYすると球が回転するので、
z軸を固定します。
準備ができたのでPLAYしてみます。
再生できない場合、ダウンロードは🎥こちら
無事に両方のRayが反応してくれてます。
これで床や壁の判断ができるので、移動処理が作って行けそうです。
最後にLinecastについて少し書いておきます。
Physics2D.Linecast(始点座標, 終点座標, 対象レイヤーマスク)は、
bool型を返すようになっています。
なので、スクリプトでは、RaycastHit2D underHitの変数を設定していましたが、
bool型でも受ける事ができます。
返り値がbool型と言う事で、
if(Physics2D.Linecast(始点座標, 終点座標, 対象レイヤーマスク))といきなり
if文に突っ込む事もできます。
この辺りは、スクリプトを組むときの手間で変えてもいいかと思います。
ジャンプの設定時にキーを押したらジャンプする処理だと、
空中でもジャンプができてしまいます。
キーを押し続ければ、ずっとジャンプし続けます。
なので、床に着地してる時だけジャンプできるようにするなら
必須になるかと思います。
また、Raycastの情報は多いのですが、Linecastは意外と見つからないので、
参考になれば幸いかと思います。
Rayが設定できたので、次回からはアクションとモーションの連動あたりを
調整できればと思います。
それでは、今回はこのへんで ( ^ 0 ^ )/~~~~see you again
この記事へのコメント