Unityで必殺技が次のWaveへ持ち越される不具合を修正した記録
第三者テストで見つかった、範囲型必殺技が次のWaveの敵へ当たる不具合について、再現手順、原因、状態管理の見直し、修正内容とテスト観点をまとめます。
Unityで制作しているスマートフォン向けゲーム「おはじきバトル(仮)」を友人に遊んでもらったところ、必殺技とWave遷移が重なったときに発生する不具合が見つかりました。
開発中は自分でも繰り返し動作確認をしていましたが、普段とは異なる操作をしてもらったことで、処理の境界にある問題を発見できました。
今回は、不具合が発生した操作、原因調査で分かったこと、必殺技システムの再設計、Wave遷移の修正内容についてまとめます。
発見された不具合
問題が発生したのは、範囲型必殺技を選択した状態で、現在のWaveに残っている最後の敵を通常の移動によって倒したときです。
具体的には、次の操作で再現しました。
- 範囲型必殺技を選択する
- キャラクターを引っ張って移動させる
- 移動中の接触ダメージで、そのWaveの敵をすべて倒す
- 敵全滅によって次のWaveへ移動する
- 必殺技の演出と効果が、次のWaveで処理される
演出を有効にしている場合は、前のWaveで選択した必殺技が次のWaveの敵へ当たりました。
一方、演出を無効にしている場合は、必殺技が発動しないまま次のWaveへ進みました。
同じ操作でも演出設定によって結果が変わるため、単純なダメージ処理だけではなく、演出完了後に呼ばれる処理とWave遷移の順番に問題があると考えました。
第三者テストで初めて見つかった理由
自分でテストすると、必殺技を選択した後は「移動してから画面をタップし、必殺技を発動する」という想定どおりの操作をしがちです。
しかし今回は、必殺技を選択した状態で最後の敵を移動中に倒すという、機能同士の境界をまたぐ操作が行われました。
個別に確認すると、次の機能はそれぞれ正常に動いていました。
- 必殺技を選択できる
- キャラクターを移動できる
- 接触によって敵を倒せる
- 敵が全滅すると次のWaveへ進む
- 必殺技の演出後に効果を発生させる
ところが、これらが同じタイミングで動くと、処理の完了順序が崩れました。
機能単体のテストだけではなく、「必殺技の待機中に敵が全滅する」といった状態の組み合わせを確認する必要がありました。
原因調査で分かったこと
調査したところ、敵の全滅通知を受けると、必殺技が待機中または演出中であっても、Wave遷移や最終勝利の処理へ直接進む構造になっていました。
主な問題は次のとおりです。
必殺技の完了を待つ仕組みがなかった
敵の全滅を検知した時点でWave遷移が開始され、回復、吹き飛ばし、追加ダメージなどの残っている効果を待っていませんでした。
そのため、必殺技の演出が終わる前に、古い敵が削除されて新しいWaveの敵が生成される可能性がありました。
発動時点の対象を保存していなかった
必殺技を選択した時点や発動を確定した時点ではなく、効果を実行する段階で対象を取得すると、その間にWaveが変わった場合、次のWaveの敵が対象に含まれてしまいます。
必殺技が「どこで、誰に対して、どの攻撃力で発動したか」を一つの行動として保存する必要がありました。
古いコールバックを判別できなかった
演出の終了後に効果処理を呼び出していましたが、そのコールバックが現在の戦闘・Wave・行動に属するものか確認する識別子がありませんでした。
画面上では次のWaveへ進んでいても、前のWaveで登録された処理が後から実行される状態でした。
演出ONとOFFで完了タイミングが異なっていた
演出を無効にした場合は完了コールバックが即時実行され、演出を有効にした場合は一定時間後に実行されていました。
処理経路が分かれていたため、演出の設定によって必殺技が持ち越されたり、発動しなかったりする違いが生まれていました。
必殺技の操作と効果を分離した
今回の修正を機に、必殺技を一つの共通処理へ押し込むのではなく、「どのように操作するか」と「何が起きるか」を分けました。
必殺技の構成は、主に次の四つに整理しています。
操作設定
- 移動型または範囲型
- 効果範囲の半径
- 使用する演出
- 必殺ゲージの消費量
効果設定
- ダメージ倍率
- 回復率
- 移動距離や速度の強化
- 敵の貫通
- 吹き飛ばし
- 敵同士や壁との再接触ダメージ
- 攻撃力・防御力の弱体化
行動状態
必殺技の状態を、選択から終了まで追跡します。
選択
↓
行動開始
↓
待機・演出
↓
効果処理
↓
完了または取消
対象確定
範囲型必殺技では、発動を確定した時点で次の情報を保存します。
- 発動中心
- 対象となる敵と味方
- 使用者の攻撃力
- 戦闘、Wave、行動の識別子
演出後に対象を探し直さないことで、途中でWaveが切り替わっても、新しく出現した敵へ効果が移ることを防ぎます。
Wave遷移を「即時実行」から「遷移予約」へ変更した
修正前は、敵が全滅するとその場でWave遷移を始めていました。
修正後は、敵全滅時にすぐ切り替えず、まず「次のWaveへ進む必要がある」という予約だけを保存します。
その後の処理は、必殺技の状態によって分けています。
- 必殺技の発動前なら、待機状態を取り消して遷移する
- 発動後なら、演出とすべての効果が完了するまで待つ
- 回復、吹き飛ばし、追加ダメージも完了条件に含める
- 完了後に予約されていたWave遷移または勝利処理を実行する
これにより、最後の敵を倒した直後でも、前のWaveに属する処理を安全に終了してから次へ進めるようになりました。
古い非同期処理を識別子で無効化した
演出や遅延処理は、開始時と実行時でゲームの状態が変わっている可能性があります。
そこで、コールバックを実行する前に、次の識別子が現在の状態と一致するか確認するようにしました。
- 戦闘世代
- Wave番号
- 行動ID
一致しない場合は、過去の戦闘やWaveから残った処理として無効化します。
戦闘世代を持たせたことで、リトライ後に以前の戦闘の処理が実行されることも防げます。
最終勝利、敗北、リトライ、リタイアでも、同じ終了処理を通して、残っている一時効果や入力状態を解除するようにしました。
演出ONとOFFを同じ処理経路に統一した
演出OFFでは処理を即時完了させますが、必殺技の状態遷移そのものは演出ONと共通にしました。
異なるのは演出にかかる時間だけで、次の流れは変わりません。
- 発動時の情報を確定する
- 必殺技を発動状態にする
- 演出を実行する、または即時完了する
- 確定済みの対象へ効果を適用する
- 必殺技を完了状態にする
- Wave遷移予約があれば遷移する
これにより、演出設定を変えてもゲーム上の結果が変わらない構造になりました。
必殺ゲージを消費するタイミング
必殺ゲージは、キャラクターを発射する入力が確定した時点で一度だけ消費します。
移動によって最後の敵を倒し、範囲効果を使う必要がなくなった場合でも、ゲージは返却しない仕様にしました。
必殺技を選んで移動を開始する判断も、ゲーム上の駆け引きに含めるためです。
一方で、処理の重複によってゲージが複数回減らないよう、同じ行動IDでは一度だけ消費するようにしています。
6属性の必殺技へ対応できる構造にした
今回の修正はWave遷移だけを直すものではなく、初期6キャラクターの必殺技を同じ仕組みで扱うための整理も含んでいます。
- 火:範囲内へ大ダメージ
- 水:範囲内へダメージを与え、使用者を含む味方を回復
- 風:移動距離を強化し、敵を吹き飛ばして敵同士の接触で追加ダメージ
- 雷:移動速度を強化して敵を貫通し、最初に触れた敵の行動カウントを増加
- 岩:範囲内へダメージと吹き飛ばしを与え、壁への再接触で追加ダメージ
- 闇:範囲内へダメージを与え、敵の攻撃力と防御力を一定期間低下
キャラクター名による分岐ではなく、必殺技を識別するIDから専用設定を参照します。
倍率、範囲半径、ゲージ消費量、レベルごとの成長値を設定側へまとめ、ゲーム内の説明文も同じ値から生成できるようにしました。
これにより、実際の効果と説明文の数値が食い違う問題も起こりにくくなります。
修正後に確認したいテストケース
今回のような不具合は、正常な発動だけを確認しても見つけにくいため、境界条件を中心に確認します。
- 通常移動で最後の敵を倒した場合
- 範囲型必殺技の選択中に最後の敵を倒した場合
- 必殺技の演出中に最後の敵を倒した場合
- 演出ONとOFFの両方
- 最終Waveで同じ操作をした場合
- 必殺ゲージが一度だけ消費されること
- 次のWaveの敵へ前のWaveの効果が入らないこと
- 回復、吹き飛ばし、追加ダメージの完了後に遷移すること
- リトライ後に古いコールバックが動かないこと
- リタイアや敗北時に入力状態と一時効果が解除されること
修正箇所だけではなく、その周囲にある勝利、敗北、リトライなども確認することが重要です。
第三者テストで得られた学び
今回の不具合は、友人に自由に遊んでもらったことで見つかりました。
開発者は仕様と内部処理を知っているため、無意識に正しい操作を選びやすくなります。対して、初めて触る人は、開発者が想定していなかった順序で機能を組み合わせます。
特にゲームでは、次のような境界で不具合が発生しやすいと感じました。
- 演出中に敵が全滅する
- 行動中にWaveが切り替わる
- 入力待機中に勝利条件を満たす
- 一時効果が残った状態でリトライする
- 同じ対象へ短時間に複数回接触する
今後は、機能ごとの確認に加えて、複数の状態が重なる操作もテスト項目へ入れます。
また、公開前に複数人へ触ってもらい、操作方法を細かく指定しない自由テストの時間も設けたいと考えています。
まとめ
今回は、範囲型必殺技の処理中に敵が全滅すると、必殺技が次のWaveへ持ち越される不具合を修正しました。
原因は、必殺技の完了を待たずにWave遷移が始まること、発動時点の対象を保存していないこと、古いコールバックを識別できないことにありました。
修正では、操作と効果を分離し、必殺技の行動状態と対象を保存しました。敵全滅時は遷移を予約し、すべての効果が完了してから次のWaveへ進むようにしています。
一つの不具合を個別対応するだけでなく、今後追加する必殺技にも使える構造へ整理できました。
そして、開発者以外の人に実際に触ってもらうことが、想定外の操作や状態の組み合わせを発見するうえで重要だと改めて分かりました。