📜  使用 ReactJS 创建石头剪刀布游戏

📅  最后修改于: 2022-05-13 01:56:43.044000             🧑  作者: Mango

使用 ReactJS 创建石头剪刀布游戏

在这里,两名球员将轮流出场。从玩家一开始,然后是玩家二。有三种武器可供选择,即石头,纸,剪刀。一旦玩家二玩了他的回合结果,就会计算更新两个玩家的赢/输状态。

使用的技术/先决条件:

  1. 反应JS
  2. 用于 UI 的 Antd 库

方法:容器是有状态的 React 组件(基于类)。组件是无状态的 React 组件(基于函数)。在这个项目中,我有一个容器控制器,它负责状态管理和整个游戏逻辑。此外,还有三个组件,即:

Player ->Represent​ing a Player entity in-game;
GameControls -> For Choosing stone, paper, or scissor; 
DecisionBox -> Displays win/loose status for players;

单击控制器中的武器按钮状态会为相应的玩家更新。当第二个玩家的武器更新时,结果处理函数会计算结果处理函数,该函数涵盖石头、纸、剪刀的所有九种组合,一次取两个。

项目结构:

脚步 :

  1. 使用 create-react-app 命令设置 React 项目: create-react-app <> –scripts-version 1.1.5。除了要在 src 文件夹中手动创建的组件和容器文件夹外,将使用上述命令生成项目结构。
  2. 使用命令安装 antd 库: npm install antd
  3. 删除App.css中的代码。
  4. 编辑App.js 中的代码:App 组件呈现 Controller 并显示标题。
    应用程序.js
    Javascript
    import React, { Component } from "react";
    import Controller from "./containers/controller/controller";
    import { Typography } from "antd";
      
    import "antd/dist/antd.css";
      
    import "./App.css";
    const { Title } = Typography;
      
    class App extends Component {
      render() {
        return (
          
                       Stone Paper Scissor                         
        );   } }    export default App;


    Javascript
    import React, { Component } from "react";
    import { Row, Col, Divider } from "antd";
    import { Typography } from "antd";
    import axios from "axios";
    import "antd/dist/antd.css";
      
    import Player from "../../components/Player/Player";
    const { Title } = Typography;
      
    class Controller extends Component {
      state = {
        playerOne: {
          active: true,
          weapon: "",
          status: ""
        },
        playerTwo: {
          active: false,
          weapon: "",
          status: ""
        }
      };


    Javascript
    weaponUpdate = (player, weapon) => {this.setState({
    [player]: {
    ...this.state[player],
    weapon: weapon
    }
    });
    if (player == "playerTwo") {
    this.resultHandler();
    } else {
    this.toggleActive();
    }
    };


    Javascript
    toggleActive = () => {
    this.setState(prevState => {
    return {
    ...prevState,
    playerOne: {
    ...prevState.playerOne,
    active: !prevState.playerOne.active
    },
    playerTwo: {
    ...prevState.playerTwo,
    active: !prevState.playerTwo.active
    }
    };
    });
    };


    Javascript
    resultHandler = () => {
    this.setState(prevState => {
    let [s1, s2] = this.deciderHelper(
    prevState.playerOne.weapon,
    prevState.playerTwo.weapon);
    return {
    ...prevState,
    playerOne: {
    ...prevState.playerOne,
    status: s1
    },
    playerTwo: {
    ...prevState.playerTwo,
    status: s2
    }
    };
    });
    this.toggleActive();
    };


    Javascript
    deciderHelper = (p1, p2) => {
      if (p1 == "r" && p2 == "s") {
        return ["w", "l"];
      }
     
      if (p1 == "r" && p2 == "p") {
        return ["l", "w"];
      }
     
      if (p1 == "r" && p2 == "r") {
        return ["w", "w"];
      }
     
      if (p1 == "p" && p2 == "r") {
        return ["w", "l"];
      }
      if (p1 == "p" && p2 == "s") {
        return ["l", "w"];
      }
      if (p1 == "p" && p2 == "p") {
        return ["w", "w"];
      }
      if (p1 == "s" && p2 == "r") {
        return ["l", "w"];
      }
      if (p1 == "s" && p2 == "p") {
        return ["w", "l"];
      }
      if (p1 == "s" && p2 == "s") {
        return ["w", "w"];
      }
    };


    Javascript
    render() {
        return (
          
            
              Player One
               this.weaponUpdate("playerOne", weapon)}
                weapon={this.state.playerOne.weapon}
                status={this.state.playerOne.status}
              />
            
      
            
              Player Two
               this.weaponUpdate("playerTwo", weapon)}
                weapon={this.state.playerTwo.weapon}
                status={this.state.playerTwo.status}
              />
            
          
        );
      }
    }
      
    export default Controller;


    Javascript
    import React from "react";
    import GameControls from "../GameControls/GameControls";
    import DecisionBox from "../DecisionBox/DecisionBox";
      
    const Player = props => {
      let glowEffect = {};
      if (props.active) {
        glowEffect = {
          "-webkit-box-shadow": "0 0 20px blue",
          "-moz-box-shadow": "0 0 20px blue",
          "box-shadow": "0 0 20px blue"
        };
      }
      
      return (
        
                      
      ); };    export default Player;


    Javascript
    import React from "react";
    import { Card } from "antd";
    import { Button } from "antd";
      
    import "antd/dist/antd.css";
      
    const GameControls = props => {
      return (
        
          

                   

                

            {" "}                

                

                   

           
      ); };    export default GameControls;


    Javascript
    import React from "react";
    import { Card } from "antd";
    import { Typography } from "antd";
      
    const { Title } = Typography;
      
    const weaponMap = {
      s: "Scissors",
      p: "Paper",
      r: "Rock"
    };
    const statusMap = {
      w: "Win",
      l: "Loose"
    };
      
    const DecisionBox = props => {
      return (
        
          
            {weaponMap[props.weapon]}
          
          
            {statusMap[props.status]}
          
        
      );
    };
      
    export default DecisionBox;


  5. Controller.js:控制器包含一个状态,其中包括每个玩家最后使用的武器、当前的胜利/失败状态以及指示轮到哪个玩家的活动状态

    Javascript

    import React, { Component } from "react";
    import { Row, Col, Divider } from "antd";
    import { Typography } from "antd";
    import axios from "axios";
    import "antd/dist/antd.css";
      
    import Player from "../../components/Player/Player";
    const { Title } = Typography;
      
    class Controller extends Component {
      state = {
        playerOne: {
          active: true,
          weapon: "",
          status: ""
        },
        playerTwo: {
          active: false,
          weapon: "",
          status: ""
        }
      };
    

    这里的核心思想是,在点击武器按钮时,相应玩家的武器状态应该会更新,下一个玩家的回合应该到来,这是通过 toggleactive函数完成的。此外,如果第二个玩家的武器更新了,那么赢/松也应该更新,这是通过 resultHandler函数完成的。对于游戏逻辑,它拥有一堆功能:

    • WeaponUpdate:用于更新玩家在该状态下的武器。它需要两个参数,首先是 playerId,即 playerOne 或 playerTwo,因为它是一个双人游戏,第二个是玩家选择的武器。

      Javascript

      weaponUpdate = (player, weapon) => {this.setState({
      [player]: {
      ...this.state[player],
      weapon: weapon
      }
      });
      if (player == "playerTwo") {
      this.resultHandler();
      } else {
      this.toggleActive();
      }
      };
      
    • ToggleActive:用于在任一玩家选择武器后反转玩家的活跃状态。状态中的活动属性是一个布尔变量,所以我们只需要使用 NOT运算符来反转每个玩家的当前状态。

      Javascript

      toggleActive = () => {
      this.setState(prevState => {
      return {
      ...prevState,
      playerOne: {
      ...prevState.playerOne,
      active: !prevState.playerOne.active
      },
      playerTwo: {
      ...prevState.playerTwo,
      active: !prevState.playerTwo.active
      }
      };
      });
      };
      
    • ResultHandler:它包含决定哪个玩家获胜的主要游戏逻辑。它使用一个称为决策助手的辅助函数,它接受两个参数,每个参数是每个玩家的武器,并返回一个包含两个元素的数组,其中第一个元素对应于第一个玩家的赢/输状态,类似地,第二个元素对应于第二个玩家的状态。然后 resulthandler 使用 decicerhelper函数返回的值更新状态。

      Javascript

      resultHandler = () => {
      this.setState(prevState => {
      let [s1, s2] = this.deciderHelper(
      prevState.playerOne.weapon,
      prevState.playerTwo.weapon);
      return {
      ...prevState,
      playerOne: {
      ...prevState.playerOne,
      status: s1
      },
      playerTwo: {
      ...prevState.playerTwo,
      status: s2
      }
      };
      });
      this.toggleActive();
      };
      
    • DeciderHelper :它是一个辅助函数,它接受两个作为每个玩家武器的输入,并返回一个由两个元素组成的数组,每个元素分别表示玩家 1 和玩家 2 的赢/输状态。这里的“r”代表岩石,“s”代表剪刀,“p”代表纸,“w”代表胜利,“l”代表松散。在平局的情况下,将考虑所有可能的石头、石头、剪刀组合,并返回具有获胜状态的两个玩家。

      Javascript

      deciderHelper = (p1, p2) => {
        if (p1 == "r" && p2 == "s") {
          return ["w", "l"];
        }
       
        if (p1 == "r" && p2 == "p") {
          return ["l", "w"];
        }
       
        if (p1 == "r" && p2 == "r") {
          return ["w", "w"];
        }
       
        if (p1 == "p" && p2 == "r") {
          return ["w", "l"];
        }
        if (p1 == "p" && p2 == "s") {
          return ["l", "w"];
        }
        if (p1 == "p" && p2 == "p") {
          return ["w", "w"];
        }
        if (p1 == "s" && p2 == "r") {
          return ["l", "w"];
        }
        if (p1 == "s" && p2 == "p") {
          return ["w", "l"];
        }
        if (p1 == "s" && p2 == "s") {
          return ["w", "w"];
        }
      };
      
    • 渲染方法:

      Javascript

      render() {
          return (
            
              
                Player One
                 this.weaponUpdate("playerOne", weapon)}
                  weapon={this.state.playerOne.weapon}
                  status={this.state.playerOne.status}
                />
              
        
              
                Player Two
                 this.weaponUpdate("playerTwo", weapon)}
                  weapon={this.state.playerTwo.weapon}
                  status={this.state.playerTwo.status}
                />
              
            
          );
        }
      }
        
      export default Controller;
      
  6. 对组件进行编码:这些代码非常简单。只是表示逻辑存在于此。

    • Player.js :如前所述,它是一个代表玩家实体的无状态组件。它接收四个道具,分别是玩家的活动状态、当前武器、获胜/失败状态和更新武器的函数处理程序。它进一步使用了两个组件 GameControls 和决策框,这将在下面讨论。此外,如果接收到的活动道具为真,则名为 gloomEffect 的 CSS 对象将应用于 div。

      Javascript

      import React from "react";
      import GameControls from "../GameControls/GameControls";
      import DecisionBox from "../DecisionBox/DecisionBox";
        
      const Player = props => {
        let glowEffect = {};
        if (props.active) {
          glowEffect = {
            "-webkit-box-shadow": "0 0 20px blue",
            "-moz-box-shadow": "0 0 20px blue",
            "box-shadow": "0 0 20px blue"
          };
        }
        
        return (
          
                        
        ); };    export default Player;
    • GameControls.js:它包含岩石、石头、剪刀三个按钮。如果播放器未处于活动状态,则按钮将被禁用。在按钮单击上,武器更新函数被调用,它接受一个参数“p”代表纸,“r”代表岩石,“s”代表剪刀,相应的状态得到更新。

      Javascript

      import React from "react";
      import { Card } from "antd";
      import { Button } from "antd";
        
      import "antd/dist/antd.css";
        
      const GameControls = props => {
        return (
          
            

                     

                  

              {" "}                

                  

                     

             
        ); };    export default GameControls;
    • DecisionBox.js :它显示玩家的武器和玩家的赢/输状态两件事。它接收两个道具武器('r'或'p'或's')和状态('w'或'l')。两个对象武器地图和状态地图用于将简写形式映射到可以在屏幕上显示的正确单词。

      Javascript

      import React from "react";
      import { Card } from "antd";
      import { Typography } from "antd";
        
      const { Title } = Typography;
        
      const weaponMap = {
        s: "Scissors",
        p: "Paper",
        r: "Rock"
      };
      const statusMap = {
        w: "Win",
        l: "Loose"
      };
        
      const DecisionBox = props => {
        return (
          
            
              {weaponMap[props.weapon]}
            
            
              {statusMap[props.status]}
            
          
        );
      };
        
      export default DecisionBox;
      

输出: