Pixel Balanceがどのように動いているのか、物理法則とゲームシステムの内側を開発者自身の言葉で詳しく解説します。単なる仕様書ではなく、「なぜこの数値にしたのか」「どのような試行錯誤を経たのか」まで含めた、物理パズルが好きな方に楽しんでいただけるドキュメントです。
Pixel BalanceはJavaScript製の2D物理エンジン「Matter.js」を使用しています。Matter.jsは剛体シミュレーション、衝突検知、制約(ジョイント)処理などをすべて内蔵したライブラリで、ブラウザ上でそのまま動くため、追加のプラグインやネイティブコードを必要としません。
重力加速度はMatter.jsのデフォルト値(1.0単位)よりも若干強めに設定しています。これは、現実の9.8 m/s²に近い感覚ではなく、「落下の衝撃がしっかりと塔に伝わる」ゲーム的な手応えを生み出すための調整です。重力を強くしすぎると塔がすぐ崩れ、弱くすると緊張感がなくなる——このスイートスポットを見つけるまでに数十回のパラメータ調整を繰り返しました。
また、重力は「上から下」の一方向のみで、ゲーム中に変化しません。これにより、プレイヤーは常に同じ物理ルールの上で戦略を組み立てられ、運の要素を最小限に抑えられています。
ブロック表面の摩擦係数は0.4前後に設定されています。これは、ブロックが滑り落ちず積み上げやすい一方で、完全に滑らない(=積み上げが簡単すぎない)絶妙な数値です。もし摩擦を1.0にすると、どんなに傾いたブロックでも吸い付くように固定されてしまい、バランスゲームとしての面白さが失われます。逆に0.1にすると、真っ平らな面に置いたブロックでも勝手に滑り落ち、プレイが成立しません。
反発係数(restitution)は0に近い値を使っています。これは、ブロック同士が衝突しても跳ね返らず、ピクセルアートらしい「しっとり」とした着地感を実現するためです。高反発(例:0.8)だとボールのように跳ねてしまい、レトロゲーム的な重厚感が損なわれます。
ただし、厳密にゼロにすると完全非弾性衝突となり、今度は塔が揺れなくなって面白みが消えます。実際には0.05程度の微量な反発を許容することで、軽い揺れや小さな振動が発生するようにしています。この微調整がプレイフィールの肝です。
Matter.jsの衝突システムは、broad-phase / narrow-phaseの2段階で動作します。broad-phaseでは、物体の境界ボックス(AABB)同士の交差を高速にチェックして、衝突の可能性がある組み合わせを絞り込みます。narrow-phaseでは、SAT(Separating Axis Theorem、分離軸定理)を用いて正確な衝突検知と接触点の計算を行います。
衝突が発生すると、Matter.jsはそれぞれのボディに対して衝突イベントを発行します。Pixel Balanceではこのイベントをフックして、以下の処理を実行します:
同色ブロックのマッチ検出は、本作の中で最も技術的に面白い部分のひとつです。基本的な流れは以下の通りです:
ここで難しいのは、マッチ処理を毎フレーム実行するとCPU負荷が跳ね上がることです。Pixel Balanceでは、接触状態が変化した(新しい接触が発生した、または既存の接触が解消された)ときにのみマッチ検出を走らせることで、計算量を大幅に削減しています。
また、削除後に上のブロックが落下して新たなマッチを誘発する「連鎖」を検出するため、削除処理直後は短い遅延(約300ミリ秒)を挟んでから再度マッチ検出を走らせています。この遅延時間は、塔の再配置が自然に見える最小値を実験で割り出したものです。
ゲームオーバーは「ブロックが画面下部の指定ラインよりも下に落ちた」ことで判定しています。厳密には、各フレームの終わりにすべてのアクティブなブロックの位置をチェックし、下端ライン以下にあるブロックを検出したらゲーム終了処理を呼び出す、というシンプルな実装です。
ただし、ブロックが一瞬だけラインを超えて戻ってくる(物理演算の過渡状態)こともあるため、実際には「ライン以下に3フレーム連続で存在する」ことを条件にしています。この工夫がないと、激しく揺れる塔で誤ゲームオーバーが頻発します。
スコアは大きく3つの要素から構成されています。
この3層構造により、「安定して積み上げるスタイル」と「マッチ狙いのアグレッシブスタイル」のどちらもハイスコアの可能性があり、プレイスタイルの多様性が担保されています。
描画は、下層から順にレイヤー化された構造になっています。
物理レイヤーとUIレイヤーを分離することで、UIの更新が物理計算に影響しないようにしています。これは地味ですが、安定したゲーム体験を支える重要な設計です。
次に落とすブロックの色と形状は、疑似乱数で決定されます。ただし、完全にランダムだとプレイヤーが「運が悪い」と感じやすいため、いくつかの補正を入れています。例えば、直前の数手で同じ色が3連続しないように重み付けしたり、長方形ばかりが連続しないようにしています。これにより、ランダム性を保ちつつ、理不尽な展開を減らしています。
A developer-written walkthrough of how Pixel Balance actually works under the hood — the physics laws, the algorithms, and the decisions that shaped them. This is more than a spec sheet: it explains why each number was chosen and what trade-offs happened along the way. If you like physics puzzles, I think you'll enjoy this.
Pixel Balance is built on Matter.js, a JavaScript 2D physics engine that handles rigid body simulation, collision detection, and constraint solving entirely in the browser. No native plugins, no extra servers — just JavaScript.
Gravity is tuned slightly higher than the Matter.js default. The goal wasn't real-world accuracy (9.8 m/s²) but to make impacts feel weighty. Too much gravity and towers collapse instantly; too little and there's no tension. Finding the sweet spot took dozens of iterations of hand-tuning.
Gravity is also strictly one-directional (top to bottom) and never changes mid-game. This guarantees players always reason about the same physics, minimizing luck and maximizing skill expression.
Block surface friction sits around 0.4 — high enough that blocks don't slide off each other casually, but low enough that placements still require precision. Crank friction to 1.0 and blocks glue themselves in place regardless of angle; drop it to 0.1 and even perfectly flat placements slip out from under you. Neither extreme is fun.
Restitution (bounciness) is kept near zero. Pixel Balance should feel heavy, not bouncy. At 0.8 restitution, every block would bounce like a basketball, killing the retro-game weightiness we want.
That said, exactly zero restitution creates perfectly inelastic collisions with no residual motion — which is boring. So restitution is set to roughly 0.05: a trace of bounce that lets towers sway subtly and keeps the world feeling alive. That tiny knob is a huge part of the game's feel.
Matter.js uses a two-phase collision system: broad phase and narrow phase. The broad phase uses cheap AABB (axis-aligned bounding box) intersection tests to produce a short list of possible collisions. The narrow phase runs SAT (Separating Axis Theorem) on that short list to compute exact collision points and normals.
When a collision is confirmed, Matter.js fires a collision event on each participating body. Pixel Balance hooks into this event to do several things:
Same-color matching is one of the most interesting technical pieces of the game. The algorithm:
The catch is that running match detection every frame is expensive. Pixel Balance only re-runs the algorithm when the contact graph actually changes — a new contact forms, or an existing one breaks. This cuts the work by an order of magnitude.
To detect chain reactions — where blocks falling into the gap left by a cleared group trigger another match — the match detector is re-run after a short delay (~300 ms) following any removal. That delay was hand-tuned to the smallest value that still lets the tower "settle visibly" before the next check.
Game over is triggered when a block falls below the designated "death line" at the bottom of the screen. The implementation is simple: at the end of every physics step, the positions of all active blocks are checked, and any below the line counts as a game-over signal.
But blocks can briefly dip below the line as a transient of the physics solver and then bounce back up. To avoid false game-overs, a block must stay below the line for three consecutive frames before it counts. Without this, violently oscillating towers would trigger phantom game-overs all the time.
The score is composed of three ingredients.
This three-layer structure means both "safe stacking" and "aggressive match hunting" can produce competitive scores, protecting the diversity of play styles.
Rendering is layered from the bottom up:
Keeping the UI layer separate from the physics layer means UI updates never perturb physics calculations. It sounds minor, but it's a critical pillar of the game's stability.
The color and shape of the next block are chosen with a pseudo-random number generator, but not uniformly. Pure uniform randomness feels unfair — players notice and complain when the same color shows up three times in a row. Pixel Balance applies weight corrections: the recent history of colors and shapes biases the next draw away from repetition. This preserves the feel of randomness while removing the most frustrating patterns.