为什么 OnKeydown 和 OnClick 在我的代码中工作方式不同?

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

我正在创建一款恐龙游戏,其中通过单击(任意位置)或按空格键来触发跳跃。 我添加了最后一个阶段 (4),其中相同的按键仍会触发相同的功能

jump()
,但随后
jump()
将在第 4 阶段执行不同的操作(会有类似击中 Boss 之类的内容)。

当我使用点击时,我的代码按预期工作,但是当我使用空格时,在最后的第 4 阶段,

jump()
未按预期执行:它确实更新
isJumping
我看到我放置的动画,但它没有不更新其他状态变量:
craMessage
craLife

为什么在这种情况下

Onclick
Onkeypress
的功能不一样?我的代码做错了什么?

提前谢谢您。

// src/App.js
import React, { useState, useEffect } from "react";
import Dino from "./components/Dino";
import Obstacle from "./components/Obstacle";
import Ground from "./components/Ground";

const App = () => {
  const [isJumping, setIsJumping] = useState(false);
  const [obstaclePosition, setObstaclePosition] = useState(1000);
  const [score, setScore] = useState(0);
  const [scoreMessage, setScoreMessage] = useState("");
  const [phase, setPhase] = useState(1);
  const [lastPhase, setLastPhase] = useState(1);
  const [craLife, setCraLife] = useState(1000);
  const [craMessage, setCraMessage] = useState("");
  const [gameOver, setGameOver] = useState(false);

  // Handle jump (both keyboard and mouse)
  const jump = () => {
    if (!isJumping) {
      setIsJumping(true);
      setTimeout(() => setIsJumping(false), 500); // Dino stays in the air for 300ms
      if (phase === 4) {
        //used same variable isJumping for hitting logic
        let hit = Math.floor(Math.random() * 150 + 200); //Boss in phase 4 will be hit between 200 and 350
        setCraMessage(`-${hit}`);
        setCraLife(craLife - hit);
        setTimeout(() => setCraMessage(""), 1000);
      }
    }
  };

  // Function to handle phase changes and difficulty scaling
  const adjustPhase = (score) => {
    if (score >= 10) {
      if (lastPhase !== 4) {
        // Show message only if phase changes
        setPhase(4); // Phase 4: New game components
        setScoreMessage("Phase 4: New Challenges!"); // Show message for Phase 4
        setTimeout(() => setScoreMessage(""), 1000); // Remove message after 1 second
        setLastPhase(4); // Update lastPhase
      }
    } else if (score >= 4) {
      if (lastPhase !== 3) {
        // Show message only if phase changes
        setPhase(3); // Phase 3: Increase speed & randomize obstacle interval
        setScoreMessage("Phase 3: Speeding Up & More Obstacles!"); // Show message for Phase 3
        setTimeout(() => setScoreMessage(""), 1000); // Remove message after 1 second
        setLastPhase(3); // Update lastPhase
      }
    } else if (score >= 2) {
      if (lastPhase !== 2) {
        // Show message only if phase changes
        setPhase(2); // Phase 2: Increase speed
        setScoreMessage("Phase 2: Speed Boost!"); // Show message for Phase 2
        setTimeout(() => setScoreMessage(""), 1000); // Remove message after 1 second
        setLastPhase(2); // Update lastPhase
      }
    } else {
      if (lastPhase !== 1) {
        // Show message only if phase changes
        setPhase(1); // Phase 1: Initial state
        setScoreMessage("Phase 1: Get Ready!"); // Show message for Phase 1
        setTimeout(() => setScoreMessage(""), 1000); // Remove message after 1 second
        setLastPhase(1); // Update lastPhase
      }
    }
  };

  // Move obstacle with changing intervals based on phase
  useEffect(() => {
    if (gameOver || phase === 4) return;

    const baseInterval = 50; // Base interval (500ms for phase 1)
    const speedIncreasePerPhase = 10; // Increase speed per phase (reduce interval by 100ms)
    let interval = baseInterval - (phase - 1) * speedIncreasePerPhase; // Decrease interval as phase increases

    const updateObstaclePosition = () => {
      setObstaclePosition((prev) => {
        if (prev <= -50) {
          setScore((prevScore) => prevScore + 1);
          if (phase === 3) {
            return Math.random() * 500 + 500; // Randomize position between 800 and 1500
          }
          // In other phases, keep the position fixed
          return 1000;
        }
        return prev - 10;
      });
    };

    const intervalId = setInterval(updateObstaclePosition, interval);

    return () => clearInterval(intervalId);
  }, [gameOver, phase]);

  useEffect(() => {
    if (gameOver || phase !== 4 || craLife <= 0) return;
    setScore((prevScore) => prevScore + 10);
  }, [gameOver, phase, craLife]);

  useEffect(() => {
    adjustPhase(score); // Update phase based on score
  }, [score]);

  useEffect(() => {
    // Ensure craLife doesn't go below 0
    if (craLife <= 0) {
      setCraLife(0); // Stop craLife from going negative
      setScoreMessage("You win!");
      setTimeout(() => setGameOver(true), 1000);
      return;
    }

    if (obstaclePosition < 60 && obstaclePosition > 10 && !isJumping) {
      if (phase === 4) {
        if (craLife <= 0) {
          setScoreMessage("You win!"); // If craLife is 0 or less, show win message
          setGameOver(true); // End the game
          return;
        }
      }
      setGameOver(true); // Game ends in other phases regardless of craLife
    }
  }, [obstaclePosition, isJumping, phase, craLife]);

  useEffect(() => {
    const handleKeyDown = (e) => {
      console.log("Keydown triggered:", e.key);
      if (e.key === " ") {
        jump();
      }
    };
    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, []);

  return (
    <div
      style={{
        position: "relative",
        height: "300px",
        width: "100%",
        overflow: "hidden",
        background: "#ddd",
      }}
      onClick={jump} // Allow mouse clicks to trigger jumping
    >
      {gameOver ? (
        <h1 style={{ textAlign: "center" }}>Game Over! Score: {score}</h1>
      ) : (
        <>
          <Dino phase={phase} isJumping={isJumping} />
          <Obstacle
            phase={phase}
            position={obstaclePosition}
            isLifted={isJumping}
          />
          <Ground />
          <div style={{ position: "absolute", top: "10px", left: "10px" }}>
            Score: {score}
          </div>
          <div> Message: {scoreMessage} </div>

          {phase === 4 && (
            <>
              <div> Cra Life: {craLife} </div>
              <div
                style={{
                  position: "absolute",
                  top: "50px",
                  right: "80px",
                  color: "red",
                }}
              >
                {craMessage}
              </div>
            </>
          )}
        </>
      )}
    </div>
  );
};

export default App;
javascript reactjs
1个回答
0
投票

在 keydown 中添加依赖项

useEffect(() => {
  const handleKeyDown = (e) => {
    if (e.key === " ") {
      jump();
    }
  };
  window.addEventListener("keydown", handleKeyDown);
  return () => window.removeEventListener("keydown", handleKeyDown);
}, [jump, isJumping, phase, craLife]); // Add dependencies

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