React

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > React > React掷骰子的小游戏

如何使用React构建一个掷骰子的小游戏

作者:练习两年半的工程师

这篇文章主要介绍了如何使用React构建一个掷骰子的小游戏,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

这是一个用 React 构建的小游戏应用,名为 Tenzies,目标是掷骰子,直到所有骰子的值相同。玩家可以“冻结”某些骰子,使它们在后续掷骰中保持不变。

1. App.jsx

import Die from "../public/components/Die"
import { useState, useRef, useEffect } from "react"
import { nanoid } from "nanoid"
import Confetti from "react-confetti"

初始化状态和引用

export default function App(){
  const [dice, setDice] = useState(() => generateAllNewDice())
  const buttonRef = useRef(null)

dice:管理 10 个骰子的数组状态。初始值通过 generateAllNewDice 函数生成。
buttonRef:引用按钮 DOM 元素,用于在胜利时自动聚焦。

游戏胜利条件

const gameWon = dice.every(die => die.isHeld) && 
  dice.every(die => die.value === dice[0].value)

游戏胜利的条件:

处理副作用

useEffect(() => {
  if (gameWon) {
    buttonRef.current.focus()
  }
}, [gameWon])

gameWontrue 时,自动让“新游戏”按钮获得焦点,提升可用性。

生成新的骰子数组

function generateAllNewDice() {
  return new Array(10).fill(0).map(() => ({
    value: Math.ceil(Math.random() * 6),
    isHeld: false,
    id: nanoid()
  }))
}

创建 10 个骰子对象,每个骰子有:

Math.ceil(Math.random() * 6) 是 JavaScript 中生成随机整数的常见方法之一。下面逐步解释其工作原理:

Math.random()

例如:可能的结果是 0.2345, 0.9876, 0.0012 等。

Math.random() * 6

示例: 如果 Math.random() 返回 0.2,则 0.2 * 6 = 1.2

如果 Math.random() 返回 0.9,则 0.9 * 6 = 5.4

Math.ceil()

作用:对数字向上取整,返回大于等于该数的最小整数。

综合步骤

Math.ceil(Math.random() * 6) 的完整过程:

返回结果

最终的返回值是一个 1 到 6 的随机整数

掷骰子逻辑

function rollDice() {
  if (!gameWon) {
    setDice(oldDice => oldDice.map(die => 
      die.isHeld ?
        die :
        {...die, value: Math.ceil(Math.random() * 6)}
    ))
  } else {
    setDice(generateAllNewDice())
  }
}

游戏未胜利时:

对未冻结的骰子重新生成随机值。

游戏胜利时:

重置游戏,生成新的骰子数组。

切换冻结状态

function hold(id) {
  setDice(oldDice => oldDice.map(die =>
    die.id === id ?
      {...die, isHeld: !die.isHeld} :
      die
  ))
}

根据点击的骰子 id,切换对应骰子的 isHeld 状态。

显示骰子

const diceElements = dice.map(dieObj => 
  (<Die 
    key={dieObj.id} 
    value={dieObj.value} 
    isHeld={dieObj.isHeld}
    hold={() => hold(dieObj.id)}
  />)
)

渲染 UI

return (
  <main>
    {gameWon && <Confetti />}
    <div aria-live="polite" className="sr-only">
        {gameWon && <p>Congratulations! You won! Press "New Game" to start again.</p>}
    </div>
    <h1 className="title">Tenzies</h1>
    <p className="instructions">Roll until all dice are the same. Click each die to freeze it at its current value between rolls.</p>
    <div className="dice-container">
      {diceElements}
    </div>
    <button ref={buttonRef} className="roll-dice" onClick={rollDice}>
      {gameWon ? "New Game" : "Roll"}
    </button>
  </main>
)

代码的核心逻辑总结

2. Die.jsx

export default function Die(props) {
    const styles = {
        backgroundColor: props.isHeld ? "#59E391" : "white"
    }

styles 是一个动态样式对象,用于控制按钮的背景颜色:

样式切换使用户能够直观地看到冻结状态。

return (
    <button 
        style={styles}
        onClick={props.hold}
        aria-pressed={props.isHeld}
        aria-label={`Die with value ${props.value}, 
        ${props.isHeld ? "held" : "not held"}`}
    >
        {props.value}
    </button>
)

style={styles}

onClick={props.hold}

aria-pressed={props.isHeld}

aria-label={Die with value ${props.value}, ${props.isHeld ? “held” : “not held”}}

3. index.css

1. 通用选择器 *

* {
  box-sizing: border-box;
}

2. body 样式

body {
  font-family: Karla, sans-serif;
  margin: 0;
  background-color: #0B2434;
  padding: 20px;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

3. div#root 样式

div#root {
  height: 100%;
  width: 100%;
  max-height: 400px;
  max-width: 400px;
}

4. main 样式

main {
  background-color: #F5F5F5;
  height: 100%;
  border-radius: 5px;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  align-items: center;
}

5. .title 样式

.title {
  font-size: 40px;
  margin: 0;
}

字体大小40px

边距margin: 0; 去除外边距。

6. .instructions 样式

.instructions {
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  margin-top: 0;
  text-align: center;
}

字体:优先使用 Inter 字体。

字体粗细:普通粗细 (font-weight: 400)。

文本对齐:居中对齐 (text-align: center)。

7. .dice-container 样式

.dice-container {
  display: grid;
  grid-template: auto auto / repeat(5, 1fr);
  gap: 20px;
  margin-bottom: 40px;
}

8. 通用按钮样式

button {
  font-family: Karla, sans-serif;
  cursor: pointer;
}

9. .dice-container button 样式

.dice-container button {
  height: 50px;
  width: 50px;
  box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.15);
  border-radius: 10px;
  border: none;
  background-color: white;
  font-size: 1.75rem;
  font-weight: bold;
}

10. .roll-dice 按钮样式

button.roll-dice {
  height: 50px;
  white-space: nowrap;
  width: auto;
  padding: 6px 21px;
  border: none;
  border-radius: 6px;
  background-color: #5035FF;
  color: white;
  font-size: 1.2rem;
}

11. .sr-only 样式

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

总结

这段 CSS 代码:

到此这篇关于使用React构建一个掷骰子的小游戏的文章就介绍到这了,更多相关React掷骰子的小游戏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文