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

如何用Vue 2.x + Vuex实现放置游戏的游戏循环?

解决Vue2+Vuex放置游戏循环频繁dispatch的性能问题

我之前在Vue2搭配Vuex做文字放置游戏时,也碰到过几乎一模一样的问题——掉帧补更时要触发几十次dispatch,不仅性能拉胯,还容易让Vue的响应式更新队列挤爆。给你几个亲测有效的解决方案:

1. 批量提交mutation,合并多次dispatch

每次dispatch本质是触发一次Vuex调度和Vue响应式更新,几十次连续调用肯定会有性能瓶颈。不如把补更的所有操作收集起来,一次性提交到Vuex处理:

// 游戏循环中先收集所有待更新操作
const batchOperations = [];
const updatePerTick = 16.67; // 60fps单帧时长(ms)
let remainingTime = deltaTime;
let updateCount = 0;

// 执行掉帧补更的计算逻辑,但不触发dispatch
while (remainingTime >= updatePerTick && updateCount < 60) {
  const resourceChanges = calculatePerTickChanges(); // 计算单帧资源变化
  batchOperations.push(resourceChanges);
  remainingTime -= updatePerTick;
  updateCount++;
}

// 单次dispatch提交批量操作
store.dispatch('batchUpdateGameState', batchOperations);

然后在Vuex里实现对应的action和mutation:

// Vuex actions
actions: {
  batchUpdateGameState({ commit }, operations) {
    commit('BATCH_UPDATE_STATE', operations);
  }
}

// Vuex mutations
mutations: {
  BATCH_UPDATE_STATE(state, operations) {
    operations.forEach(op => {
      // 统一处理所有单帧更新逻辑
      state.resources.gold += op.gold;
      state.resources.wood += op.wood;
      // 其他如任务进度、成就判定等逻辑也在这里批量处理
    });
  }
}

这种方式把几十次dispatch压缩成一次,能大幅减少Vuex调度和响应式更新的开销。

2. 把循环计算逻辑移出Vuex,只同步最终状态

掉帧补更的核心是纯计算逻辑,完全不需要每一步都走Vuex的响应式流程。可以把游戏循环的计算部分放在独立的JS模块里,计算完最终状态后再一次性同步到Vuex:

// 独立的游戏循环模块(非Vuex)
export function runGameLoop(deltaTime) {
  const timePerTick = 16.67;
  let remainingTime = deltaTime;
  let updateCount = 0;
  // 取当前状态快照,避免循环中读取响应式数据
  const currentState = { ...store.state.game };

  // 纯JS计算补更逻辑,不触发任何Vuex操作
  while (remainingTime >= timePerTick && updateCount < 60) {
    currentState.gold += currentState.goldPerTick;
    currentState.wood += currentState.woodPerTick;
    // 处理怪物刷新、任务完成判定等逻辑
    checkTaskCompletion(currentState);
    remainingTime -= timePerTick;
    updateCount++;
  }

  // 计算完成后,一次性同步到Vuex
  store.dispatch('syncGameState', currentState);
}

Vuex里只需要一个同步状态的mutation:

mutations: {
  SYNC_GAME_STATE(state, newState) {
    // 用Object.assign合并状态,保留响应式
    Object.assign(state.game, newState);
  }
}

这种方案把所有计算逻辑从Vuex的响应式流程中剥离,性能提升最明显。

3. 优化Vuex响应式范围,减少不必要监听

如果你的游戏状态里有大量中间计算数据(比如临时的怪物属性、技能冷却倒计时),可以把这些不需要实时展示的字段放在非响应式区域,避免Vue对其做监听:

// Vuex state
state: {
  // 仅保留需要页面展示的响应式状态
  displayState: { gold: 0, wood: 0, currentTask: '' },
  // 用Object.freeze标记为非响应式,存储循环计算的中间数据
  _gameCache: Object.freeze({
    goldPerTick: 0,
    monsterHp: 0,
    skillCooldowns: {}
  })
}

游戏循环中更新_gameCache不会触发响应式更新,只有当需要更新页面展示的displayState时才触发dispatch。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:11:06