使用 Firebase 和 React 构建实时多人游戏:Gladiator Taunt Wars

发布:2024-11-13 09:19 阅读:23 点赞:0

引言

在本深入指南中,我们将介绍如何使用 Firebase 和 React 构建实时多人游戏,并提供有关 Gladiator Taunt Wars 的详细示例。这种游戏模式中,玩家进行战略性的嘲讽决斗,轮流选择和回应嘲讽以减少对手的生命值(HP)。本文将涵盖构建此类游戏的各个方面,包括 Firebase 设置、匹配、游戏状态管理、动画、实时更新和基于 ELO 的排行榜集成。最终,您将对如何实现响应式、引人入胜的实时多人游戏体验有深入的了解。

设置 Firebase 和项目初始化

Firebase 设置
  1. 初始化 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);
  2. 设置 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_matches
    useEffect(() => {
      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,
      });
    };
计时器组件
  • 限制每个回合的持续时间: 组件保持游戏流程稳定。Timer
    const 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 进行动画: 用于制作健康和攻击的动画。CanvasComponent
    const 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,
        duration0.2,
        onFinish() => attackerRef.current.to({ x: player1Pos.x, duration0.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 驱动的对手和增强的比赛策略,这将加深游戏体验,让每场战斗都更加身临其境。