質問するログイン新規登録

Q&A

解決済

2回答

521閲覧

JavaScript:localStorageの内容が正しく更新されない

numin

総合スコア41

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2025/05/28 00:50

0

1

実現したいこと

localStorageに保存された内容をゲームの勝敗に応じて正しく更新させたい

前提

自作のブラウザゲームにて、JavaScriptのlocalStorageを用いて下記のように連勝数を記録・表示する仕組みを実装したいと考えています。

  • ページ読み込み時・難易度変更時: 難易度に応じた連勝数を表示
  • 勝利時: 数値化した連勝数に1を足して更新・表示
  • 引き分け時: 連勝数を変更せずに表示
  • 敗北時: 連勝数を0にリセットし表示

発生している問題・エラーメッセージ

連続して勝った際に連勝数が1増える仕組みには問題ないものの、1度敗北して連勝数が0にリセットされた後に同じ難易度で挑戦し勝利した場合、何故か以前の連勝数が戻ってしまいます。

※例: 10連勝↠負けて0連勝↠勝って10連勝に戻る

なおコンソール上エラーは起きていないように見受けられます。

該当のソースコード

JavaScript

1document.addEventListener("DOMContentLoaded", () => { 2 // ゲーム本体に関わる変数定義(省略) 3 const highscore = document.getElementById('highscore'); // 連勝数表示領域 4 // ゲーム初期設定(省略) 5 6 // ページ読み込み時に難易度をEasyに設定、連勝数保存状況を確認して表示 7 let difficulty = "easy"; 8 if(localStorage.getItem('cdoEasy')) { 9 highscore.textContent = localStorage.getItem('cdoEasy'); 10 } else { 11 localStorage.setItem('cdoEasy', '0'); 12 highscore.textContent = '0'; 13 } 14 15 // ゲーム初期化(大部分省略) 16startGameButton.addEventListener("click", () => { 17 // ... 18 // 盤面生成・ゲーム終了確認 19 function renderBoard() { 20 // ... 21 if (currentPlayer === playerPiece) { 22 const playerMoves = getValidMoves(playerPiece); 23 if (playerMoves.length === 0) { 24 // プレイヤーの取れる手がない場合 25 alert("あなたの置ける場所がありません。敵のターンです。"); 26 currentPlayer = opponentPiece; 27 28 // 敵の取れる手があるか確認 29 if (getValidMoves(opponentPiece).length === 0) { 30 checkEndGame(); // 両社共に取れる手がない場合、ゲーム終了 31 } else { 32 setTimeout(() => handleOpponentMove(), 500); 33 } 34 } 35 } 36 } 37// ゲーム本体のコード(省略 38 39// ゲーム終了時、勝敗判定及び連勝数記録 40function checkEndGame() { 41 const playerValidMoves = getValidMoves(playerPiece); 42 const opponentValidMoves = getValidMoves(opponentPiece); 43 44 if (playerValidMoves.length === 0 && opponentValidMoves.length === 0) { 45 if (!gameOver) { 46 gameOver = true; 47 48 // 集計 49 const playerCount = board.flat().filter(piece => piece === playerPiece).length; 50 const opponentCount = board.flat().filter(piece => piece === opponentPiece).length; 51 52 document.getElementById('controls-section').classList.remove('hidden'); 53 // 勝利時 54 if (playerCount > opponentCount) { 55 playWin(); // 効果音再生(別ファイルにて定義) 56 setTimeout(function(){ 57 alert(`ゲーム終了\nおめでとうございます! あなたの勝利です。 ${playerPiece}\n${playerPiece}: ${playerCount}/${opponentPiece}: ${opponentCount}`); 58 }, 4000); 59 // 難易度によって連勝数を更新 60 if(difficulty == 'easy') { 61 let cdoCur = Number(localStorage.getItem('cdoEasy')) + 1; 62 localStorage.setItem('cdoEasy', String(cdoCur)); 63 highscore.textContent = localStorage.getItem('cdoEasy'); 64 } else if(difficulty == 'medium') { 65 let cdoCur = Number(localStorage.getItem('cdoMedium')) + 1; 66 localStorage.setItem('cdoMedium', String(cdoCur)); 67 highscore.textContent = localStorage.getItem('cdoMedium'); 68 } else { 69 let cdoCur = Number(localStorage.getItem('cdoMedium')) + 1; 70 localStorage.setItem('cdoHard', String(cdoCur)); 71 highscore.textContent = localStorage.getItem('cdoHard'); 72 } 73 } else if (opponentCount > playerCount) { 74 // 敗北時 75 playLose(); // 効果音再生(別ファイルにて定義) 76 setTimeout(function(){ 77 alert(`ゲーム終了\n残念、あなたの負けです... ${opponentPiece}\n${playerPiece}: ${playerCount}/${opponentPiece}: ${opponentCount}`); 78 }, 6500); 79 // 難易度によって連勝数を更新 80 if(difficulty == 'easy') { 81 localStorage.removeItem('cdoEasy'); // 備考あり 82 localStorage.setItem('cdoEasy', '0'); 83 highscore.textContent = localStorage.getItem('cdoEasy'); 84 } else if(difficulty == 'medium') { 85 localStorage.removeItem('cdoMedium'); // 備考あり 86 localStorage.setItem('cdoMedium', '0'); 87 highscore.textContent = localStorage.getItem('cdoMedium'); 88 } else if(difficulty == 'hard') { 89 localStorage.removeItem('cdoHard'); // 備考あり 90 localStorage.setItem('cdoHard', '0'); 91 highscore.textContent = localStorage.getItem('cdoHard'); 92 } 93 } else { 94 // 引き分け時 95 playDraw(); // 効果音再生(別ファイルにて定義) 96 setTimeout(function(){ 97 alert(`ゲーム終了\n結果は引き分けです。\n${playerPiece}: ${playerCount}/${opponentPiece}: ${opponentCount}`); 98 }, 4000); 99 if(difficulty == 'easy') { 100 highscore.textContent = localStorage.getItem('cdoEasy'); 101 } else if(difficulty == 'medium') { 102 highscore.textContent = localStorage.getItem('cdoMedium'); 103 } else if(difficulty == 'hard') { 104 highscore.textContent = localStorage.getItem('cdoHard'); 105 } 106 } 107 } 108 } 109} 110}); 111 112// 難易度変更時に連勝数表示を更新 113document.getElementById("difficulty-choice").addEventListener('change', function() { 114 let difficulty = document.getElementById("difficulty-choice").value; 115 let highscore = document.getElementById('highscore'); 116 if(difficulty == 'easy') { 117 if(localStorage.getItem('cdoEasy')) { 118 highscore.textContent = localStorage.getItem('cdoEasy'); 119 } else { 120 localStorage.setItem('cdoEasy', '0'); 121 highscore.textContent = '0'; 122 } 123 } else if(difficulty == 'medium') { 124 if(localStorage.getItem('cdoMedium')) { 125 highscore.textContent = localStorage.getItem('cdoMedium'); 126 } else { 127 localStorage.setItem('cdoMedium', '0'); 128 highscore.textContent = '0'; 129 } 130 } else if(difficulty == 'hard') { 131 if(localStorage.getItem('cdoHard')) { 132 highscore.textContent = localStorage.getItem('cdoHard'); 133 } else { 134 localStorage.setItem('cdoHard', '0'); 135 highscore.textContent = '0'; 136 } 137 } 138});

試したこと

上記ソースコード内、「備考あり」と記載がある箇所に一度localStorageを削除する処理を追記しました。

ただこちらの対応をして以来、今度は

  • 敗北し連勝数をリセット
  • 勝利して以前の連勝数が戻る
  • その後勝利しても連勝数が変わらない

と状況が悪化してしまいました。


こちらの問題の解決方法をご存じの方がいましたら、ご教示いただけますと幸いです。

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

maisumakun

2025/05/28 00:55

localStorageの中身も要所要所で出力させて、中身を確認しながらのデバッグ…などは行ってみましたか?
yambejp

2025/05/28 01:11

とりあえず動作する状態で提示するか、動作するサイトにアップしてください
numin

2025/05/28 01:54

>yambejpさん コメント・回答を頂きありがとうございます。 まず「動作するウェブサイト」について、上記を反映済のサイトがあるのですが、こちらに外部サイトのURLを掲載することは規約・マナー上問題ないでしょうか。 また記録と現在の連勝数についてですが、該当ページでは「連勝記録」は保持せず、「現在の連勝数」のみを更新・表示したいと考えています。
numin

2025/05/28 01:55

>maisumakunさん ありがとうございます。現在ゲーム終了時にlocalStorageが出力されるよう調整・検証してみています。
Lhankor_Mhy

2025/05/28 02:12

ご提示のコードを試してみましたが、特に問題は起きませんでした。 ここに書かれていない、numinさんが問題に関係がないと思って省略している部分に原因があるかもしれませんので、現状のコードのコピーを作って、問題に関係がないと思っている部分を少しずつ削除して検証してみると原因の部分が見つかるかもしれません。
yambejp

2025/05/29 03:33

>外部サイトのURLを掲載することは規約・マナー上問題ない 広告があるようなサイトだと誘導とみなされる可能性はありますね codepenのようなソースサンプルサイトなら大丈夫ですよ 参考までにサンプルデータ回答につけておきました
guest

回答2

0

自己解決

たくさんのコメント・回答を頂いていたにも関わらず、自己解決の形にしてしまって申し訳ありません。

厳密には「解決」した分けではないのですが、最初にアップしたコード・回答欄で頂いたコード共に、PC版Chrome・Edgeでは正しく動作することが検証を通じてわかりました。

どうやら本問題はiOS版Safari及びiOS用に作成したWebViewアプリでのみ発生していたようです。

この原因についてはまだわかりませんが、少し検証を重ねてみたいと思います。

ご助言・ご協力いただきありがとうございました。

投稿2025/05/29 06:19

numin

総合スコア41

yambejp

2025/05/29 09:16

とりあえず「解決済み」にしておいてください
yambejp

2025/06/02 04:20

ちなみにtimeout処理をするのは違うと思います・・・
guest

0

localStorageに連勝記録を保持するとして、現在の連勝数は別途localStorageなりグローバル変数などで管理しないと、常に連勝記録をいじってしまう設定になっていませんか?

参考

特に反応がないようなのでサンプル

html

1<script> 2const points=JSON.parse(localStorage.getItem('points')??`{"easy":0,"meduim":0,"hard":0}`); 3window.addEventListener('DOMContentLoaded', ()=>{ 4 easy.textContent=points.easy; 5 meduim.textContent=points.meduim; 6 hard.textContent=points.hard; 7 level.addEventListener('change',()=>{ 8 consect.textContent="0"; 9 }); 10}); 11document.addEventListener('click',e=>{ 12 const t=e.target; 13 let c=parseInt(consect.textContent); 14 if(t.matches('#win')){ 15 c++; 16 } 17 if(t.matches('#lose')){ 18 c=0; 19 } 20 if(points[level.value]<c){ 21 points[level.value]=c; 22 document.querySelector(`#${level.value}`).textContent=c; 23 localStorage.setItem('points',JSON.stringify(points)); 24 } 25 consect.textContent=c; 26}); 27</script> 28<nav> 29<dl> 30<dt>Easy</dt> 31<dd id="easy">0</dd> 32<dt>Medim</dt> 33<dd id="meduim">0</dd> 34<dt>Hard</dt> 35<dd id="hard">0</dd> 36</dl> 37</nav> 38<select id="level"> 39<option value="easy">Easy</option> 40<option value="meduim">Medium</option> 41<option value="hard">Hard</option> 42</select> 43<input type="button" id="win" value="win"> 44<input type="button" id="draw" value="draw"> 45<input type="button" id="lose" value="lose"> 46<dl> 47<dt>consecut</dt> 48<dd id="consect">0</dd> 49</dl>

投稿2025/05/28 01:15

編集2025/05/29 03:30
yambejp

総合スコア118405

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.29%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問