使用 Firebase 和 React 构建实时多人游戏:Gladiator Taunt Wars
                        
                        阅读:250
                        点赞:0
                    
                    引言
在本深入指南中,我们将介绍如何使用 Firebase 和 React 构建实时多人游戏,并提供有关 Gladiator Taunt Wars 的详细示例。这种游戏模式中,玩家进行战略性的嘲讽决斗,轮流选择和回应嘲讽以减少对手的生命值(HP)。本文将涵盖构建此类游戏的各个方面,包括 Firebase 设置、匹配、游戏状态管理、动画、实时更新和基于 ELO 的排行榜集成。最终,您将对如何实现响应式、引人入胜的实时多人游戏体验有深入的了解。
设置 Firebase 和项目初始化
Firebase 设置
- 
初始化 Firebase:使用 Firestore 和 Authentication 初始化 Firebase,以进行实时数据处理和玩家验证。 import { initializeApp } from 'firebase/app';
 import { getFirestore } from 'firebase/firestore';
 import { getAuth } from 'firebase/auth';
 const firebaseConfig = {
 apiKey: 'YOUR_API_KEY',
 authDomain: 'YOUR_AUTH_DOMAIN',
 projectId: 'YOUR_PROJECT_ID',
 storageBucket: 'YOUR_STORAGE_BUCKET',
 messagingSenderId: 'YOUR_MESSAGING_SENDER_ID',
 appId: 'YOUR_APP_ID'
 };
 const app = initializeApp(firebaseConfig);
 const db = getFirestore(app);
 const auth = getAuth(app);
- 
设置 Firestore 规则:确保设置 Firestore 规则以限制对匹配数据的访问,仅允许经过身份验证的玩家查看和更新相关信息。 service cloud.firestore {
 match /databases/{database}/documents {
 match /tauntWars_matchmaking/{document=**} {
 allow read, write: if request.auth != null;
 }
 match /tauntWars_matches/{document=**} {
 allow read, write: if request.auth != null;
 }
 }
 }
React 项目结构
- 
组织组件:将 React 项目组织成可重用的组件,如 、、 和 ,以实现清晰且可维护的架构。 MainMenuGameBoardLeaderboardChatBox
游戏的关键组成部分
主菜单和匹配
- 
MainMenu 组件:向玩家提供选项,允许他们加入匹配、查看统计数据或访问排行榜。 const MainMenu = () => {
 const [isSearching, setIsSearching] = useState(false);
 const startSearching = async () => {
 // 启动匹配逻辑
 };
 return (
 <div>
 <button onClick={startSearching}>加入匹配button>
 <button>查看统计数据button>
 <button>访问排行榜button>
 div>
 );
 };
匹配逻辑
- 
startSearching 函数:通过将玩家添加到 Firestore 中的队列来启动匹配过程。 const startSearching = async () => {
 const user = auth.currentUser;
 if (user && db) {
 try {
 const matchmakingRef = collection(db, 'tauntWars_matchmaking');
 const userDocRef = doc(matchmakingRef, user.uid);
 await runTransaction(db, async (transaction) => {
 const userDoc = await transaction.get(userDocRef);
 if (!userDoc.exists()) {
 transaction.set(userDocRef, { userId: user.uid, status: 'waiting', timestamp: serverTimestamp() });
 } else {
 transaction.update(userDocRef, { status: 'waiting', timestamp: serverTimestamp() });
 }
 const q = query(matchmakingRef, where('status', '==', 'waiting'));
 const waitingPlayers = await getDocs(q);
 if (waitingPlayers.size > 1) {
 // 配对逻辑
 }
 });
 } catch (error) {
 setIsSearching(false);
 }
 }
 };
实时游戏状态
- 
监听游戏状态更改: 组件侦听 集合中的更改。 GameBoardtauntWars_matchesuseEffect(() => {
 const matchRef = doc(db, 'tauntWars_matches', matchId);
 const unsubscribe = onSnapshot(matchRef, (docSnapshot) => {
 if (docSnapshot.exists()) {
 setMatchData(docSnapshot.data());
 if (docSnapshot.data().currentTurn === 'response') {
 setResponses(getAvailableResponses(docSnapshot.data().selectedTaunt));
 }
 }
 });
 return () => unsubscribe();
 }, [matchId]);
玩家操作和嘲讽选择
- 
ActionSelection 组件:显示可用的嘲讽并处理选择过程。 const handleTauntSelection = async (taunt) => {
 const otherPlayer = currentPlayer === matchData.player1 ? matchData.player2 : matchData.player1;
 await updateDoc(doc(db, 'tauntWars_matches', matchId), {
 currentTurn: 'response',
 turn: otherPlayer,
 selectedTaunt: taunt.id,
 });
 };
计时器组件
- 
限制每个回合的持续时间: 组件保持游戏流程稳定。 Timerconst Timer = ({ isPlayerTurn, onTimeUp }) => {
 const [timeLeft, setTimeLeft] = useState(30);
 useEffect(() => {
 if (isPlayerTurn) {
 const interval = setInterval(() => {
 setTimeLeft(prev => {
 if (prev <= 1) {
 clearInterval(interval);
 onTimeUp();
 return 0;
 }
 return prev - 1;
 });
 }, 1000);
 return () => clearInterval(interval);
 }
 }, [isPlayerTurn, onTimeUp]);
 return <div>时间剩余: {timeLeft} 秒div>;
 };
动画
- 
使用 Konva 进行动画: 用于制作健康和攻击的动画。 CanvasComponentconst animateAttack = useCallback((attacker, defender) => {
 const targetX = attacker === 'player1' ? player1Pos.x + 50 : player2Pos.x - 50;
 const attackerRef = attacker === 'player1' ? player1Ref : player2Ref;
 attackerRef.current.to({
 x: targetX,
 duration: 0.2,
 onFinish: () => attackerRef.current.to({ x: player1Pos.x, duration: 0.2 })
 });
 });
实时聊天
- 
ChatBox 组件:显示嘲讽和响应消息。 const ChatBox = ({ matchId }) => {
 const [messages, setMessages] = useState([]);
 useEffect(() => {
 const chatRef = collection(db, 'tauntWars_matches', matchId, 'chat');
 const unsubscribe = onSnapshot(chatRef, (snapshot) => {
 setMessages(snapshot.docs.map((doc) => doc.data()));
 });
 return () => unsubscribe();
 }, [matchId]);
 return (
 <div>
 {messages.map((message, index) => (
 <div key={index} style={{ color: message.sender === auth.currentUser.uid ? 'blue' : 'black' }}>
 {message.text}
 div>
 ))}
 div>
 );
 };
排行榜
- 
EloLeaderboard 组件:根据玩家的 ELO 评级对玩家进行排序。 const EloLeaderboard = () => {
 const [players, setPlayers] = useState([]);
 useEffect(() => {
 const q = query(collection(db, 'users'), orderBy('tauntWars.elo', 'desc'), limit(100));
 const unsubscribe = onSnapshot(q, (querySnapshot) => {
 setPlayers(querySnapshot.docs.map((doc, index) => ({
 rank: index + 1,
 username: doc.data().username,
 elo: doc.data().tauntWars.elo,
 })));
 });
 return () => unsubscribe();
 }, []);
 return (
 <div>
 {players.map((player) => (
 <div key={player.rank}>
 {player.rank}. {player.username} - ELO: {player.elo}
 div>
 ))}
 div>
 );
 };
技术挑战和最佳实践
- 
使用事务确保一致性:在匹配和评分更新期间使用 Firestore 事务。 
- 
优化实时侦听器:使用 进行侦听器清理以防止内存泄漏,限制查询以减少 Firestore 读取次数。 unsubscribe()
- 
响应式设计: 根据视口调整大小,使用 库可靠地渲染交互式元素。 CanvasComponentreact-konva
- 
处理边缘情况:考虑玩家在游戏中途断开连接的情况,实施清理功能以确保更新匹配数据并关闭任何已放弃的匹配实例。 
结论
使用 Firebase 和 React,您可以创建适应实时用户操作的快节奏多人游戏体验。Gladiator Taunt Wars 的示例展示了如何集成实时更新、安全事务和动态动画,以制作引人入胜且具有视觉吸引力的游戏。随着我们继续扩展《角斗士嘲讽战争》,我们对新功能的潜力感到兴奋,包括 AI 驱动的对手和增强的比赛策略,这将加深游戏体验,让每场战斗都更加身临其境。