マガジン

ゲーム中に画面が暗くなる:スマホのスリープを防ぐ方法

遊びをつくる

執筆にClaudeを使用しています。

キーボードとタッチの二つの入力が、同じ駒のジャンプにつながる様子を描いたイラスト。
記事のテーマをもとに制作したAI生成イラスト。

ブラウザゲームをスマホでプレイしていると、少し手を止めるだけで画面が暗くなり、スリープに入ってしまうことがあります。パズルゲームで考え込む場面、リズムゲームの待機画面、チュートリアルの説明を読んでいる最中など、「操作がない=放置」とOSに判断されてしまうのが原因です。 この問題はゲーム側のコードで対処できます。ブラウザに搭載された Wake Lock API を使うと、スマホやタブレットのOSに「画面を消灯しないでほしい」と伝える信号をJavaScriptから送れます。OSの設定を変えずに、ゲームが起動している間だけスリープを抑制できるのが特徴です。 この記事では、Wake Lock APIの仕組みと使い方、取得・解放のタイミング、古いブラウザへの対処、よくある失敗パターンを順に説明します。

この記事の目次
  1. Wake Lock APIとは何か
  2. 基本的な取得と解放の書き方
  3. 非表示になったときの再取得
  4. 対応ブラウザの確認と非対応環境への対処
  5. よくある失敗パターン
  6. テスト方法
  7. 次の行動
  8. 参考資料

Wake Lock APIとは何か

Wake Lock APIは、W3Cが標準化を進めているブラウザ向けAPIです。navigator.wakeLock.request('screen') を呼び出すと、OSに対して「このページが表示されている間はスクリーンをオフにしないでください」と要求を送ります。

重要な点が二つあります。一つ目は、ユーザーの操作(タップ・クリックなど)のあとにしか呼び出せないことです。ページ読み込み直後に自動で呼ぶと、ブラウザがリクエストを拒否します。ゲームの「スタートボタンを押した瞬間」に取得するのが自然なタイミングです。

二つ目は、ページが非表示になると自動で解除されることです。ホームボタンを押したり、別のタブに切り替えたりすると Wake Lock は自動的に失効します。ゲームに戻ったときに再取得しないと、その後も画面がスリープしてしまうので、再取得の処理も必ずセットで書きます。

基本的な取得と解放の書き方

javascript
let wakeLock = null;

async function requestWakeLock() {
  if (!('wakeLock' in navigator)) return; // 非対応環境は何もしない
  try {
    wakeLock = await navigator.wakeLock.request('screen');
  } catch (err) {
    // バッテリー残量が極端に少ないときなど、OSが拒否する場合がある
    console.warn('Wake Lock の取得に失敗しました:', err);
  }
}

function releaseWakeLock() {
  if (wakeLock) {
    wakeLock.release();
    wakeLock = null;
  }
}

呼び出すタイミングの目安は次のとおりです。

  • 取得:スタートボタン押下、ゲームループ開始時
  • 解放:ゲームオーバー・クリア画面表示時、メニューに戻るとき

ゲームを最後まで遊んだあと画面を見続ける理由はないので、ゲームが終わったら releaseWakeLock() を呼んで明示的に解放します。バッテリーへの配慮という観点でも、不要になった Wake Lock を持ち続けるのは避けたほうがよいです。

非表示になったときの再取得

ページが非表示になると Wake Lock は自動解除されますが、wakeLock 変数にはオブジェクトが残ったままになります。visibilitychange イベントを監視して、ゲームが再び表示されたときに取得し直すのが定番の対処です。

javascript
document.addEventListener('visibilitychange', async () => {
  if (document.visibilityState === 'visible' && isGameRunning) {
    await requestWakeLock();
  }
});

isGameRunning はゲームの進行状態を管理するフラグです。メニュー画面に戻っているときは再取得しない、という制御を入れておくとより丁寧な実装になります。

対応ブラウザの確認と非対応環境への対処

Wake Lock APIは主要なモバイルブラウザでサポートされていますが、古い機種や一部のブラウザでは使えない場合があります。'wakeLock' in navigator で対応確認ができるので、非対応の場合は処理をスキップするだけで十分です。スリープを防げないだけでゲーム自体は動くので、エラーを出して止める必要はありません。

Safariはバージョンによってサポート状況が異なります。iOS端末向けに確実な対応が必要な場合は、公式の MDN Web Docs や Can I use で最新の対応状況を確認してください。

代替手段として、かつては「小さな音声を無音再生し続ける」「非表示のビデオをループ再生する」といったハック的な方法が使われていました。ただし、これらはブラウザのバージョンアップで動作が変わりやすく、ユーザーに意図しない通知(再生中マークなど)が表示されることもあります。現在は Wake Lock API が使えるなら素直にそちらを使うほうが安定します。

よくある失敗パターン

ページ読み込み直後に呼んでいる:ユーザー操作なしに request() を呼ぶと NotAllowedError が返ります。必ずボタン押下などのイベントハンドラの中で呼び出してください。

async/await を使わずに呼んでいる:navigator.wakeLock.request() は Promise を返します。await なしで呼ぶと取得完了を待たずに次の処理に進んでしまい、wakeLock 変数が null のままになることがあります。

解放処理を書いていない:ゲームクリア後もずっと Wake Lock を保持し続けるのは、ユーザーのバッテリーを不必要に消費します。ゲームが終わる画面遷移と合わせて releaseWakeLock() を呼ぶ習慣をつけましょう。

visibilitychange の再取得を忘れている:バックグラウンドから復帰したあとに画面がまたスリープするという報告は、この再取得の漏れが原因であることがほとんどです。

テスト方法

実装後は実機で動作を確認することが欠かせません。エミュレーターやPC上のブラウザではスリープ挙動が異なるためです。テストの手順は次のとおりです。

  1. スマホのスリープ時間を最短(15〜30秒程度)に設定する
  2. ゲームを起動してスタートボタンを押す
  3. 何も操作せず1〜2分待ち、画面が暗くならないことを確認する
  4. ホームボタンを押して他のアプリを開き、数十秒後にゲームに戻る
  5. 再びしばらく待ち、復帰後も画面が維持されることを確認する

テスト後はスマホのスリープ設定を元に戻すことを忘れないでください。

次の行動

まずはゲームのスタート処理に requestWakeLock() を追加し、実機で画面が暗くならないことを確認してください。visibilitychange での再取得もセットで実装しておくと、バックグラウンドからの復帰後も安定します。完成したゲームはアソバースにZIPまたはHTMLファイルとして投稿して公開できます。

参考資料

  • MDN Web Docs「Screen Wake Lock API」
  • W3C Screen Wake Lock API 仕様書
  • Can I use「Screen Wake Lock API」