【マイレース開発記録(15)】canvas描画との戦い
「マイレース」は、入力した情報から計算した結果を、うさぎのレースとして“眺められる”ことが核になっているアプリです。
だからこそ、Canvas描画が安定しないとアプリ全体の体験が崩れます。
この回では、Canvasで「動くレース」を成立させるまでに詰まった点と、どう整理して前に進めたかをまとめます。
目的:レースを“結果表示”ではなく“体験”にする
マイレースは、単に順位を出す占いではありません。
「仕事・金運・恋愛・健康・勝負」の5つを、それぞれ別のうさぎとして走らせ、速度とジャンプの違いから「流れ」と「リズム」を読み取れるようにしています。
そのためにCanvasで実現したかったのは、次の3点でした。
- 5レーンを並走する
- スピード差が視覚的に伝わる
- ジャンプ(上下の揺れ)でリズムを感じられる
Canvasは自由度が高い反面、HTMLのように「勝手に整ってくれる」仕組みがありません。
描画の基本から、ひとつずつ積み上げる必要がありました。
まず詰まったのは「座標の基準」と「レイアウト変動」
Canvasは「座標で置く」ので、設計が曖昧だと破綻します。
今回のレースは、画面幅によって見え方が変わる前提なので、
「開始地点とゴール地点」を固定値で決めると、以下が起きました。
- 画面が広いとレースが間延びする
- 画面が狭いとゴールラインが見切れる
- うさぎと文字が重なる
結果、座標計算を「Canvas幅に対する割合」で持つ方針に変えました。
Python
function updateRaceBounds(){
SX = cv.width * 0.12;
GX = cv.width * 0.93;
}
固定値で逃げずに、描画領域の基準を数式に落とすことが必要でした。
Canvasの「更新」=ループが必要
Canvasの基本は、毎フレーム「描き直す」ことです。
最初は「一度描画すれば動く」感覚で考えてしまい、当然動きませんでした。
ここで理解したのが、
- 更新:状態を進める
- 描画:状態を画面に反映する
- これを毎フレーム繰り返す
という分離です。
今回の実装はこの形に落ち着きました。
up():状態更新dr():描画requestAnimationFrame(lp):次のフレームへ
JavaScript
function lp(){
if(!st.r)return;
up(); dr();
requestAnimationFrame(lp);
}
この分離をしたことで、「どこが壊れているか」が追えるようになりました。
ジャンプロジックの破綻:跳ねるタイミングが揃わない
ジャンプは、単純に「上下に揺らす」だけだと面白くなりません。
そこで「占星術的なフェーズ(moon / mars)」を位相に使う設計にしました。
JavaScript
function j(r){
let ph=(r.k==="love"||r.k==="health")?st.p.moon:st.p.mars;
return Math.sin(st.f/45*2*Math.PI+ph*6)*8;
}
しかしこの段階で起きたのが、
- 跳ねが大きすぎてレーンから飛び出す
- うさぎが揃って跳ねてしまい“違い”が消える
- フェーズが変わっても違いが分かりづらい
ここはAIとの対話がかなり役立ちました。
「式を変えれば解決」というより、何を表現したいのかを言語化し直したのが大きいです。
- ジャンプは派手さではなく「リズムの差」
- 跳ね幅はレーン内に収める
- 位相は“ズレ”として効かせる
結果として振幅を控えめにして、差が見える方向に寄せました。
背景がうるさい問題:読めない、見えない
芝生背景(画像)を入れたことで雰囲気は出たのですが、そのままだと「レーンの文字」が読めなくなりました。
CanvasはCSSのように簡単に「背景を暗くする」ができないので、描画段階で半透明プレートを敷く方法にしました。
JavaScript
cx.fillStyle = "rgba(0, 0, 0, 0.28)";
cx.fillRect(0, 0, PLATE_W, cv.height);
この一枚で、UIが一気に“使える画面”になりました。
見た目の調整も、Canvasでは「描画処理の一部」になります。
レスポンシブ対応:Canvasは勝手に縮んでくれない
見た目はCSSで width:100% にできますが、Canvasは厄介です。
CSSで見た目を変えても、内部座標は変わらず、描画がぼやけたりズレたりします。
今回は、極端にCanvasサイズを動的変更せず、
- 見た目はCSSで調整
- 内部座標は固定(560×180)
- SX/GXを割合で調整
という「破綻しにくい方式」に寄せています。
これが結果的に、安定性を上げました。
まとめ
Canvasで詰まったことは、技術的には細かい話が多いです。
でも就活目線で大事なのは、「詰まり方」と「解き方」だったと思います。
- 曖昧なまま描くと破綻する → 基準を数式で固定する
- ループがないと動かない → 更新と描画を分ける
- 見えないUIは存在しない → 表示補助は描画に組み込む
- レスポンシブはCanvasの外だけでは完結しない → 設計方針を決める
そして個人的には、ここがAI協働の良さが最も出た部分でした。
Canvasは「何が原因か分からないまま沼る」領域になりやすい。
自分の状況を言葉にして、仮説を立て、試して、整理する。
その反復が途切れにくくなりました。
次回予告
次回は、Canvasを動かした上で
- レース進行の気持ちよさ
- ゾーン演出(CSSグロー)
- “占い”として読めるUI
を整える話に入ります。
次の記事は。
として、動きの安定化と「止め方」「終わらせ方」の設計を書きます。


