如何在组件中处理两个不同的回调函数,一个更新状态,另一个调用使用该状态的函数?

问题描述 投票:0回答:1

我正在开发一款游戏,需要检查两个对象(“敌人”和玩家)的碰撞。每次敌人移动时,它都会运行一个回调函数,将其当前位置传递给 handleCollision 函数。

此handleCollision函数使用返回的敌人位置和当前玩家位置(存储在状态中)来检查是否发生了碰撞。

问题是,即使玩家回调将playerPosition状态设置为当前位置,当敌人调用handleCollision函数时,(0,0)值会作为玩家的位置传递。

代码示例如下:

游戏状态.tsx

export default function GameState() {
  const [score, setScore] = useState(0);

  const [enemies, setEnemies] = useState<Array<React.ReactNode>>([]);

  const [playerPosition, setPlayerPosition] = useState<Position>({
    xpos: 0,
    ypos: 0,
  });

  useEffect(() => {
    setEnemies(createEnemies(1));
  }, []);

  function handleCollision(otherObject: Position) {

    if (checkCollision(playerPosition, otherObject)) {
      setScore((prevScore) => prevScore + 1);
    }
  }

  function createEnemies(numEnemies: number) {
    let enemies = [];
    for (let i = 0; i < numEnemies; i++) {
      enemies.push(
        <Enemies
          key={i}
          onPositionChange={(position: Position) => {
            handleCollision(position);
          }}
        />
      );
    }
    return enemies;
  }

  return (
    // Need to pass the score as a prop to the canvas element
    <Canvas>
      <ThePlayer
        onPositionChange={(position: Position) => {
          setPlayerPosition(position);
        }}
      />
      {enemies}
    </Canvas>
  );
}

Emenies.tsx

export default function Enemies({ onPositionChange }) {
  const enemy = useRef(new Enemy());

  const [enemyPosition, setEnemyPosition]: Position = useState();

  useEffect(() => {
    setInterval(() => {
      enemy.current.move();
      const newPosition = enemy.current.getPos();
      setEnemyPosition(enemy.current.getPos());
      onPositionChange(newPosition);
    }, Math.floor(Math.random() * 500)) + 200;
  }, []);

  return (
    <div
      className="enemy"
      style={{
        top: `${enemy.current.posy}px`,
        left: `${enemy.current.posx}px`,
        transform: `rotate(${enemy.current.direction}deg)`,
      }}
    ></div>
  );
}

玩家.tsx

export default function ThePlayer({ onPositionChange }) {
  const player = new Player();

  const [xpos, setXpos] = useState(player.getPos().posx);
  const [ypos, setYpos] = useState(player.getPos().posy);

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => move(e);
    onPositionChange({ xpos, ypos }); // Initialize position
    window.addEventListener("keydown", handleKeyDown);
    return () => {
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [ypos, xpos]);

  function move(e: KeyboardEvent) {
    e.preventDefault();
    let newPosX = xpos;
    let newPosY = ypos;
    switch (e.key) {
      case "ArrowUp":
        if (ypos - player.speed <= 0) {
          newPosY = window.innerHeight - 20;
        } else {
          newPosY -= player.speed;
        }
        break;

      case "ArrowDown":
        if (ypos + player.speed >= window.innerHeight) {
          newPosY = 0;
        } else {
          newPosY += player.speed;
        }
        break;

      case "ArrowLeft":
        if (xpos - player.speed <= 0) {
          newPosX = window.innerWidth - 20;
        } else {
          newPosX -= player.speed;
        }
        break;

      case "ArrowRight":
        if (xpos + player.speed >= window.innerWidth) {
          newPosX = 0;
        } else {
          newPosX += player.speed;
        }
        break;

      case " ":
        //Handle spacebar logic
        console.log("Spacebar Pressed!");
        break;

      default:
        console.log("Not a valid action key!");
    }
    // console.log("Player Position Updated:", { xpos: newPosX, ypos: newPosY });
    setXpos(newPosX);
    setYpos(newPosY);
  }

  return (
    <div
      className="player"
      style={{ top: `${ypos}px`, left: `${xpos}px` }}
    ></div>
  );
}

我已经尝试在不同的组件中进行控制台日志记录,似乎播放器组件实际上将正确的位置传递给回调函数。敌人的位置也是如此。

我认为问题存在于 GameState.tsx 文件中的某个位置,因为playerPosition的初始状态保持在(0,0),随后这是在handleCollison函数中调用checkCollision函数时传递的值。

如果我更改playerPosition状态的初始值,这些值也会被传递。

javascript reactjs typescript components react-state
1个回答
0
投票

您在 ThePlayer 组件中声明了一些状态:

export default function ThePlayer({ onPositionChange }) {
  const player = new Player();

  const [xpos, setXpos] = useState(player.getPos().posx);
  const [ypos, setYpos] = useState(player.getPos().posy);

好的。

您在 ThePlayer 组件中更新该状态:

setXpos(newPosX);
setYpos(newPosY);

好的。

您的 useEffect 运行取决于该组件中的 xposypos

  useEffect(() => {
    ...
  }, [ypos, xpos]);

好。

现在。是什么改变了 xpos 和/或 ypos 状态,以便 useEffect 回调运行?啊?

这个应该改变它们,对吧?

const handleKeyDown = (e: KeyboardEvent) => move(e);
...
window.addEventListener("keydown", handleKeyDown);

但它在 useEffect 回调内部。

因此,要运行 useEffect 回调,您必须更改 xpos 和/或 ypos 状态。但是要更改 xpos 和/或 ypos 状态,您必须使 useEffect 回调运行。

© www.soinside.com 2019 - 2024. All rights reserved.