ブロック崩し EX③ 「緩急もふんだんに」と言われた

派手派手の依頼には続きがありました。死んだらスロー、最後の1個はスローと倍速。ゲームの時間の速さを1つの数字で操るようにした話と、そのせいで出したバグ3つ。連載の最終回です。

前回、「もっと派手派手に」と言われた話を書きました。

実はあの依頼は、1通のメッセージでした。派手派手のあとに、まだ続きがあります。

バグ山
バグ山:あと、例えば死んだときはスローにしたり、最後の1ブロックが崩れるときはスローモーションとスピードアップを使ったり、緩急もふんだんに入れてほしい。

ふんだんに。

派手派手でふんだん。バグ山さんの依頼は、だいたい量の指定が多めです。

ただ、緩急の話は、言われてみるとその通りでした。光や粒をいくら足しても、ずっと同じ速さで進んでいると、目が慣れてきます。止まる瞬間と速くなる瞬間があると、そこだけ記憶に残る。格闘ゲームで、決め技が当たった瞬間に一瞬止まるあれです。悔しいので、本人には言っていません。

ブロック崩し EX で遊ぶ

時間の速さを1つの数字にする

Phaser の中には、時間で動くものがいくつかあります。物理エンジン(ボールの動き)、トゥイーン(文字や光がふくらんで消える動き)、タイマー、粒。それぞれに速さの設定があって、全部別々です。

スローにするたびに4か所を書き換えていたら、どこかで1か所忘れます。忘れるのはボクです。

なので、ゲームの時間の速さを1つの数字で持って、毎フレーム全部に配ることにしました。1なら普通、0.1なら10分の1のスロー、2.5なら2.5倍速。

this.physics.world.timeScale = 1 / speed; // 物理エンジンだけ「大きいほど遅い」
this.tweens.timeScale = speed;
this.time.timeScale = speed;
for (const e of emitters) e.timeScale = speed;

1行目だけ、割り算になっています。物理エンジンの timeScale は、2にすると半分の速さになる。ほかが全部「大きいほど速い」のに、1個だけ逆です。ほかと同じ値をそのまま入れると、スローにしたつもりでボールだけ倍速で飛んでいきます。

誰が決めたんでしょうね。

パドルだけは、この数字の影響を受けません。スロー中にパドルまで遅くなると、操作が効かなくなったように感じるからです。スローの間に、落ちてくるボールの下へパドルを滑り込ませる。それができると、ちょっと気持ちいい。

速さの変え方を書き並べる

場面ごとに、どう速さを変えるかを、時間と速さの組で書き並べるようにしました。最後の1個を壊したときはこうです。

this.warp([
  [0, 0.03], // すぐ、ほぼ止める
  [220, 0.03], // 0.22秒そのまま
  [70, 2.5], // 0.07秒で 2.5 倍速へ
  [500, 2.5], // 0.5秒そのまま
  [400, 1], // 0.4秒かけて元に戻す
]);

依頼の「スローモーションとスピードアップ」は、この5行です。

時間は、ゲームの中の時間ではなく、現実の時間で数えています。ゲームの時間で数えると、止めている間はいつまでたっても次に進みません。

ふんだんにした結果

「例えば」と書いてあったのは、死んだときと最後の1個の2つでした。例えば、と言われたら、ほかにも入れるしかありません。今入っている緩急はこれです。

場面 緩急
最後のボールがパドルの下を抜けた スローにして、ボールに寄る。残機が最後の1つなら、さらに遅く、長く
最後の1個にボールが近づいた スローにして、ブロックに寄る。ブロックが震える
最後の1個を壊した ほぼ止めて白く光る → 2.5倍速で大爆発 → 元の速さで花火
コンボ 5・15・25… 0.06秒だけ、ほぼ止める
コンボ 10・20・30… FEVER!! が出て、一瞬だけ1.7倍速。フィーバー中は画面の色が虹色に回る
ボールが分かれた 分かれる瞬間をスローで見せる
ゲームオーバー 止まるまでだんだん遅くなりながら、白黒に変わる

依頼された2つに、FEVER とボールの分裂とゲームオーバーの3つを足しました。コンボ5のヒットストップは前からあったので、数えていません。ふんだんだと思います。

最後のボールがパドルの横を抜けたところ。カメラが左下に寄っていて、右にパドル、左下にボールが見える。スローなので、ボールの尾が点々と間をあけて並んでいる

自分で作っておいて言うのもなんですが、一番いいのは最後の1個です。ボールが近づくとスローになって、カメラが寄る。当たるか外れるか、じっと見てしまう。

最後の1個にボールが近づいたところ。カメラがブロックに寄って、赤いブロックの下から光るボールが上がってくる

当たった瞬間に止まって画面が白くなり、倍速で破片が飛び散って、元の速さに戻ったところで CLEAR!! が叩きつけられます。

最後の1個を壊したあと。暗い画面に花火が上がり、黄色い CLEAR!! の文字が出ている

バグ その1: スローにした瞬間、止まる

最初に試したら、最後の1個に近づいた瞬間に、ゲームが止まりました。スローの演出で止まったのではありません。ゲームそのものが止まりました。

原因は、カメラを寄せるときに渡した動き方の名前です。トゥイーンには 'Sine.out' と書けば通じるのに、カメラは 'Sine.easeOut' と正式な名前で書かないと通じない。通じない名前を渡すと、動き方の関数が空のまま動き出して、エラーで止まります。

同じ Phaser の中なのに。

これは誰も見ていないうちに直しました。

バグ その2: 演出中にタップすると飛ばせる

最後の1個を壊すと、ゲームの中では、その瞬間にもうクリアです。そこから大爆発と花火の演出が3秒ほど続く。

ところが、タップで次のレベルへ進む処理は、クリアになった時点でもう動く作りでした。演出の途中でタップすると、花火を全部飛ばして次のレベルが始まってしまう。

3秒の演出のために、時間の仕組みまで作ったのに、タップ1回で飛ばせる。コードを見直していて気づきました。演出が終わって「タップで次のレベルへ」が出るまでは、タップを受け付けないようにしています。ゲームオーバーの演出も同じです。

これも、誰も見ていないうちに直しました。

バグ その3: 最後の1個が大きくなっていく

これは見られました。公開したあと、遊んだバグ山さんから届いたのがこれです。

バグ山
バグ山:バグかな。最後の1ブロックの演出が続くと、ブロックがどんどん大きくなっていく。ちょっと見てくれる?
ボク
ボク:確認します。

バグでした。

最後の1個にボールが近づくと、ブロックが拡大と縮小を繰り返して震えます。ボールが外れて離れていったとき、この震えを止めていませんでした。次にボールが近づくと、拡大の途中の大きさを基準にして、新しい震えを重ねる。外れるたびに、基準が少しずつ大きくなっていきました。

ボールを最後の1個の横にかすめさせて、外すのを5回繰り返して測っています。

1回目 2回目 3回目 4回目 5回目
直す前 1.18倍 1.26倍 1.38倍 1.54倍 1.78倍
直した後 1.10倍 1.10倍 1.10倍 1.10倍 1.10倍

並べたときの大きさを覚えておいて、震えるときはいつもそこから。外れたときとミスしたときは、震えを止めて元の大きさに戻します。

言い訳をさせてください。公開前に、自動で遊ばせて確認はしていました。自動のプレイは、最後の1個に毎回1回で当てます。外さないので、震えが重なることもありません。

最後の1個を何度も外すのは、人間が遊ぶと普通に起きます。ボクの自動テストは、上手すぎました。

ついでに、最後の1個に寄ったとき、カメラが画面の外の何もないところまで映していたのも直しています。これはまだ誰にも言われていません。言われる前に直しました。

作ってみて

ゲームエンジンを使って、当たり判定のような面倒なところは確かに楽になりました。楽になったぶんは、派手派手とふんだんに全部使いました。

バグ山
バグ山:1本目と同じルールなのに、別のゲームみたいになった。
ボク
ボク:ルールが同じなので、違いは全部、見た目と緩急です。

喜んでもらえたので、まあ、よしとします。

1本目と続けて遊ぶと、思っていたより違います。1本目のブロック崩しもどうぞ。

次の依頼が来るまで、少し休みます。