斜方投射
弾とかをこういう軌道で発射したい
https://gyazo.com/98886a5c9d009c595e16bc5ccba3c059
おおまかな考え方
弾の座標計算は、横軸は等速直線運動、縦軸は鉛直投げ上げ(等加速度運動)で行う
着弾地点を指示したい場合は、鉛直投げ上げの最大高度を指定して着弾までの時間を求める
等速直線運動
x = v * t 的なやつ
速度v[m/s]と時間t[s]を掛け算して位置x[m]を出す
ゲームに使う場合、1フレーム毎の移動量が欲しいので、時間は前フレームから今フレームまでの時間(Time.deltaTime)になる。
速度v[m/s]と時間の変化量dt[s]を掛け算して位置の変化量dx[m]を出して、前回位置x[m]に足すと、このフレームにおける位置x'[m]が計算できる。
こういう、極小の差分を積み重ねて行くことを積分と呼ぶそうな?
生まれてからの経過秒で計算すると、自機狙いとかで速度が変わった時にそれまでの変化量を考慮しないので、ワープする(初期値設定してそれ以降変化しないなら良いんだと思う)
code:cs
void FixedUpdate(){
float deltaX_m = direction.x * this.InitialVelocity_mps * Time.deltaTime;
}
等加速度運動
x = x0 + v0 * t + (1/2) * a * t^2的なやつ (x0:初期位置 v0:初速度)
(1/2) * a * t^2は、位置の変化を等速運動によるものとみなして計算してるので、謎の1/2が存在する
(1/2) * a * tで平均の速度av[m/s]を求めて、それに時間t[s]を掛けて位置の変化量dx[m]としてる。
↑がなんで平均の速度になるのかはよく分からん。x-t平面にプロットしてどうのこうのする理屈のようだけど・・・
考え方的には、位置の変化量x = v * dtと同じように速度の変化量を毎フレーム出して、それを積み上げたもの(積分したもの)を現在の速度と扱う。
v = a * dtでこのフレームにおける速度の変化量dv[m/s]を求める。
前回速度v[m/s]にdvを足して、このフレームにおける速度v'[m/s]を求める。
あとは等速直線運動と同じように、x' = x + v' * dtで今回位置を出す
すげぇわかり辛いんだけど、v'は速度であって、位置の変化量dx[m]ではない
加減計算は同じ単位同士でしか成立しない。ことに注意する
code:cs
void FixedUpdate(){
float deltaGravity_mps = Physics2D.gravity.y * Time.fixedDeltaTime; // Physics2D.gravity.yはm/s^2 this.gravity_mps += deltaGravity_mps;
float deltaY_m =
direction.y * this.InitialVelocity_mps * Time.deltaTime
+ this.gravity_mps * Time.fixedDeltaTime;
}
鉛直投げ上げ
等加速度運動の特殊系? 加速度aが重力加速度gになる話。
公式とかでx = x0 + v0t - (1/2) * g * t^2とかになってるけど、UnityのPhysics.gravityだと負の値が出てくるので、計算する時にわけわからんくなる
教科書通りの数式を使いたい時は、スカラ値に直して取り扱うと多少はマシ(ただし重力反転要素とか上手くいかなくなるかも)
初速度と角度の計算
弾発射する時の初期値の定義
v0とθを求める
着弾地点と最高到達点を入力にとる
code:cs
void Fire(){
Vector2 target = Player.transform.position;
Vector2 distance = target - this.transform.position;
float top_m = target.y + 3; // 鉛直投げ上げの最高到達点
if(distance.y <= 0) top_m = 3; // 相手が自分より下に居る場合は自分から見て3m上へ
float gravity_mpss = Mathf.Abs(Physics2D.gravity.y); // スカラ値に直す
// v^2 - v0^2 = -2gy (v=0, y=top_m)を使って、v0を計算
// 鉛直投げ上げで、高度topの時に速度が0になる時の初速度v0はいくつ? という式
float initialVelocity_Y_mps = Mathf.Sqrt(2f * gravity_mpss * top_m);
// y = v0t - (1/2)gt^2 + y0 を解の公式で無理やりtを作る (y=distance.y, y0=0) ※
float ivy_mps = initialVelocity_Y_mps; // alias
float landingTime =
( -ivy_mps - Mathf.Sqrt(ivy_mps * ivy_mps -2f * -gravity_mpss * -distance.y) / -gravity_mpss;
// tに基づいて横方向の初速度を計算
float initialVelocity_X_mps = distance.x / landingTime;
// 初速度ベクトルを作成
Vector2 initialVelocity = new Vector2(initialVelocity_X_mps, initialVelocity_Y_mps);
// 初速度のスカラ値(v0)を取得(三平方の定理)
float speed_mps = initialVelocity.magnitude;
// 発射角(θ)を取得
float angle_degree = Mathf.Atan2(initialVelocity.y, initialVelocity.x) * Mathf.Rad2Deg;
// 発射
this.myGun.fire(speed_mps, angle_degree);
}
正直自分で何やってるのかあまり理解してない
※の所について
解の公式:ax^2 + bx + c = 0 の時
$ \frac{-b \pm \sqrt{b^2-4ac}}{2a}
変数の割り当て
$ a=-\frac{1}{2}g
$ b=v_0
$ c=y_0 - y
もろもろ突っ込んで
$ t = \frac{-v_0 \pm \sqrt{v_0^2-4(-\frac{1}{2}g)(y_0-y)}}{4(-\frac{1}{2}g)}
解の公式の±の扱い
https://gyazo.com/1f8719278728ac985873c260197a2dbe
メモ 軌道予測線を出したりするための経路の式
y=tan(θ) * x − g / (2 * v0^2 * cos(θ)^2) * x^2
初速度と発射角を入力に取る
xは上限値決めてリープ使ったり、yが地下に潜るまで計算したり