使用React制作一個貪吃蛇游戲的代碼詳解
在 React 中創(chuàng)建貪吃蛇游戲
Snake Game 使用 ReactJS 項目實現(xiàn)功能組件并相應地管理狀態(tài)。開發(fā)的游戲允許用戶使用箭頭鍵控制蛇或觸摸屏幕上顯示的按鈕來收集食物并增長長度。游戲的目標是在不與墻壁或蛇自己的身體碰撞的情況下吃盡可能多的食物。
最終輸出預覽: 讓我們看看我們的最終項目會是什么樣子。
創(chuàng)建貪吃蛇游戲的方法:
給定的代碼代表使用 ReactJS
的貪吃蛇游戲項目。它涉及設(shè)置蛇、食物、按鈕和菜單的組件。游戲以初始狀態(tài)初始化,處理蛇運動的用戶輸入,檢測碰撞,并相應地更新游戲板。渲染和用戶界面的實現(xiàn)是為了顯示游戲元素。游戲流程包括菜單和游戲玩法的過渡。
創(chuàng)建貪吃蛇游戲的步驟:
步驟 1: 在 VSCode IDE 中使用以下命令設(shè)置 React 項目。
?npx create-react-app snack_game
步驟 2: 執(zhí)行以下命令導航到新創(chuàng)建的項目文件夾。
?cd snack_game
步驟 3: 創(chuàng)建一個名為 Components 的文件夾。我們將在此組件文件夾中創(chuàng)建各種組件及其樣式文件,例如 Button.js、Food.js、Menu.js、Snake.js、Menu.css 和 Button.css。
貪吃蛇游戲的項目結(jié)構(gòu):
package.json中更新后的依賴項將如下所示:
?"dependencies": { ? ? ?"@testing-library/jest-dom": "^5.16.5", ? ? ?"@testing-library/react": "^13.4.0", ? ? ?"@testing-library/user-event": "^13.5.0", ? ? ?"react": "^18.2.0", ? ? ?"react-dom": "^18.2.0", ? ? ?"react-scripts": "5.0.1", ? ? ?"web-vitals": "^2.1.4" ?}
示例: 在上述目錄結(jié)構(gòu)中提到的App.js
和 index.css
文件中插入以下代碼
App.js
?// App.js ?import React, { Component } from "react"; ?import Snake from "./Components/Snake"; ?import Food from "./Components/Food"; ?import Button from "./Components/Button"; ?import Menu from "./Components/Menu"; ?import "./App.css"; ?const getRandomFood = () => { ? let min = 1; ? let max = 98; ? let x = Math.floor((Math.random() * (max - min + 1) + min) / 2) * 2; ? let y = Math.floor((Math.random() * (max - min + 1) + min) / 2) * 2; ? return [x, y]; ?}; ?? ?const initialState = { ? food: getRandomFood(), ? direction: "RIGHT", ? speed: 100, ? route: "menu", ? snakeDots: [ ? [0, 0], ? [0, 2], ? ], ?}; ?? ?class App extends Component { ? constructor() { ? super(); ? this.state = initialState; ? } ?? ? componentDidMount() { ? setInterval(this.moveSnake, this.state.speed); ? document.onkeydown = this.onKeyDown; ? } ?? ? componentDidUpdate() { ? this.onSnakeOutOfBounds(); ? this.onSnakeCollapsed(); ? this.onSnakeEats(); ? } ?? ? onKeyDown = (e) => { ? e.preventDefault(); ? e = e || window.event; ? switch (e.keyCode) { ? case 37: ? this.setState({ direction: "LEFT" }); ? break; ? case 38: ? this.setState({ direction: "UP" }); ? break; ? case 39: ? this.setState({ direction: "RIGHT" }); ? break; ? case 40: ? this.setState({ direction: "DOWN" }); ? break; ? } ? }; ?? ? moveSnake = () => { ? let dots = [...this.state.snakeDots]; ? let head = dots[dots.length - 1]; ? if (this.state.route === "game") { ? switch (this.state.direction) { ? case "RIGHT": ? head = [head[0] + 2, head[1]]; ? break; ? case "LEFT": ? head = [head[0] - 2, head[1]]; ? break; ? case "DOWN": ? head = [head[0], head[1] + 2]; ? break; ? case "UP": ? head = [head[0], head[1] - 2]; ? break; ? } ? dots.push(head); ? dots.shift(); ? this.setState({ ? snakeDots: dots, ? }); ? } ? }; ?? ? onSnakeOutOfBounds() { ? let head = this.state.snakeDots[this.state.snakeDots.length - 1]; ? if (this.state.route === "game") { ? if ( ? head[0] >= 100 || ? head[1] >= 100 || ? head[0] < 0 || ? head[1] < 0 ? ) { ? this.gameOver(); ? } ? } ? } ?? ? onSnakeCollapsed() { ? let snake = [...this.state.snakeDots]; ? let head = snake[snake.length - 1]; ? snake.pop(); ? snake.forEach((dot) => { ? if (head[0] == dot[0] && head[1] == dot[1]) { ? this.gameOver(); ? } ? }); ? } ?? ? onSnakeEats() { ? let head = this.state.snakeDots[this.state.snakeDots.length - 1]; ? let food = this.state.food; ? if (head[0] == food[0] && head[1] == food[1]) { ? this.setState({ ? food: getRandomFood(), ? }); ? this.increaseSnake(); ? this.increaseSpeed(); ? } ? } ?? ? increaseSnake() { ? let newSnake = [...this.state.snakeDots]; ? newSnake.unshift([]); ? this.setState({ ? snakeDots: newSnake, ? }); ? } ?? ? increaseSpeed() { ? if (this.state.speed > 10) { ? this.setState({ ? speed: this.state.speed - 20, ? }); ? } ? } ?? ? onRouteChange = () => { ? this.setState({ ? route: "game", ? }); ? }; ?? ? gameOver() { ? alert(`GAME OVER, your score is ${this.state.snakeDots.length - 2}`); ? this.setState(initialState); ? } ?? ? onDown = () => { ? let dots = [...this.state.snakeDots]; ? let head = dots[dots.length - 1]; ?? ? head = [head[0], head[1] + 2]; ? dots.push(head); ? dots.shift(); ? this.setState({ ? direction: "DOWN", ? snakeDots: dots, ? }); ? }; ?? ? onUp = () => { ? let dots = [...this.state.snakeDots]; ? let head = dots[dots.length - 1]; ?? ? head = [head[0], head[1] - 2]; ? dots.push(head); ? dots.shift(); ? this.setState({ ? direction: "UP", ? snakeDots: dots, ? }); ? }; ?? ? onRight = () => { ? let dots = [...this.state.snakeDots]; ? let head = dots[dots.length - 1]; ?? ? head = [head[0] + 2, head[1]]; ? dots.push(head); ? dots.shift(); ? this.setState({ ? direction: "RIGHT", ? snakeDots: dots, ? }); ? }; ?? ? onLeft = () => { ? let dots = [...this.state.snakeDots]; ? let head = dots[dots.length - 1]; ?? ? head = [head[0] - 2, head[1]]; ? dots.push(head); ? dots.shift(); ? this.setState({ ? direction: "LEFT", ? snakeDots: dots, ? }); ? }; ?? ? render() { ? const { route, snakeDots, food } = this.state; ? return ( ? <div> ? {route === "menu" ? ( ? <div> ? <Menu onRouteChange={this.onRouteChange} /> ? </div> ? ) : ( ? <div> ? <div className="game-area"> ? <Snake snakeDots={snakeDots} /> ? <Food dot={food} /> ? </div> ? <Button ? onDown={this.onDown} ? onLeft={this.onLeft} ? onRight={this.onRight} ? onUp={this.onUp} ? /> ? </div> ? )} ? </div> ? ); ? } ?} ?? ?export default App; ??
index.css
?/* index.css */ ?body { ? background-color: #1e1e1e; ?} ?? ?.game-area { ? position: relative; ? width: 600px; ? height: 500px; ? border: 2px solid #dc042c; ? border-radius: 10px; ? margin: 50px auto; ? display: flex; ? flex-wrap: wrap; ? box-shadow: 0 0 10px #abbfc0; ?} ?? ?@media only screen and (max-width: 800px) { ? .game-area { ? position: relative; ? width: 350px; ? height: 300px; ? } ?? ? .snake { ? width: 12px; ? height: 12px; ? } ?} ?? ?.snake { ? position: absolute; ? width: 2%; ? height: 2%; ? background-color: #dc042c; ? border: 1px solid white; ? z-index: 2; ?} ?? ?.food { ? position: absolute; ? width: 12px; ? height: 12px; ? background-color: white; ? border-radius: 20px; ? z-index: 1; ?} ??
在不同的文件中編寫以下提到的代碼(每個代碼塊的第一行都提到了文件名)
- Button.js: Button.js表示React功能組件,用于在snake游戲中渲染控制蛇移動的按鈕。
- Menu.js: Menu.js文件代碼為Snake Game呈現(xiàn)菜單。它顯示一個“開始游戲”按鈕,并在單擊時觸發(fā)onRouteChange功能。菜單的樣式使用“menu.CSS”文件中的CSS
- Food.js 是一個React組件,它根據(jù)提供的坐標在游戲中呈現(xiàn)食物。
- Snake.js:Snake.js文件代碼是一個React組件,它在游戲中基于表示蛇點的坐標數(shù)組來渲染蛇。
//Button.js
?//Button.js ?import React from "react"; ?import "./Button.css"; ?? ?const Button = ({ onUp, onDown, onLeft, onRight }) => { ? return ( ? <div className="buttons"> ? <div className="upwards"> ? <input className="up" onClick={onUp} type="button" value="UP" /> ? </div> ? <div className="sideways"> ? <input ? className="left" ? onClick={onLeft} ? type="button" ? value="LEFT" ? /> ? <input ? className="right" ? onClick={onRight} ? type="button" ? value="RIGHT" ? /> ? </div> ? <div className="downwards"> ? <input ? className="down" ? onClick={onDown} ? type="button" ? value="DOWN" ? /> ? </div> ? </div> ? ); ?}; ?export default Button; ??
Food.js
?//Food.js ?import React from "react"; ?? ?const Food = (props) => { ? const style = { ? left: `${props.dot[0]}%`, ? top: `${props.dot[1]}%`, ? }; ? return <div className="food" style={style} />; ?}; ?? ?export default Food; ??
Menu.js
?//Menu.js ?import React from "react"; ?import "./Menu.css"; ?? ?const Menu = ({ onRouteChange }) => { ? return ( ? <div className="wrapper"> ? <div> ? <input ? onClick={onRouteChange} ? className="start" ? type="button" ? value="start game" ? /> ? </div> ? </div> ? ); ?}; ?? ?export default Menu; ??
Snake.js
?//Snake.js ?import React from "react"; ?? ?const Snake = (props) => { ? return ( ? <div> ? {props.snakeDots.map((dot, i) => { ? const style = { ? left: `${dot[0]}%`, ? top: `${dot[1]}%`, ? }; ? return <div className="snake" key={i} style={style} />; ? })} ? </div> ? ); ?}; ?export default Snake; ??
Button.css
?/* Button.css */ ?.upwards, ?.downwards { ? display: flex; ? justify-content: center; ?} ?? ?.sideways { ? display: flex; ? justify-content: center; ? margin: 10px; ?} ?? ?.left, ?.right { ? margin: 50px; ? padding: 20px; ? border: 0px solid; ? border-radius: 20px; ? border: 1px solid white; ? color: #dc042c; ? background: #1e1e1e; ? box-shadow: 5px -5px 10px rgba(0, 0, 0, 0.6); ?} ?? ?.up, ?.down { ? padding: 20px; ? border: 0px solid; ? border-radius: 20px; ? border: 1px solid white; ? color: #dc042c; ? background: #1e1e1e; ? box-shadow: 5px -5px 10px rgba(0, 0, 0, 0.6); ?} ??
Menu.css
?/* Menu.css */ ?.wrapper { ? position: relative; ? width: 200px; ? height: 250px; ? border: 2px solid #dc042c; ? /* border-radius: 10px; */ ? margin: 50px auto; ? margin-top: 200px; ? display: flex; ? flex-wrap: wrap; ? justify-content: center; ? /* box-shadow: 0 0 10px #abbfc0; */ ?} ?? ?.start { ? margin: 100px; ? background: #1e1e1e; ? color: white; ? border-radius: 7px; ? border: 0px; ? padding: 10px; ? font-size: 1.2em; ? box-shadow: 0 0 70px #abbfc0; ? font-family: "Courier New", Courier, monospace; ?} ??
啟動我們的程序:
Step 1: 在命令行執(zhí)行一下命令啟動項目程序
?npm start
Step 2: 在瀏覽器地址中打開一下地址
輸出:
以上就是使用React制作一個貪吃蛇游戲的代碼詳解的詳細內(nèi)容,更多關(guān)于React貪吃蛇游戲的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
react執(zhí)行【npx create-react-app my-app】出現(xiàn)常見錯誤的解決辦法
文章主要介紹了在使用npx創(chuàng)建React應用時可能遇到的幾種常見錯誤及其解決方法,包括缺少依賴、網(wǎng)絡問題和npx解析錯誤等,并提供了相應的解決措施,此外,還提到了使用騰訊云云產(chǎn)品來支持React應用開發(fā)2024-11-11react-three/postprocessing庫的參數(shù)中文含義使用解析
這篇文章主要介紹了react-three/postprocessing庫的參數(shù)中文含義使用總結(jié),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05React實現(xiàn)錨點跳轉(zhuǎn)組件附帶吸頂效果的示例代碼
這篇文章主要為大家詳細介紹了React如何實現(xiàn)移動端錨點跳轉(zhuǎn)組件附帶吸頂效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下2023-01-01在?React?Native?中使用?CSS?Modules的配置方法
有些前端工程師希望也能像開發(fā) web 應用那樣,使用 CSS Modules 來開發(fā) React Native,本文將介紹如何在 React Native 中使用 CSS Modules,需要的朋友可以參考下2022-08-08React實現(xiàn)下拉框的key,value的值同時傳送
這篇文章主要介紹了React實現(xiàn)下拉框的key,value的值同時傳送方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08