シューティングゲームなどを作っていると、そのオブジェクトがどちらの方向に進んでいるか取得したいときがあります。
敵キャラの動く方向に合わせてアニメーションを変えないといけないときなどです。
例えば二次関数で敵キャラを動かしているとき。
上から下に降りてくるときは正面のアニメーション。
下限の横移動のときは横向きのアニメーション。
そして下から上へ帰るときは後ろ向きのアニメーション。
行動ごとに場合分けをしていたらキリもないですし、自然に実装したい……そんなことをゴーヤチャンプルーを作りながら考えておりましたw
ここではGameObjectの進んでいる方向を角度で返す方法をご紹介します。
もっと良い方法もあるかもしれませんw
GameObjectが進んでいる方向の角度を取得する方法【Unity2D】
考え方は以下です。
- 前回のGameObjectの位置を保存しておく
- 今回のGameObjectの位置と前回の位置の差分を出す。
- x,yの差分をベクトルにする。(高校のときに習った単位円みたいになりますね!)
- ベクトルをアークタンジェントを使って角度にする
1.前回のGameObjectの位置を保存しておく
これは、Update()の最後にでも保存変数を作って入れておきましょうw
2.今回のGameObjectの位置と前回の位置の差分を出す
void Update () {
float x = this.transform.position.x - prevPos.x;
float y = this.transform.position.y - prevPos.y;
prevPos = this.transform.position;
}
prevPosが前回の位置です。
3.x,yの差分をベクトルにする。
void Update () {
float x = this.transform.position.x - prevPos.x;
float y = this.transform.position.y - prevPos.y;
Vector2 vec = new Vector2 (x, y).normalized;
prevPos = this.transform.position;
}
xとyをベクトルにします。
とりあえず正規化しています。(単位ベクトル)
いらないかも……。
こういう図がイメージできれば良さそうです。
4.ベクトルをアークタンジェントを使って角度にする
void Update () {
float x = this.transform.position.x - prevPos.x;
float y = this.transform.position.y - prevPos.y;
Vector2 vec = new Vector2 (x, y).normalized;
float rot = Mathf.Atan2 (vec.y, vec.x) * 180 / Mathf.PI;
if(rot > 180) rot-= 360;
if(rot <-180) rot+= 360;
Debug.Log("Angle = " + rot);
prevPos = this.transform.position;
}
数学の時間です!
よく聞くsin, cos, tanは角度から三角関数の値を求める方法です。
sin30°やcos90°なんてテストでよく出ましたね。
アークがつくアークサイン、アークコサイン、アークタンジェントは逆の意味になります。
つまり三角関数の値から角度を求める方法です。
ずばり今回知りたい値ですよね。
これでrotは上側への移動は 0 ~ 180度、下側の移動は0~ -180度で取得できます。
おまけ
アニメーションはこんな感じでわけました。
角度を45で割った商で0のときは0 ~ 45度、1のときは45度〜90度……みたいに範囲を指定しなくても分ける方法がありますが、可読性が悪くなりそうでしたので直球で書いていますw
増分がxもyも0のときは何もしないようにしています。
理由は、まっすぐ動き続けているように見えてもフレーム単位で動いていないときがあるからです。
これを入れておかないとアニメーションが右向きと正面が混じって荒ぶったりします!
void setAnimeTrigger(float x, float y){
if( (x == 0) && (y == 0) ){
return;
}
//単位ベクトルからの角度計算
Vector2 vec = new Vector2 (x, y).normalized;
float rot = new Common ().vectorToAngle (vec);
if( (rot >= -45 ) && (rot < 45) ){
this.GetComponent<Animator>().SetTrigger("rightTrigger");
}
else if( (rot >= 45 ) && (rot < 135) ){
this.GetComponent<Animator>().SetTrigger("backTrigger");
}
else if( (rot >= 135 ) && (rot <= 180) ){
this.GetComponent<Animator>().SetTrigger("leftTrigger");
}
else if( (rot <= -135 ) && (rot >= -180) ){
this.GetComponent<Animator>().SetTrigger("leftTrigger");
}
else if( (rot > -135 ) && (rot < -45) ){
this.GetComponent<Animator>().SetTrigger("frontTrigger");
}
}