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

React 3×3网格游戏玩家移动逻辑实现技术求助

解决React 3×3网格游戏局部更新问题

核心问题

你的代码没有用React状态管理网格数据,每次组件渲染都会重新调用loot.choose()生成所有格子,导致无法保留已有的战利品,也无法实现仅更新新格子的需求。

解决方案

下面是修改后的完整代码,核心是用useState存储网格状态,实现移动时的局部更新:

import { useState } from "react";
import LootTable from "./LootTable";

const loot = new LootTable();
loot.add("chest", 1);
loot.add("energy", 1);
loot.add("roll", 1);
loot.add("empty", 5);

// 生成初始3×3网格:中间为玩家,其余为随机战利品
const generateInitialGrid = () => {
  const grid = Array(9).fill(null);
  grid[4] = "player"; // 中间位置(索引4)设为玩家
  for (let i = 0; i < 9; i++) {
    if (i !== 4) grid[i] = loot.choose();
  }
  return grid;
};

// 可点击的Square组件
const Square = ({ value, onClick }) => {
  return (
    <button className="square" onClick={onClick}>
      {value}
    </button>
  );
};

const Board = () => {
  const [grid, setGrid] = useState(generateInitialGrid());
  const playerPos = grid.indexOf("player");

  // 判断两个格子是否为上下左右相邻
  const isAdjacent = (from, to) => {
    const fromRow = Math.floor(from / 3);
    const fromCol = from % 3;
    const toRow = Math.floor(to / 3);
    const toCol = to % 3;

    return (
      (Math.abs(fromRow - toRow) === 1 && fromCol === toCol) ||
      (Math.abs(fromCol - toCol) === 1 && fromRow === toRow)
    );
  };

  // 处理格子点击事件
  const handleSquareClick = (index) => {
    // 非相邻格子不响应
    if (!isAdjacent(playerPos, index)) return;

    // 复制网格数组,避免直接修改原状态
    const newGrid = [...grid];
    // 更新玩家位置到点击的格子
    newGrid[index] = "player";

    // 根据移动方向,生成新物品填充对应格子
    let newItemIndex = -1;
    switch (index - playerPos) {
      case -3: // 向上移动 → 更新原玩家位置下方的格子
        newItemIndex = playerPos + 3;
        break;
      case 3: // 向下移动 → 更新原玩家位置上方的格子
        newItemIndex = playerPos - 3;
        break;
      case -1: // 向左移动 → 更新原玩家位置右侧的格子
        newItemIndex = playerPos + 1;
        break;
      case 1: // 向右移动 → 更新原玩家位置左侧的格子
        newItemIndex = playerPos - 1;
        break;
    }

    // 生成新物品并更新对应格子
    if (newItemIndex >= 0 && newItemIndex < 9) {
      newGrid[newItemIndex] = loot.choose();
    }

    // 更新网格状态
    setGrid(newGrid);
  };

  const renderSquare = (index) => {
    return (
      <Square
        value={grid[index]}
        onClick={() => handleSquareClick(index)}
      />
    );
  };

  return (
    <div>
      <div className="board-row">
        {renderSquare(0)}
        {renderSquare(1)}
        {renderSquare(2)}
      </div>
      <div className="board-row">
        {renderSquare(3)}
        {renderSquare(4)}
        {renderSquare(5)}
      </div>
      <div className="board-row">
        {renderSquare(6)}
        {renderSquare(7)}
        {renderSquare(8)}
      </div>
    </div>
  );
};

export default Board;

关键改进点

  • 状态持久化:用useState存储网格数组,所有战利品状态会被保留,不会随组件渲染丢失。
  • 局部更新:移动时仅修改玩家位置和对应方向的新格子,其余已生成的战利品完全保留。
  • 移动规则约束:通过行列坐标计算,确保玩家只能移动到上下左右相邻的格子。
  • 不可变更新:通过复制数组[...grid]修改状态,符合React的不可变数据原则,避免意外的状态突变。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 17:45:41