You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS游戏开发:LocalStorage数据不持久及push函数报错求助

LocalStorage数据丢失及objectForMonsterMarkers.push报错修复

问题1:页面刷新后LocalStorage数据无法保存显示

原因

  1. 初始化条件逻辑错误:原代码if (playerCharachteristics || monsterCharachteritics === null)的判断逻辑完全错误——只要playerCharachteristics存在(非null),不管怪物数据是否缺失,都会重新生成玩家和怪物数据,直接覆盖本地存储的值。
  2. 无效的分支判断:后续的else if与前面的if条件完全重复,永远不会触发,导致读取本地存储后无法调用generateMonster渲染怪物。
  3. 存储DOM元素到LocalStorage:代码中将playerCharachteristics.pHealthBar、monsterCharachteritics.mHealthBar等DOM对象存入LocalStorage,这类对象无法被JSON正确序列化,直接导致存储和读取失败。

修复方案

  • 修正初始化条件:改为任一数据不存在时才初始化,即if (!playerCharachteristics || !monsterCharachteritics)。
  • 删除重复的else if分支,在数据存在时直接调用generateMonster渲染内容。
  • 分离数据与DOM引用:只存储数值、布尔值等可序列化的数据,DOM元素在页面加载后重新获取,不存入LocalStorage。

问题2:objectForMonsterMarkers.push不是函数报错

原因

objectForMonsterMarkers初始化为数组,但在monsterHit函数中,将布尔值booleanGameMechanics存入了monsterBooleanImage对应的LocalStorage键中。下次页面加载时,objectForMonsterMarkers会被解析为布尔值而非数组,调用push方法自然报错。

修复方案

  • 拆分存储键:用单独的键存储objectForMonsterMarkers数组(比如monsterMarkers),怪物的布尔状态用另一个键(比如monsterActiveStatus)存储,避免类型混淆。
  • 确保数组类型安全:读取objectForMonsterMarkers时直接做兜底初始化,保证其始终为数组。

修改后的完整代码

// 初始化本地存储数据
let playerCharachteristics = JSON.parse(localStorage.getItem('playerCharachteristics'));
let monsterCharachteritics = JSON.parse(localStorage.getItem('monsterCharachteritics'));
let objectForMonsterMarkers = JSON.parse(localStorage.getItem('monsterMarkers')) || [];
let monsterActiveStatus = JSON.parse(localStorage.getItem('monsterActiveStatus'));

// 初始化玩家和怪物数据(任一不存在时)
if (!playerCharachteristics || !monsterCharachteritics) {
  playerCharachteristics = {
    pStrength: parseInt(Math.random() * 80), // 攻击点数,在monsterHit中会增加
    pStrengthBar: parseInt(Math.random() * 80),
    pDefence: parseInt(Math.random() * 70),
    pDefenceBar: parseInt(Math.random() * 80),
    pHealth: parseInt(Math.random() * 100),
    pHealthBarWidth: 100 // 存储宽度数值,而非DOM元素
  };

  monsterCharachteritics = {
    mStrength: 40,
    mStrengthBarWidth: 40, // 存储宽度数值
    mDefence: parseInt(Math.random() * 80),
    mDefenceBar: parseInt(Math.random() * 80),
    mHealth: parseInt(Math.random() * 110),
    mHealthBarWidth: parseInt(Math.random() * 80) // 存储宽度数值
  };
  // 首次初始化时设置怪物状态为活跃
  monsterActiveStatus = true;
}

// 读取到数据后渲染怪物
generateMonster(monsterActiveStatus);

function generateMonster(monsterBooleanImage) {
  if (!monsterBooleanImage) return;

  let monsterHealthAdditionalHealthPoints = 800;
  monsterCharachteritics.mHealth += monsterHealthAdditionalHealthPoints;
  monsterCharachteritics.mStrength = 35; // 基础怪物攻击力

  // 渲染DOM元素
  divImage.innerHTML += `
    <img alt="" class="first" fetchpriority="auto" loading="auto"
         src="https://i.pinimg.com/564x/85/c8/f3/85c8f3eca9a5cbdef756956ba16b89dd.jpg" 
         id="gameCanvas" width="270" height="330" >
  `;
  monsterHealthDiv.innerHTML += `
    <div id="monsterhealthbar"> 
      <div class="monsterhealthfill" > 
        <i class="hp3"> Monster Health Points -${monsterCharachteritics.mHealth}</i>
      </div>
    </div> 
    <div id="monsterstrengthbar"> 
      <div class="monsterstrengthfill" > 
        <i class="hp3"> Monster Strength Points -${monsterCharachteritics.mStrength}</i>
      </div>
    </div> 
  `;

  // 获取DOM元素(仅在当前页面使用,不存入LocalStorage)
  const monsterSDFbarFills = {
    mhFill: document.querySelector(".monsterhealthfill"),
    msFill: document.querySelector(".monsterstrengthfill")
  };
  const monsterHealthBar = document.querySelector("#monsterhealthbar");
  const monsterStrengthBar = document.querySelector("#monsterstrengthbar");

  // 设置进度条宽度
  monsterHealthBar.style.width = monsterCharachteritics.mHealthBarWidth + 'px';
  monsterStrengthBar.style.width = monsterCharachteritics.mStrengthBarWidth + 'px';

  checker2++;
  if (checker2 === 1) {
    divThrowButon.innerHTML = `
      <button onclick="throwForStrengthHealth()"> Throw For Health and Base Strength</button> 
    `;
  }

  attackDiv.innerHTML = `
    <button class="button" onclick="monsterHit(${monsterBooleanImage})">Attack</button>
  `;

  // 存储数据到LocalStorage(仅存数值/布尔/数组,不存DOM)
  localStorage.setItem('monsterActiveStatus', JSON.stringify(monsterBooleanImage));
  localStorage.setItem('playerCharachteristics', JSON.stringify(playerCharachteristics));
  localStorage.setItem('monsterCharachteritics', JSON.stringify(monsterCharachteritics));
  localStorage.setItem('monsterMarkers', JSON.stringify(objectForMonsterMarkers));
}

function monsterHit(booleanGameMechanics) {
  if (!booleanGameMechanics) return;

  let playerThrowAdditionalAttackPoints = parseInt(Math.random() * 80);
  let overallPlayerDamage = playerCharachteristics.pStrength + playerThrowAdditionalAttackPoints;
  let monsterThrowAdditionalAttackPoints = parseInt(Math.random() * 90);
  let overallMonsterDamage = monsterThrowAdditionalAttackPoints + monsterCharachteritics.mStrength;

  if (overallMonsterDamage > overallPlayerDamage) {
    attackExchangeCounter++
  }
  if (attackExchangeCounter >= 3) {
    attackDiv.innerHTML = `
      <button onclick="secondAttack(${overallMonsterDamage},${booleanGameMechanics})"> Second Attack</button>
      <button onclick="lowerYourAttackPoints(${booleanGameMechanics})"> Lower your attack points</button>
    `;
    attackExchangeCounter = 0;
  }

  // 更新数值
  playerCharachteristics.pHealth -= overallMonsterDamage;
  monsterCharachteritics.mHealth -= overallPlayerDamage;

  // 更新玩家生命值宽度
  if (overallMonsterDamage > 100) {
    playerCharachteristics.pHealthBarWidth -= 100;
  } else if (overallMonsterDamage > 50) {
    playerCharachteristics.pHealthBarWidth -= 50;
  } else {
    playerCharachteristics.pHealthBarWidth -= 20;
  }

  // 获取DOM元素
  const playerHealthBar = document.querySelector("#playerhealthbar");
  const monsterHealthBar = document.querySelector("#monsterhealthbar");
  const monsterStrengthBar = document.querySelector("#monsterstrengthbar");
  const streDefeHealthBarFills = {
    hFill: document.querySelector(".playerhealthfill")
  };
  const monsterSDFbarFills = {
    mhFill: document.querySelector(".monsterhealthfill"),
    msFill: document.querySelector(".monsterstrengthfill")
  };

  // 更新DOM显示
  playerHealthBar.style.width = playerCharachteristics.pHealthBarWidth + "px";
  monsterHealthBar.style.width = monsterCharachteritics.mHealth + "px";
  monsterStrengthBar.style.width = monsterCharachteritics.mStrength * 10 + "px";

  monsterSDFbarFills.mhFill.innerHTML = `
    <i class="hp3"> Monster Health Points -${monsterCharachteritics.mHealth}</i>
  `;
  monsterSDFbarFills.msFill.innerHTML = `
    <i class="hp3"> Monster Strength Points -${monsterCharachteritics.mStrength}</i>
  `;
  streDefeHealthBarFills.hFill.innerHTML = `
    <i class="i">Health Points -${playerCharachteristics.pHealth}</i>
  `;
  riddleContainer.innerHTML = `
    <i class="hp3"> You dealt ${overallPlayerDamage} health points worth of damage to your opponent!</i>
    <i class="hp3"> You received an overall damage of ${overallMonsterDamage} health points by your opponent!</i>
  `;

  // 怪物死亡逻辑
  if (monsterCharachteritics.mHealth < 0) {
    playerCharachteristics.pHealth += 300;
    playerCharachteristics.pHealthBarWidth = 1450; // 重置宽度
    playerHealthBar.style.width = playerCharachteristics.pHealthBarWidth + "px";

    moveButton.innerHTML += `
      <button class="Move" onclick="move()"> Throw Dice To Move</button>
    `;
    divImage.innerHTML = "";
    monsterHealthDiv.innerHTML = "";
    attackDiv.innerHTML = "";
    riddleContainer.innerHTML = "";
    streDefeHealthBarFills.hFill.innerHTML = `
      <i class="i">Health Points -${playerCharachteristics.pHealth}</i>
    `;
    monsterActiveStatus = false; // 设置怪物状态为非活跃
  }

  // 玩家死亡逻辑
  if (playerCharachteristics.pHealth < 0) {
    mainContainer.style.backgroundColor = "red";
    mainContainer.innerHTML = `
      <i class="hp6"> GAME OVER! YOU DIED!</i>
    `;
  }

  // 存储更新后的数据
  localStorage.setItem('playerCharachteristics', JSON.stringify(playerCharachteristics));
  localStorage.setItem('monsterCharachteritics', JSON.stringify(monsterCharachteritics));
  localStorage.setItem('monsterActiveStatus', JSON.stringify(booleanGameMechanics));
  localStorage.setItem('monsterMarkers', JSON.stringify(objectForMonsterMarkers));
}

内容的提问来源于stack exchange,提问作者CFHVDOPFBD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:15:55