react+three+fiber实现三维过马路避障游戏代码
代码语言:html
所属分类:游戏
代码描述:react+three+fiber实现三维过马路避障游戏代码,操作上下左右键让立方体过马路,别被车子撞到即可。
代码标签: react three fiber 三维 过 马路 避障 游戏 代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <style> @import url("https://fonts.googleapis.com/css?family=Press+Start+2P"); body { margin: 0; display: flex; min-height: 100vh; } #root { width: 100%; } .game { position: relative; width: 100%; height: 100%; font-family: "Press Start 2P", cursive; } #controls { position: absolute; bottom: 20px; min-width: 100%; display: flex; align-items: flex-end; justify-content: center; } #controls div { display: grid; grid-template-columns: 50px 50px 50px; gap: 10px; } #controls button { width: 100%; height: 40px; background-color: white; border: 1px solid lightgray; box-shadow: 3px 5px 0px 0px rgba(0, 0, 0, 0.75); cursor: pointer; outline: none; } #controls button:first-of-type { grid-column: 1/-1; } #score { position: absolute; top: 20px; left: 20px; font-size: 2em; color: white; } #result-container { position: absolute; min-width: 100%; min-height: 100%; top: 0; display: flex; align-items: center; justify-content: center; #result { display: flex; flex-direction: column; align-items: center; background-color: white; padding: 20px; } button { background-color: red; padding: 20px 50px 20px 50px; font-family: inherit; font-size: inherit; cursor: pointer; } } #youtube, #youtube-card { display: none; font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; color: black; } @media (min-height: 425px) { /** Youtube logo by https://codepen.io/alvaromontoro */ #youtube { z-index: 50; width: 100px; display: block; height: 70px; position: fixed; bottom: 20px; right: 20px; background: red; border-radius: 50% / 11%; transform: scale(0.8); transition: transform 0.5s; } #youtube:hover, #youtube:focus { transform: scale(0.9); color: black; } #youtube::before { content: ""; display: block; position: absolute; top: 7.5%; left: -6%; width: 112%; height: 85%; background: red; border-radius: 9% / 50%; } #youtube::after { content: ""; display: block; position: absolute; top: 20px; left: 40px; width: 45px; height: 30px; border: 15px solid transparent; box-sizing: border-box; border-left: 30px solid white; } #youtube span { font-size: 0; position: absolute; width: 0; height: 0; overflow: hidden; } #youtube:hover + #youtube-card { z-index: 49; display: block; position: fixed; bottom: 12px; right: 10px; padding: 25px 130px 25px 25px; width: 300px; background-color: white; } } </style> </head> <body translate="no"> <div id="root"></div> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/babel.7.18.13.js"></script> <script type="text/babel" data-type="module"> import React, { useRef, useEffect } from "https://esm.sh/react"; import { createRoot } from "https://esm.sh/react-dom/client"; import { Canvas, useFrame, useThree } from "https://esm.sh/@react-three/fiber"; import { Bounds } from "https://esm.sh/@react-three/drei"; import * as THREE from "https://esm.sh/three"; import { create } from "https://esm.sh/zustand"; const minTileIndex = -8; const maxTileIndex = 8; const tilesPerRow = maxTileIndex - minTileIndex + 1; const tileSize = 42; const playerState = { currentRow: 0, currentTile: 0, movesQueue: [], ref: null }; function queueMove(direction) { const isValidMove = endsUpInValidPosition( { rowIndex: playerState.currentRow, tileIndex: playerState.currentTile }, [...playerState.movesQueue, direction] ); if (!isValidMove) return; playerState.movesQueue.push(direction); } function stepCompleted() { const direction = playerState.movesQueue.shift(); if (direction === "forward") playerState.currentRow += 1; if (direction === "backward") playerState.currentRow -= 1; if (direction === "left") playerState.currentTile -= 1; if (direction === "right") playerState.currentTile += 1; // Add new rows if the player is running out of them if (playerState.currentRow === useMapStore.getState().rows.length - 10) { useMapStore.getState().addRows(); } useGameStore.getState().updateScore(playerState.currentRow); } function setPlayerRef(ref) { playerState.ref = ref; } function resetPlayerStore() { playerState.currentRow = 0; playerState.currentTile = 0; playerState.movesQueue = []; if (!playerState.ref) return; playerState.ref.position.x = 0; playerState.ref.position.y = 0; playerState.ref.children[0].rotation.z = 0; } const useGameStore = create((set) => ({ status: "running", score: 0, updateScore: (rowIndex) => { set((state) => ({ score: Math.max(rowIndex, state.score) })); }, endGame: () => { set({ status: "over" }); }, reset: () => { useMapStore.getState().reset(); resetPlayerStore(); set({ status: "running", score: 0 }); } })); const useMapStore = create((set) => ({ rows: generateRows(20), addRows: () => { const newRows = generateRows(20); set((state) => ({ rows: [...state.rows, ...newRows] })); }, reset: () => set({ rows: generateRows(20) }) })); function Game() { return ( <div className="game"> <Scene> <Player /> <Map /> </Scene> <Score /> <Controls /> <Result /> </div> ); } const Scene = ({ children }) => { return ( <Canvas orthographic={true} shadows={true} camera={{ up: [0, 0, 1], position: [300, -300, 300] }} > <ambientLight /> {children} </Canvas> ); }; function Controls() { useEventListeners(); return ( <div id="controls"> <div> <button onClick={() => queueMove("forward")}>▲</button> <button onClick={() => queueMove("left")}>◀</button> <button onClick={() => queueMove("backward")}>▼</button> <button onClick={() => queueMove("right")}>▶</button> </div> </div> ); } function Score() { const score = useGameStore((state) => state.score); return <div id="score">{score}</div>; } function Result() { cons.........完整代码请登录后点击上方下载按钮下载查看
网友评论0