Unity5 メモ4
- モンストで敵に当たったときのキャラの跳ね返り処理
図で言うと、Aから進んでOの地点で接触した場合、Cの方向に進むのが正しい。
現状進もうとしているベクトルOA'を回転させてベクトルOCにすればいいのだが、直接∠A'OCを求めることは難しいため、まずは∠A'OPの角度を求めて、ベクトルOA'を時計回りに2度回してベクトルOC'とし、そのベクトルを反転させてベクトルOCにすることを考える。 前提として、∠AOB = ∠BOC、∠A'OP=∠POC'。
まず、2つのベクトルのなす角は以下の公式を使う。
この公式を2つのベクトルOA'とOPに適用すると、∠A'OPのcosθが取得できる。このcosθに逆余弦であるarccos(アークコサイン)をかけると、∠A'OPがラジアンで取得できる。ここまでできればあとは簡単で、取得できたラジアンを使ってOA'を時計回り方向に2回回し、最後に-1をかけてそのベクトルを反転させれば、欲しかったベクトルOCが取得できる。
これを手動で行う場合は以下のようになる。
まず、2つのベクトルOA'とOPがなす角∠A'OPを求めるために、上記リンクで解説されている公式を適用し、(OA'とOPの内積)/(OA'の長さ*OPの長さ)
を求めたいが、簡略化のために両方とも長さを1とし、Oを原点として考える。すると分母は(1*1)=1となって計算が省かれ、A'.x * P.x + A'.y + P.yだけ計算すればよくなる。これがcosθの値なので、ここにアークコサインをかける(arccos(A'.x * P.x + A'.y + P.y))。
これが∠A'OPのラジアン角なので、それを2倍すると∠A'OC'のラジアン角となる。これを使って、ベクトルOA'を回転させ、そのあとにベクトルを反転させれば答えとなる。
これをUnityで行う場合、実はここまで考えなくてもいい。
Unityでは回転系の関数がQuaternion
クラスなどにまとめられているので簡素に実装することができる。
Vector3 attackerForce;
がキャラの移動ベクトル(上の図ではベクトルAOであり、ベクトルOA')として、OnTriggerEnter()
内で以下のようにできる。
// プレイヤーから敵へのベクトル、上の図ではOPに相当 Vector3 vecToEnemy = coll.gameObject.transform.position - this.transform.position; // to make sure attackerForce.z = 0; vecToEnemy.z = 0; // この関数を呼ぶだけで角度が取得できる float deg = Vector2.Angle(attackerForce, vecToEnemy); // しかし、↑で取得した角度は相対的な角度で、常にプラスの角度しか取得できない // ので、2つのベクトルの外積を求め、そのz成分が正だったらマイナスにする Vector3 cross = Vector3.Cross(attackerForce, vecToEnemy); if (cross.z > 0) deg *= -1; // ここでdegが∠A'OPのラジアン角で、それを2倍している // そしてそれをattackerForce にかけ、最後に-1をかけてベクトルを反転させている attackerForce = Quaternion.AngleAxis(deg * 2, Vector3.back) * attackerForce * -1; // Vector3.backというのは、new Vector3(0, 0, -1)と同じで、手前へのベクトルで、 // これを軸に回転させることでXY平面の2Dとしての回転に利用できる
float ang = Vector2.Angle(fromVector2, toVector2); Vector3 cross = Vector3.Cross(fromVector2, toVector2); if (cross.z > 0) ang *= -1;
Unityは左手座標系
UnityはDirectX同様奥ほどZが大きいので、XY平面を数学的に直感的に回転させるときは、
Quaternion.AngleAxis()
の第2引数のZ軸をVector3.back
で指定する(正の角度で反時計回り)。
Vector3.foward
だと回転が時計回りになる。ヒットストップの実装
キャラが敵に当たったとき、一瞬止まり、すぐ復帰するいわゆるヒットストップ処理をする場合、
Time.timeScale
を0にしてInvoke()
で一定時間後にtimeScale
を元に戻す関数を呼ぶ方法が思いつくが、
Invoke()
も内部的にtimeScale
で実装されているため、これだと永久に呼ばれなくなってしまう。
Time.realtimeSinceStartup
を使用して、ヒットしたときに
Time.timeScale = 0; lastHitTime = Time.realtimeSinceStartup; isHitStopped = true; /// とし、Update()関数内で以下のようにすると実現できる。 if(isHitStopped && Time.realtimeSinceStartup > lastHitTime + HIT_STOP_TIME){ Time.timeScale = 1; isHitStopped = false; }
- 拡張メソッド
C#内在の機能で、特定のクラスにメソッドを追加する。
まず、任意の新規スクリプトをpublic static class
として宣言する。
追加したいメソッドをstatic関数として定義し、第1引数はthis 拡張対象のクラス 変数名 の形式で書く。
たとえば、Vector2
クラスにRotate()メソッドを追加したい場合以下のように書くことができる。
public static class Extensions{ public static void Rotate(this Vector2 v, float degrees){ return Quaternion.Euler(0, 0, degrees) * v; } } /// これで、 Vector2 vec = new Vector2(3, 5); vec = vec.Rotate(45f); /// のように使うことができる。 /// このスクリプトは何かのGameObjectにアタッチしなくてもビルドを通すだけで使える。
スマホの縦画面のアスペクト比
多くは9:16なので、GameウインドウでFreeAspectになっている部分をクリック、プラスボタンを押してTypeをAspectRatioにして
9:16になるように変更してOKを押すと、縦画面のアスペクト比で固定される。MonoDevelopのショートカット
多くのVS互換のショートカットが利用できる
C-F(search) C-H(replace) C-W(close tab) C-G(goto line)
F2(rename) F7(build) F9(breakpoint) F10(step over) F11(step in) F12(goto definition)スプライトを非表示にするには
SpriteRendererに対して、
spriteRenderer.enabled = false;
Vector3をQuaternionに変換
Quaternion.Euler(new Vector3(0, 0, angle));
キャラクターを押している間だけキャラクターを振動させる
キャラクター本体を動かすとpositionが変わって弾く方向まで変わってしまうため、
空のオブジェクトを作ってそこにコライダーなどスプライト以外全てのコンポーネントを移し、
スプライトだけをそのオブジェクトの子オブジェクトにし、子オブジェクトのpositionをいじって調整する。
当たり判定・位置情報を親のものを使うことで描画だけをずらすことができる。