BasicCreator.prototype.calculateOrbits()
calculateOrbits() メソッドは、投げ方データに基づいて左右の腕の動きや道具の軌道を計算します。
BasicCreator.prototype.paths に指定された SVGPathElement の始点から終点まで移動する時間を1単位とします。全ての SVGPathElement は1単位で移動するため、経路が長ければ速く、短ければゆっくり移動することになります。
サイトスワップ 3 の場合、投げてからキャッチするまでの空中にある時間が2単位で、キャッチしてから次に投げるまで道具が手の平に載っている時間が1単位となります。最初の2単位は空中で放物線を描き、その後の1単位は手の平から BasicCreator.prototype.offset だけずれた軌道を移動します。サイトスワップ 4 なら空中に3単位、5 なら空中に4単位、…以下同様です。
サイトスワップの 2 と 1 は特殊です。2 の場合は投げず、ずっと手の平(から offset だけずれた)軌道を移動します。1 の場合は通常より0.5単位だけ早く投げて、空中を1単位で移動し、反対側の手の平で0.5単位遅れてキャッチします。
アニメーションを実現するには1単位時間をさらに分割する必要がありますが、何分割するかはサイトスワップに含まれる数字 (a = 10, b = 11, ..., z = 35) の最大値によって変わります。
最大値 | 1-5 | 6 | 7 | 8-9 | a-b | c-d | e-g | h-l | m-t | u-z |
---|---|---|---|---|---|---|---|---|---|---|
分割数 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 |
例えばサイトスワップ 3 なら12分割です。97531 の場合は最大値が 9 なので9分割となります。最大値が大きくなると分割数が減って、見た目のスピードは速くなります。そうしないと動作が遅く感じられるからです。
分割数の計算方法は次の通りです。最初に基準としてサイトスワップ 5 の分割数を 12、スピードを 1 と決めて、サイトスワップ 4 以下は 5 と同じとします。6 以上は 1 増えるごとにスピードを 0.1 ずつ増やし、分割数は 12 をスピードで割って四捨五入した値です。
空中に投げられた道具が到達する高さもサイトスワップの最大値で変わります。
最大値 | 1-5 | 6 | 7 | ... | z |
---|---|---|---|---|---|
画面縮尺 | 1 | 1.25 | 1.5 | ... | 8.5 |
1 の高さ | 15 | 12 | 10 | ... | 1.76 |
3 の高さ | 60 | 48 | 40 | ... | 7.06 |
4 の高さ | 135 | 108 | 90 | ... | 15.88 |
5 の高さ | 240 | 192 | 160 | ... | 28.24 |
6 の高さ | - | 300 | 250 | ... | 44.12 |
7 の高さ | - | - | 360 | ... | 63.53 |
: | : | : | : | : | |
z の高さ | - | - | - | ... | 2,040 |
例えばサイトスワップ 7131 の場合は最大値が 7 なので、そこに含まれる数字のうち 7 の高さは 360、1 の高さは 10、3 の高さは 40 となります。
先に画面縮尺を getScale() に示した方法で計算してから、最大値以外の数字も含む高さを求めます。1 の高さは 15 ÷ 画面縮尺 です。3 以上の場合、高さは (数字 - 1)2 × 15 ÷ 画面縮尺 です。これはサイトスワップ 5 を投げた場合に 300×300 の描画領域全体を使うような高さが基準となっています。重力加速度から計算した値ではありません。
構文
calculateOrbits(table, sync)
引数
- table
- 道具ごとの投げ方データです。投げ方データは次のようなオブジェクトで、これを道具の個数だけ配列にします。
-
{ "start": 0, "length": 2, "numbers": [ 5, 1 ], "times": [ 5, 1 ], }
- Siteswap.separate() の返値をそのまま渡すことができます。
- sync
- 投げ方がシンクロなら true を、それ以外なら false を指定します。Siteswap.analyze() の返値の sync プロパティをそのまま渡すことができます。
返値
以下のようなプロパティを持ったオブジェクトを返します。
- arms
- 腕の配列です。腕は2本なので配列の大きさは常に 2 です。それぞれが関節の状態一覧の配列で、大きさは関節の個数です。デフォルトのままなら関節は手の平と肘の2つで、それぞれ状態一覧を持ちます。
- 関節の状態一覧は次のようなオブジェクト(道具の状態一覧と同じ)です。
-
{ "init": [ pi0, pi1, pi2, ... ], "loop": [ pl0, pl1, pl2, ... ], }
- init は初期動作、loop は繰り返し動作です。pi0, pl1 などはその関節を表示すべき座標です。init は空の配列である可能性があります。loop 配列の大きさは、その関節の SVGPathElement の個数×分割数となります。
- props
- 道具の状態一覧の配列です。配列の大きさは道具の個数です。状態一覧は次のようなオブジェクト(関節の状態一覧と同じ)です。
-
{ "init": [ pi0, pi1, pi2, ... ], "loop": [ pl0, pl1, pl2, ... ], }
- init は初期動作、loop は繰り返し動作です。pi0, pl1 などはその道具を表示すべき座標です。init は空の配列である可能性があります。loop 配列の大きさは、引数の投げ方データに含まれる1周期分の高さ(の絶対値)の合計×分割数となります。
例
const result = jmotion.Siteswap.analyze("3");
const table = jmotion.Siteswap.separate(result.throws, result.sync);
const creator = new jmotion.BasicCreator();
const orbits = creator.calculateOrbits(table, result.sync);
// orbits = {
// "arms": [
// [
// {
// "init": [],
// "loop": [
// { "x": -90, "y": 10 },
// { "x": -89, "y": 16 },
// ...
// ],
// },
// {
// "init": [],
// "loop": [ ... ],
// },
// ],
// [
// ...
// ],
// ],
// "props": [
// {
// "init": [],
// "loop": [
// { "x": -90, "y": 0 },
// { "x": -89, "y": 6 },
// ...
// ],
// },
// ...
// ],
// }