首頁 >web前端 >js教程 >使用 React 和 Firebase 建立即時多人遊戲:角鬥士嘲諷戰爭

使用 React 和 Firebase 建立即時多人遊戲:角鬥士嘲諷戰爭

Barbara Streisand
Barbara Streisand原創
2024-11-14 11:27:02211瀏覽

Building a Real-Time Multiplayer Game with React and Firebase: Gladiator Taunt Wars

Introduction

In this in-depth guide, we’ll walk through building a real-time multiplayer game using Firebase and React, with a detailed example from Gladiator Taunt Wars. In this game mode, players engage in strategic taunt duels, taking turns selecting and responding to taunts to reduce their opponent’s health points (HP). This article will cover every aspect of building such a game, including Firebase setup, matchmaking, game state management, animations, real-time updates, and ELO-based leaderboard integration. By the end, you'll gain a solid understanding of how to implement a responsive, engaging, real-time multiplayer experience.

Setting Up Firebase and Project Initialization
Firebase Setup
Initialize Firebase with Firestore and Authentication for real-time data handling and player verification. These will provide the backbone for storing and managing match data, player information, and real-time leaderboard updates. Ensure you set up Firestore rules to restrict access to match data, allowing only the authenticated players to view and update relevant information.

React Project Structure
Organize your React project into reusable components that will represent each game element, such as the matchmaking system, game board, leaderboard, and chat. Structure components hierarchically for a clear and maintainable architecture.

Key Components of the Game

  1. Main Menu and Matchmaking The MainMenu component presents options to players, allowing them to join matchmaking, view stats, or access the leaderboard. The Matchmaking Component facilitates pairing players in real-time, leveraging Firestore transactions for consistency.

Matchmaking Logic
The startSearching function initiates the matchmaking process by adding the player to a queue in Firestore. If an opponent is found, a new match document is created, storing both players’ IDs and initializing game parameters.

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) {
          // Pairing logic
        }
      });
    } catch (error) {
      setIsSearching(false);
    }
  }
};

The function uses Firestore transactions to ensure that a player isn't double-matched, which would disrupt the matchmaking system. Firebase’s serverTimestamp function is useful here to ensure consistent timestamps across multiple time zones.

  1. Real-Time Game State on the GameBoard Component Listening to Game State Changes The GameBoard component listens for changes in the tauntWars_matches collection. When a player selects a taunt or responds, the change is immediately reflected in Firestore, triggering a re-render for both players.
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]);

Handling Game Phases
Players alternate turns, each choosing a taunt or response. The currentTurn attribute indicates which action phase the game is in. Each action is updated in Firestore, triggering real-time synchronization across both clients. For instance, a player selecting a taunt switches currentTurn to “response,” alerting the opponent to choose a response.

  1. Player Actions and Taunt Selection ActionSelection Component This component displays available taunts and handles the selection process. Players select a taunt or response, which is stored in Firestore and triggers the next phase.
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,
  });
};

The Timer component restricts the duration of each turn. This timeout function maintains a steady game flow and penalizes players who fail to act in time, reducing their HP.

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]);
};
  1. Animations with Konva for Health and Attacks CanvasComponent: Uses react-konva to animate health changes and attacks. The health bars visually represent the damage taken or inflicted based on taunts, enhancing engagement.
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,
    duration: 0.2,
    onFinish: () => attackerRef.current.to({ x: player1Pos.x, duration: 0.2 })
  });
});

By simulating attacks in this way, we visually indicate the power and result of each taunt or response, creating a more immersive experience.

  1. Real-Time Chat with ChatBox The ChatBox component is a real-time chat that displays taunt and response messages. This chat interface gives players feedback and context, creating an interactive experience.
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]);
};

Each message is rendered conditionally based on the user’s ID, differentiating sent and received messages with distinct styling.

  1. Leaderboard with ELO Rankings The EloLeaderboard component sorts players based on their ELO rating. Each match updates player ratings in Firestore, which is fetched and displayed in real-time.
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();
  }, []);
};

The leaderboard ranks players based on their ELO, providing competitive motivation and a way for players to track their progress.

Technical Challenges and Best Practices
Consistency with Firestore Transactions
Using transactions ensures that simultaneous reads/writes to Firestore maintain data integrity, especially during matchmaking and scoring updates.

Optimizing Real-Time Listeners
Employ listener cleanup using unsubscribe() to prevent memory leaks. Also, limiting queries can help reduce the number of Firestore reads, optimizing costs and performance.

畫布響應式設計
CanvasComponent 根據視窗調整其大小,使遊戲能夠跨裝置回應。使用react-konva庫可以實現互動元素的穩健渲染,透過動畫為玩家提供視覺回饋。

處理邊緣情況
考慮玩家在遊戲中斷開連線的情況。為此,實現一個清理功能,以確保更新比賽資料並關閉任何廢棄的比賽實例。

總結
透過 Firebase 和 React,您可以創建適應即時用戶操作的快節奏多人遊戲體驗。 Gladiator Taunt Wars 中的範例示範如何整合即時更新、安全交易和動態動畫來製作引人入勝且具有視覺吸引力的遊戲。

結論

為《角鬥士之戰》建構《角鬥士嘲諷戰爭》是一次收穫豐富的旅程,它將React、Firebase 和沈浸式遊戲機制結合在一起,在一款基於Web 的遊戲中捕捉羅馬競技場戰鬥的激烈程度。利用 Firebase 的即時 Firestore 資料庫、安全身份驗證和強大的託管功能,我們能夠創建無縫、社群驅動的體驗,讓玩家可以在策略戰鬥中進行對決。整合 GitHub Actions 進行持續部署也簡化了開發,讓我們專注於增強遊戲玩法和使用者互動。

隨著我們繼續擴展《角鬥士嘲諷戰爭》,我們對新功能的潛力感到興奮,包括人工智慧驅動的對手和增強的比賽策略,這將加深遊戲體驗,讓每場戰鬥都更加身臨其境。歷史策略與現代技術的結合為玩家提供了一種參與角鬥士世界的動態方式。

本系列的後續文章將深入探討使用 Firebase 創建互動式 Web 應用程式的技術細節,包括優化即時資料流、管理複雜的遊戲狀態以及利用 AI 增強玩家參與度。我們將探索橋接前端和後端服務的最佳實踐,以創建響應迅速的即時多人遊戲環境。

無論您是開發自己的互動遊戲還是對 Gladiators Battle 背後的技術感到好奇,本系列都提供了有關使用 Firebase 構建現代 Web 應用程式的寶貴見解。加入我們,我們將繼續將古代歷史與尖端技術相融合,為當今的數位世界重新構想角鬥士戰鬥的刺激。

?發現更多:

探索角鬥士之戰:潛入羅馬世界,體驗策略與戰鬥 https://gladiatorsbattle.com
請參閱我們的 GitHub:查看我們的程式碼庫和貢獻:https://github.com/HanGPIErr/Gladiators-Battle-Documentation。
在 LinkedIn 上聯絡:在 LinkedIn 上關注我的專案更新 https://www.linkedin.com/in/pierre-romain-lopez/
還有我的 X 帳號:https://x.com/GladiatorsBT

以上是使用 React 和 Firebase 建立即時多人遊戲:角鬥士嘲諷戰爭的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn