【マイレース開発記録(17)】ジャンプロジックの破綻
――「跳ねる」表現をどう作るか
マイレースでは、ウサギの「速さ」だけでなく、もうひとつ大切な要素があります。
それが ジャンプ(跳ね) です。
レースの順位は「外側の流れ」、ジャンプは「内側のリズム」を表すための要素として設計しました。
しかし、このジャンプのロジックは、フロントエンド実装の中で一度完全に破綻します。
今回は、その過程を記録しておきます。
「ジャンプ」はどう表現するか
最初の設計では、ジャンプはとても単純でした。
一定の周期で上下に動かせば、それっぽいアニメーションになるだろうと考えていたからです。
JavaScript では、次のような式で高さを計算していました。
JavaScript
Math.sin(frame / 45 * 2 * Math.PI)
sin 波を使えば、自然な上下運動になります。
この値に振幅を掛ければ、ジャンプの高さを作ることができます。
つまり、
高さ = sin波 × 振幅
という単純な構造です。
ここまでは、問題なく動きました。
しかし、全員同じジャンプになった
実際に表示してみると、すぐに違和感が出ました。
すべてのウサギが同じタイミングで跳ねる のです。
見た目としては、
- 行進している
- 同期している
ような動きになってしまいました。
本来やりたかったのは、
- それぞれ違うリズムで跳ねる
- 心の状態の違いを表す
という表現です。
そこで「ジャンプの位相」を個別にずらす必要がありました。
フェーズ(位相)を導入する
ここでバックエンドのロジックと接続します。
マイレースでは、次の2つの周期を計算しています。
- 月周期
- 火星周期
それぞれの周期を「フェーズ(phase)」として計算しています。
Python
def calc_phase(days, period):
return (days % period) / period
この値は 0〜1 の範囲になります。
このフェーズを、sin 波に足すことで、ジャンプのタイミングをずらすことができます。
JavaScript 側ではこうなりました。
JavaScript
Math.sin(frame / 45 * 2 * Math.PI + phase * 6)
これで、ウサギごとに違うリズムになります。
ここで別の問題が発生する
この変更を入れると、確かに動きは自然になりました。
しかし、今度は別の問題が起きます。
ジャンプの高さがレース結果に影響してしまうのです。
ジャンプが大きいと、ウサギが前に進んでいるように見えてしまう。
つまり、
- 見た目の動き
- 実際のレース順位
がズレてしまいました。
占いとしては、これは致命的です。
レース結果はあくまで天体計算の結果で決まる必要があります。
表示ロジックを完全に分離する
そこで設計を整理しました。
レースには2つのレイヤーがあります。
① 計算レイヤー(バックエンド)
- 天体計算
- スピード計算
- ゴール順位
これは Python 側で確定します。
② 表示レイヤー(フロントエンド)
- 走るアニメーション
- ジャンプ演出
- レース演出
これは JavaScript 側だけで処理します。
ジャンプは完全に表示専用の演出として扱うことにしました。
そのため、
JavaScript
r.y0 = r.by - jump(r)
のように、Y座標だけを上下させる構造に変更しました。
X座標(前進)はジャンプとは無関係に進みます。
これで
- レース順位
- ジャンプ演出
を分離することができました。
小さな演出が意味を持ち始めた
ジャンプは、ただのアニメーションではありません。
マイレースでは、
- HIGH
- NORMAL
- LOW
の3段階で表示されます。
JavaScript
if(p > 0.75) return "HIGH"
if(p > 0.45) return "NORMAL"
return "LOW"
この値は、
- 月フェーズ
- 火星フェーズ
から計算されます。
つまり、ジャンプは
「気持ちの揺れ」や「内側のエネルギー」
を表す演出です。
AIとの開発で助かった部分
このジャンプロジックは、思った以上に試行錯誤が多い部分でした。
特に難しかったのは、
- アニメーションと計算ロジックの分離
- 数式の調整
- Canvas座標の扱い
です。
AIとの対話では、
- 数式の意味を確認する
- 描画ロジックを整理する
- 表示バグの原因を分解する
といった形で、思考整理に使うことができました。
コードをそのまま採用するのではなく、理解しながら調整することで、
最終的なロジックは自分で組み直しています。
まとめ
ジャンプの実装は、「見た目の演出」として始まりました。
しかし開発を進める中で、
- 計算ロジック
- 表示ロジック
- 占いとしての意味
を整理する必要が出てきました。
その結果、
ジャンプは順位とは独立した
「内側のリズム」の表現
として設計し直されています。
小さなアニメーションですが、マイレースのコンセプトを支える重要な要素になりました。
次回予告
次の記事は、
として、
ゾーン結果によって、フォームが光る演出をどのように実装したのかを書いていきます。


