<問題>
スタートからゴールまでの間に4か所の中継地点があり、それぞれの座標が示されています。
それぞれの区間の距離はバラバラです。
それぞれの区間内の移動速度は一定ですが、区間毎にはバラバラです。
これらの座標と速度が示されているとき、「スタートからゴールまでにかかる時間のパーセンテージ」を渡された際に、どの区間のどの距離にいるのかを計算し座標を求めるプログラムを作成しなさい。
(各区間のルートは直線もしくは方程式で表現できるものとします)
文章だけを読むと、なんだかややこしそうですね。
まずは問題を紐解いていきながら理解を深めます。
スタートとゴールまでの間に、中継地点が4か所ありますので、これらをS・A・B・C・D・Gとしましょう。
6つの場所にはそれぞれ座標が示されています。
分かりやすく1次元で考えます。(地図なら2次元ですね。考え方は同じです)
それぞれの区間の距離が全て同じで、移動速度も全て同じならば、「スタートからゴールまでにかかる時間のパーセンテージ」が50%だとすると、全体距離のちょうど半分、つまりBとCの中間地点にいることになります。
しかし実際には各区間の距離はバラバラなので、ちょうどBとCの中間に来るとは限らないわけです。
もし各区間の移動速度が全て一定だったとすると、50%の場所を出すには、各区間の距離を出し、総距離に占める割合を出して、さらにその区間内の割合を出すことになります。
例えば各区間の距離が以下の場合、50%であれば、CポイントとDポイントの区間を1/4の距離を進んだところになります。
今回の問題では距離ではなく時間の割合が与えられています。
そして区間ごとの移動速度もバラバラなわけですので、今までの考え方を応用して、全体の所要時間と各区間の所要時間を出していきます。
時間は距離を速度で割れば出ます。
全体の所要時間と各区間の所要時間が出れば、各区間の時間による割合を出していけます。
すると上の図と同じような形で表すことができます。
先ほどは区間毎の距離を書いていましたが、今度は時間になります。
50%であれば、CポイントとDポイントの区間を1/4の時間を進んだところになります。
1/4の時間を進んだ距離は、時間と速さを掛ければ出てきます。
これで「どの区間か」と「その区間で進んだ距離」が出てきます。
あとはCの座標からDの方向に「その区間で進んだ距離」を足してやれば、現在の座標が出てきます。
アルゴリズムができたらプログラムに落とし込んでいきます。
なお今回のプログラムは各区間が直線であることを前提としています。
public static float GetPoint(float[] points, float[] speed, int percent)
{
if (percent <= 0)
{
return points[0];
}
else if (percent >= 100)
{
return points[points.Length - 1];
}
var totalTime = 0f;
var second = new float[speed.Length];
for (var i = 0; i < points.Length - 1; i++)
{
second[i] = (points[i + 1] - points[i]) / speed[i];
totalTime += second[i];
}
var nowPer = 0;
for (var i = 0; i < (second.Length - 1); i++)
{
// エリアパーセンテージ(区間時間/全体時間)
var areaPer = (int)((second[i] * 100) / totalTime);
if ((nowPer + areaPer) < percent)
{
nowPer += areaPer;
}
else
{
nowPer = percent - nowPer;
var freq = (float)nowPer / areaPer;
var pos = (points[i + 1] - points[i]) * freq + points[i];
return pos;
}
}
}
プログラムが書けたら、ちゃんと動いているかどうかデバッグです。
デバッグは適当に値を設定して、正しい値を返すかどうかをチェックします。
このためチェックには事前に答えを知っておく必要があり、自分自身で解ける必要があります。
なのでプログラムを書く前に問題をしっかり理解しておくことが必要なわけですね。
時間と距離と速さの関係とそれに伴う変換はゲームでもよく使います。
今回は考えをシンプルにするために単位をなるべく省いて考えましたが、実際の製作においては単位が非常に重要になってきます。
単位の変換にも注意しましょう。
コメント