【Unity】テレポーターを作ってみる

stayホームで家から出てないのに、Unityの勉強が進んでないケロです。
何事もマイペースが信条でっすw
(;^o^) \(ToT )あんたほんとにそれでいいの

外は天気がいいのに、どこにも行けない。
自粛要請はいつまで続くのやらヽ(´~`;)ウーン

コロナの無い所にテレポートしたいですね~


そんな事で、無理やりお題に結びつけてみました。
今回はテレポーターを作ってみたので記事にしてみます。


まず、オブジェクトをテレポートさせるには、
transformに移動先を指定すれば、瞬間移動してくれます。

実際に簡単な物を作ってみます。
teleporter1.jpg
赤い円がテレポーターです。

ボール青が上昇して行き、テレポーターに当たると
Canvasの最下段にテレポートして、上昇を続けます。
黄色のストッパーに当たると停止するみたいな感じです。
Test_Ball

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

public class Test_Ball : MonoBehaviour
{
public float speed; //ボールのスピード

private Transform balltran; //ボールのtransform
private bool moving=true; //移動フラグ


void Start()
{
//ボールのtransform取得
balltran = GetComponent<Transform>();
}

void Update()
{
//フラグ判定falseなら停止
if (moving)
{
MovingBall();
}
}

//ボールの移動処理
void MovingBall()
{
float y = balltran.localPosition.y;
y += Time.deltaTime * speed;

Vector3 pos = new Vector3(balltran.localPosition.x, y, 0f);
balltran.localPosition = pos;
}

//接触判定
private void OnTriggerEnter2D(Collider2D collision)
{
//黄色なら停止
if (collision.gameObject.tag == "TelY")
{
moving = false;
}
//赤ならテレポート
if (collision.gameObject.tag == "TelR")
{
balltran.localPosition = new Vector2(0, -590);
}
}
}

このスクリプトをボールにアタッチします。
ボールのスピードは、public変数にしてあるのでコンポーネント上で設定します。
今回は300くらいにしておきます。

続いて、各オブジェクトに必要なコンポーネントをアタッチして行きます。
teleporter2.jpg
ボールには、Rigidbody2DとCircleCollider2Dをアタッチします。

Rigidbodyをtransformで動かす場合、必ずモードをキネマティックにして、
完全なキネマティックコンタクトにチェックを入れます。

これは、物理演算の計算が重複すると処理が重くなる為で、
物理演算が必要な処理の場合、Rigidbody.Positionで移動させる必要があります。

今回は、物理演算が必要ないのでキネマティックにしています。

次はテレポーターです。
teleporter3.jpg
接触判定を使うので、CircleCollider2Dをアタッチします。

接触時の判定用にタグを設定します。
Colliderは接触センサーになるので、トリガーにチェックを入れます。

最後はストッパーです。
teleporter4.jpg
接触判定のタグを設定して、トリガーにチェックします。

これで、テレポーターの完成です。

動画がショボイですが、一応動いてるのが分かると思います。

簡単な物は作れたのですが、本来テレポーターって対になっていて、
どちらからでもアクセスできるようになっていると思います。

対になるテレポーターを設置すればいいだけと言いたいのですが、
どちらもトリガーになるので、一度乗せると転送が繰り返されて、
無限ループが起こってしまいます。

なので、転送先で再転送が起こらない処理を考えてみます。
また、テレポーターが二つになるので、お互いの座標を
読み取れるように改良してみます。

まず、テレポーターの座標取得から新規Scriptを立ち上げて
スクリプト名をTest_Telとしておきます。
Test_Tel

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

public class Test_Tel : MonoBehaviour
{
public GameObject target; //テレポーターの相方

public Vector3 targettvector; //相方の座標

void Awake()
{
targettvector = target.GetComponent<Transform>().localPosition;
}
}

このスクリプトをテレポーターにアタッチします。
注意点なのですが、このtransformの取得はstartで行うとエラーが出るので、
Awakeで行っています。

良くは分からないのですが、コンポーネントの取得だけならStartでも問題ないようですが、
positionまで取得しているので、取得が間に合わないのかもしれません。

続いて、テレポーターの複製を作ります。
teleporter5.jpg
テレポーターにTest_Telスクリプトをアタッチして、
target変数にお互いのテレポーターをアタッチします。

これで、お互いの座標が取得できたので、
テレポートの処理を改良してみます。
Test_Ball

private bool transfer; //転送中のフラグ

private void OnTriggerEnter2D(Collider2D collision)
{
//赤ならテレポート
if (collision.gameObject.tag == "TelR")
{
//転送判定
if (transfer)
{
transfer = false;
}
else
{
//接触時に転送座標を取得する
balltran.localPosition = collision.GetComponent<Test_Tel>().targetvector;
transfer = true;
}
}
}

テレポーターに接触したら、ターゲット座標を取得して相方に転送します。
転送中が判断できるようにtransferフラグをtrueにします。

転送先でフラグcheckを行って、trueなら転送されてきたと判断して、
何もしない処理にしています。

これで無事、転送ループから出れるようになります。

最後に動きを修正して、できたのがこちら。

ボールを上下に動くようにして様子をみましたが、
お互いの座標に無事、転送が行えています。

難点は、接触したテレポーターの上に移動する前に転送されてしまう所でしょうか。
この辺りは、コルーチンなどを使う必要があるかと思います。

テレポーター上で、パーティクルなどの処理を行ってから移動させると
綺麗な転送ができるかと思います。

何か良い処理が思いついたら、また記事にしてみたいと思います。

それでは、今回はこのへんで
( ^ 0 ^ )/~~~~see you again

この記事へのコメント