カラヤミビヨリ

Unityの覚え書きとか

【Unity】目標を自然な回転で追跡する

自分のメモ書き代わりにここにオブジェクトの正面を徐々に目標へ向けさせるコードを書いておく。

方向転換が左右のみの場合は以下のコードを使用する。

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

public class ObjRotation : MonoBehaviour {

void TargetLock(){

///自分の正面ベクトルをローカルからワールドへ変換
///自分から見た敵の方向ベクトルを算出
Vector3 _ForwardVec = transform.TransformDirection(Vector3.up);
Vector3 _TargetVec = (Target - transform.position);

/// 自身と敵の角度差・回転速度
float _Angle = Vector3.Angle(_TargetVec.normalized, _ForwardVec.normalized);
float _addAngle = (RotSpeed * Time.deltaTime);

/// 外積

Vector3 InOrOut = Vector3.Cross(_ForwardVec, _TargetVec);

/// 内側か外側か(右か左か)
int _IOO = InOrOut.z > 0 ? 1 : -1;

///

if (_Angle >= _Adjust)
    {
    ///Vector3.upは回転軸で必要に応じて変える。
    transform.Rotate(Vector3.up * addAngle * IOO, Space.World);

    }
}
}

3次元上で用いる場合は以下のコードで行う。

void Chase(){

Vector3 Fowardvec = transform.TransformDirection(Vector3.forward);
Vector3 TargetVec = (target.transform.position - this.transform.position);

float   Angle = Vector3.Angle(TargetVec.normalized, Fowardvec.normalized);
float   addAngle = (rotSpeed * Time.deltaTime);

Vector3 toRotationTarget = Quaternion.LookRotation(TargetVec);

float   t = (addAngle / Angle);

        transform.rotation = Quaternion.Slerp(this.transform.rotation, 
                                              toRotationTarget, t);

        transform.Translate(transform.TransformDirection(Vector3.forward)
                            * Speed);


        //RD.AddForce(transform.TransformDirection(Vector3.forward) * Speed, 
                      ForceMode.Force);
}

2次元と3次元でコードが違うのは、外積が必要か否か。
2次元で回す場合、上記の方法は自分と敵の角度差を求めその分だけ回転するようにしているが、Vecroe3.Angleはあくまで角度差だけしか出せず、敵が右か左かの区別ができない。
そのため外積の内外判定を使うことで左右どちら側かを判定する。

判定後、右がプラスの場合、左なら回転する数字にマイナスをかけることで回転方向を反転させる。

/// 外積

Vector3 InOrOut = Vector3.Cross(_ForwardVec, _TargetVec);

/// 内側か外側か(右か左か)
int _IOO = InOrOut.z > 0 ? 1 : -1;

///

3次元では、回転をQuaternion.Sleapを用いればほぼ解決する。
これは2点の座標を球状補間するので、自分の座標と目標の座標を変数に入れるだけで可能になる。

ちなみに、目標への角度が極端に0に近くなると、オブジェクトががくがくと震える現象が起こることがあるので、そういう時は以下のように角度差が一定以上の場合に回転させるという風にすれば回避できる。

/// Angle が _Adjustを下回ると回転させない。

if (Angle >= _Adjust)
    {
    ///Vector3.upは回転軸で必要に応じて変える。
    transform.Rotate(Vector3.up * addAngle * IOO * Abs, Space.World);

    }

ブログを始める

ゲームを作るのだと、Unityを触り続けて約3年。

いまだに「こんな方法があったのか」と気づかされる未熟者です。

日々いろんな手法を探っているうちに頻繁に使うコードや便利そうなものをメモ代わりにでも書き綴ろうかなと始めました。

たまに(もしくは頻繁に)己の主観なんかを垂れ流すかもしれません。

 

よろしくお願いします。