使用 Firebase 和 React 构建实时多人游戏:Gladiator Taunt Wars
阅读:17
点赞: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 项目组织成可重用的组件,如 、、 和 ,以实现清晰且可维护的架构。 MainMenu
GameBoard
Leaderboard
ChatBox
游戏的关键组成部分
主菜单和匹配
-
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);
}
}
};
实时游戏状态
-
监听游戏状态更改: 组件侦听 集合中的更改。 GameBoard
tauntWars_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,
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()
-
响应式设计: 根据视口调整大小,使用 库可靠地渲染交互式元素。 CanvasComponent
react-konva
-
处理边缘情况:考虑玩家在游戏中途断开连接的情况,实施清理功能以确保更新匹配数据并关闭任何已放弃的匹配实例。
结论
使用 Firebase 和 React,您可以创建适应实时用户操作的快节奏多人游戏体验。Gladiator Taunt Wars 的示例展示了如何集成实时更新、安全事务和动态动画,以制作引人入胜且具有视觉吸引力的游戏。随着我们继续扩展《角斗士嘲讽战争》,我们对新功能的潜力感到兴奋,包括 AI 驱动的对手和增强的比赛策略,这将加深游戏体验,让每场战斗都更加身临其境。