我正在开发一款游戏,需要检查两个对象(“敌人”和玩家)的碰撞。每次敌人移动时,它都会运行一个回调函数,将其当前位置传递给 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状态的初始值,这些值也会被传递。
您在 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 运行取决于该组件中的 xpos 和 ypos:
useEffect(() => {
...
}, [ypos, xpos]);
好。
现在。是什么改变了 xpos 和/或 ypos 状态,以便 useEffect 回调运行?啊?
这个应该改变它们,对吧?
const handleKeyDown = (e: KeyboardEvent) => move(e);
...
window.addEventListener("keydown", handleKeyDown);
但它在 useEffect 回调内部。
因此,要运行 useEffect 回调,您必须更改 xpos 和/或 ypos 状态。但是要更改 xpos 和/或 ypos 状态,您必须使 useEffect 回调运行。