Head-to-Head Game Integration Guide
Overview
MCAP provides three distinct pathways for providers to integrate Head-to-Head (H2H) multiplayer games with real-money on-chain mechanics. Choose the option that best fits your technical requirements and development timeline.
Integration Options
Option 1: SDK/iframe Integration (Recommended, Under Development)
Embed MCAP's ready-to-use H2H game components directly into your platform. Get professional game interfaces with minimal code - just add an iframe or use our SDK components.
Option 2: MCAP Game Server Integration
Connect to MCAP's hosted game servers (Chess, Battleship) and create custom skins/UIs while we handle the game logic and real-time multiplayer Web3 infrastructure.
Option 3: Custom H2H Game Development (Under Development)
Build your own multiplayer games from scratch while leveraging MCAP's betting infrastructure for match creation, non-custodial fund management, and automated settlement.
Option 1: SDK/iframe Integration (Recommended, Under Development)
Overview
The SDK/iframe integration is the fastest way to add H2H multiplayer games to your platform. MCAP provides ready-to-use UI components and complete game interfaces that you can embed directly into your website or application with minimal code.
Benefits
- ⚡ Fastest Implementation: Get H2H games live in hours, not weeks
- 🎨 Professional UI: Polished, battle-tested game interfaces
- 🔧 Zero Maintenance: We handle all updates, bug fixes, and improvements
- 📱 Responsive Design: Works seamlessly on desktop and mobile
- 🎮 Multiple Games: Chess, Battleship, and more games available
- 🎯 Plug & Play: No game logic development required
Implementation Methods
Method 1: iframe Embedding
The simplest integration method - just add an iframe to your page:
<!-- Basic iframe integration -->
<iframe
src="https://games.mcap.ai/chess?provider=YOUR_PROVIDER_ID&theme=dark"
width="100%"
height="600px"
frameborder="0"
allow="clipboard-write">
</iframe>
<!-- With custom styling -->
<div class="mcap-game-container">
<iframe
id="mcap-chess-game"
src="https://games.mcap.ai/chess?provider=YOUR_PROVIDER_ID&token=USDC&theme=light"
style="width: 100%; height: 80vh; border: none; border-radius: 8px;">
</iframe>
</div>
Supported Parameters:
provider: Your provider ID (required)theme:light|dark|auto(default: auto)token: Default token symbol (optional)locale:en|es|fr| etc. (default: en)autoConnect:true|false(default: false)
Method 2: SDK Integration
For more control and better integration with your existing UI:
npm install @mcap/platform-sdk
import { MCAPGames } from '@mcap/platform-sdk';
// Initialize MCAP Games
const mcapGames = new MCAPGames({
providerId: 'YOUR_PROVIDER_ID',
theme: 'dark',
apiUrl: 'https://api.mcap.ai'
});
// Mount a chess game
const chessGame = await mcapGames.mountGame('chess', {
container: '#chess-container',
onMatchCreated: (matchData) => {
console.log('Match created:', matchData);
},
onGameEnd: (result) => {
console.log('Game ended:', result);
// Handle win/loss/draw
},
onError: (error) => {
console.error('Game error:', error);
}
});
// Mount a battleship game
const battleshipGame = await mcapGames.mountGame('battleship', {
container: '#battleship-container',
customStyles: {
primaryColor: '#your-brand-color',
backgroundColor: '#your-bg-color'
}
});
Method 3: React Component Integration
For React applications:
npm install @mcap/react-games
import { ChessGame, BattleshipGame } from '@mcap/react-games';
function MyGamesPage() {
const handleGameEnd = (result: GameResult) => {
if (result.isWinner) {
// Show celebration
showCelebration();
}
// Update user balance, show results, etc.
};
return (
<div className="games-container">
<h2>Play Chess</h2>
<ChessGame
providerId="YOUR_PROVIDER_ID"
theme="dark"
onGameEnd={handleGameEnd}
onMatchCreated={(match) => console.log('Chess match:', match)}
style={{ width: '100%', height: '600px' }}
/>
<h2>Play Battleship</h2>
<BattleshipGame
providerId="YOUR_PROVIDER_ID"
theme="light"
onGameEnd={handleGameEnd}
customStyles={{
primaryColor: '#your-brand-color',
secondaryColor: '#your-secondary-color'
}}
/>
</div>
);
}
Customization Options
Theme Customization
const customTheme = {
colors: {
primary: '#your-primary-color',
secondary: '#your-secondary-color',
background: '#your-bg-color',
text: '#your-text-color',
accent: '#your-accent-color'
},
fonts: {
primary: 'Your Primary Font',
secondary: 'Your Secondary Font'
},
borderRadius: '8px',
shadows: {
card: '0 4px 6px rgba(0, 0, 0, 0.1)',
button: '0 2px 4px rgba(0, 0, 0, 0.1)'
}
};
const mcapGames = new MCAPGames({
providerId: 'YOUR_PROVIDER_ID',
customTheme
});
Localization Support
// Built-in language support
const mcapGames = new MCAPGames({
providerId: 'YOUR_PROVIDER_ID',
locale: 'es', // Spanish
// Other supported: 'en', 'fr', 'de', 'pt', 'ja', 'ko'
});
// Custom translations
const customTranslations = {
'game.chess.title': 'Ajedrez',
'game.battleship.title': 'Batalla Naval',
'button.createMatch': 'Crear Partida',
'button.joinMatch': 'Unirse a Partida'
};
mcapGames.setTranslations('es', customTranslations);
Authentication Integration
The SDK automatically handles user authentication when integrated with your existing auth system:
// Option 1: Pass existing JWT token
const mcapGames = new MCAPGames({
providerId: 'YOUR_PROVIDER_ID',
userToken: userJwtToken // Your existing user JWT
});
// Option 2: Use wallet connection
const mcapGames = new MCAPGames({
providerId: 'YOUR_PROVIDER_ID',
walletProvider: 'metamask' // or 'walletconnect', 'coinbase'
});
// Option 3: Custom authentication
mcapGames.setAuthenticationHandler(async () => {
const walletAddress = await yourWalletProvider.getAddress();
const signature = await yourWalletProvider.signMessage('MCAP Auth');
return {
walletAddress,
signature,
timestamp: Date.now()
};
});
Event Handling
const mcapGames = new MCAPGames({
providerId: 'YOUR_PROVIDER_ID'
});
// Global event listeners
mcapGames.on('matchCreated', (matchData) => {
// Track match creation in your analytics
analytics.track('Match Created', {
gameType: matchData.gameType,
wager: matchData.wager
});
});
mcapGames.on('gameEnd', (result) => {
// Update user stats, show notifications
if (result.isWinner) {
showWinNotification(result.winnings);
updateUserBalance(result.newBalance);
}
});
mcapGames.on('error', (error) => {
// Handle errors gracefully
if (error.code === 'INSUFFICIENT_FUNDS') {
showDepositModal();
} else {
showErrorMessage(error.message);
}
});
// Game-specific events
const chessGame = mcapGames.getGame('chess');
chessGame.on('moveMade', (move) => {
// Track moves for analysis
analytics.track('Chess Move', { move });
});
chessGame.on('checkmate', (winner) => {
// Special celebration for checkmate
showCheckmateAnimation();
});
Advanced Configuration
const mcapGames = new MCAPGames({
providerId: 'YOUR_PROVIDER_ID',
// Performance settings
enablePreloading: true,
cacheGames: true,
optimizeForMobile: true,
// Feature flags
features: {
spectatorMode: true,
gameRecording: true,
socialFeatures: true,
tournaments: true
},
// Analytics integration
analytics: {
provider: 'google-analytics', // or 'mixpanel', 'amplitude'
trackingId: 'YOUR_GA_ID'
},
// Custom API endpoints (for white-label solutions)
apiEndpoints: {
games: 'https://your-custom-domain.com/api/games',
auth: 'https://your-custom-domain.com/api/auth'
}
});
Best Practices
1. Responsive Design
/* Ensure games scale properly */
.mcap-game-container {
width: 100%;
max-width: 800px;
margin: 0 auto;
aspect-ratio: 1; /* For chess */
}
@media (max-width: 768px) {
.mcap-game-container {
height: 70vh;
aspect-ratio: unset;
}
}
2. Loading States
mcapGames.on('gameLoading', (gameType) => {
showLoadingSpinner(`Loading ${gameType}...`);
});
mcapGames.on('gameReady', (gameType) => {
hideLoadingSpinner();
});
3. Error Boundaries
// React Error Boundary for game components
class GameErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.error('Game Error:', error, errorInfo);
// Report to error tracking service
}
render() {
if (this.state.hasError) {
return (
<div className="game-error">
<h3>Game temporarily unavailable</h3>
<button onClick={() => window.location.reload()}>
Refresh Page
</button>
</div>
);
}
return this.props.children;
}
}
Getting Started with SDK/iframe
- Get Your Provider ID: Register at MCAP Provider Portal
- Choose Integration Method: iframe, SDK, or React components
- Add to Your Site: Copy the code examples above
- Customize: Apply your branding and theme
- Test: Verify games work in your environment
- Go Live: Deploy to production
Estimated Implementation Time: 1-4 hours
Option 2: MCAP Game Server Integration
Overview
Connect to MCAP's hosted game servers for Chess and Battleship. You create custom UIs while we handle game logic, anti-cheat, and real-time multiplayer infrastructure.
Benefits
- 🎮 Pre-built Games: Chess and Battleship ready to use
- 🔒 Anti-cheat: Built-in cheat prevention
- ⚡ Real-time: WebSocket-based instant updates
- 🎨 Custom UI: Full control over visual design
- ⚙️ Low Maintenance: We handle game logic updates
Quick Start
- Connect via WebSocket:
const ws = new WebSocket(`${MCAP_GAME_SERVER_URL}/ws?playerWalletAddress=${address}`);
- Authenticate with Session:
ws.send(JSON.stringify({
type: 'authenticate',
content: { sessionId, gameType: 'chess' }
}));
- Handle Game Messages:
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
// Update your UI based on message.type
};
- Send Game Actions:
// Chess move example
ws.send(JSON.stringify({
type: 'game_action',
gameId,
content: { action: 'make_move', from: 'e2', to: 'e4' }
}));
Estimated Implementation Time: 1-3 weeks
Option 3: Custom H2H Game Development (Under Development)
Overview
Build your own multiplayer games from scratch while leveraging MCAP's betting infrastructure for match creation, non-custodial fund management, and automated settlement.
Benefits
- 🎯 Full Control: Build any game type with custom rules
- 📈 Scalable: Handle unlimited concurrent players
- 💰 Revenue Share: Keep more revenue vs pre-built options
- 🔧 Flexible: Implement complex game mechanics
Quick Start
- Authenticate Users:
// Get nonce → User signs → Exchange for JWT
const { nonce } = await fetch('/v1/auth/nonce', { ... });
const signature = await wallet.signMessage(nonce);
const { access_token } = await fetch('/v1/auth/login', { ... });
- Create Sessions:
const { session_id } = await fetch('/v1/sessions', {
method: 'POST',
headers: { 'Authorization': `Bearer ${access_token}` },
body: JSON.stringify({ token_address, amount, provider_id, game_id })
});
- Manage Matches:
// Create match
const match = await fetch('/v1/user/multiplayer-bets/matches', {
method: 'POST',
body: JSON.stringify({ creator_session_id, wager })
});
// Join match
await fetch(`/v1/user/multiplayer-bets/matches/${matchId}/join`, {
method: 'POST',
body: JSON.stringify({ joiner_session_id })
});
// Settle match
await fetch(`/v1/user/multiplayer-bets/matches/${matchId}/settle`, {
method: 'POST',
body: JSON.stringify({ winner_session_id, is_draw })
});
- Implement Game Logic:
class GameManager {
async handlePlayerMove(matchId, playerId, moveData) {
// Validate move
// Update game state
// Check for win/draw
// Call settlement if game ended
}
}
Estimated Implementation Time: 2-8 weeks
Comparison Table
| Aspect | SDK/iframe | MCAP Servers | Custom Development |
|---|---|---|---|
| Development Time | 1-4 hours | 1-3 weeks | 2-8 weeks |
| Game Logic Control | Pre-built | Pre-built | Full control |
| UI Customization | Themes only | Full custom UI | Unlimited |
| Anti-cheat | Built-in | Built-in | You implement |
| Maintenance | Zero | Game logic only | Full maintenance |
| Technical Complexity | Very low | Medium | High |
| Revenue Share | Higher | Medium | Lower |
Getting Started
- Register as Provider: Get your API keys and provider ID
- Choose Integration: Pick the option that fits your needs
- Follow Documentation: Use the specific implementation guide
- Test Integration: Verify everything works in staging
- Go Live: Deploy to production
Support
- API Documentation: MCAP API Docs
- Provider Guide: Provider Onboarding
- Technical Support: support@mcap.ai
Core Integration Flow
1. Player Authentication & Session Creation
First, authenticate players and create gaming sessions:
// Step 1: Get authentication nonce
const nonceResponse = await fetch(`${MCAP_API_URL}/v1/auth/nonce`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
wallet_address: playerWallet,
provider_id: YOUR_PROVIDER_ID
})
});
// Step 2: Player signs the nonce with their wallet
const message = `Sign this message to authenticate with nonce: ${nonce}`;
const signature = await playerWallet.signMessage(message);
// Step 3: Login to get JWT tokens
const loginResponse = await fetch(`${MCAP_API_URL}/v1/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
wallet_address: playerWallet,
provider_id: YOUR_PROVIDER_ID,
signature,
nonce
})
});
const { access_token } = await loginResponse.json();
// Step 4: Create gaming session
const sessionResponse = await fetch(`${MCAP_API_URL}/v1/sessions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
token_id: SELECTED_TOKEN_ID,
game_id: YOUR_GAME_ID
})
});
const { session_id } = await sessionResponse.json();
2. Match Creation and Management
Use MCAP's multiplayer match endpoints to handle betting mechanics:
// Create a new H2H match
const createMatch = async (creatorSessionId: string, wager: string) => {
const response = await fetch(`${MCAP_API_URL}/v1/providers/multiplayer-bets/matches`, {
method: 'POST',
headers: {
'X-API-Key': YOUR_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
creator_id: playerWalletAddress,
session_id: creatorSessionId,
provider_id: YOUR_PROVIDER_ID,
game_type: 'your_custom_game',
game_id: YOUR_GAME_ID,
min_players: 2,
max_players: 2,
wager: wager, // Amount in wei
expiry_hours: 24
})
});
return await response.json();
};
// Join an existing match
const joinMatch = async (matchId: string, playerSessionId: string) => {
const response = await fetch(`${MCAP_API_URL}/v1/providers/multiplayer-bets/matches/${matchId}/join`, {
method: 'POST',
headers: {
'X-API-Key': YOUR_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
provider_id: YOUR_PROVIDER_ID,
session_id: playerSessionId
})
});
return await response.json();
};
// Start the match (locks funds)
const startMatch = async (matchId: string, creatorWalletId: string) => {
const response = await fetch(`${MCAP_API_URL}/v1/providers/multiplayer-bets/matches/${matchId}/start`, {
method: 'POST',
headers: {
'X-API-Key': YOUR_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
match_id: matchId,
wallet_id: creatorWalletId
})
});
return await response.json();
};
3. Game Logic Implementation
Implement your custom game mechanics. Here's a simplified example structure:
interface GameState {
matchId: string;
players: Player[];
currentTurn: string;
gameData: any; // Your custom game state
status: 'waiting' | 'in_progress' | 'finished';
}
class CustomH2HGame {
private gameState: GameState;
constructor(matchId: string) {
this.gameState = {
matchId,
players: [],
currentTurn: '',
gameData: {},
status: 'waiting'
};
}
// Handle player moves
async makeMove(playerId: string, moveData: any): Promise<boolean> {
// Validate move
if (!this.isValidMove(playerId, moveData)) {
return false;
}
// Apply move to game state
this.applyMove(playerId, moveData);
// Check for game end
const winner = this.checkGameEnd();
if (winner) {
await this.settleMatch(winner);
} else {
this.switchTurn();
}
// Broadcast state to all players
this.broadcastGameState();
return true;
}
// Your custom game logic methods
private isValidMove(playerId: string, moveData: any): boolean {
// Implement your validation logic
return true;
}
private applyMove(playerId: string, moveData: any): void {
// Apply the move to your game state
}
private checkGameEnd(): string | null {
// Return winner ID or null if game continues
return null;
}
private switchTurn(): void {
// Switch to next player's turn
}
}
4. Match Settlement
When the game ends, settle the match through MCAP smart contracts:
const settleMatch = async (matchId: string, winnerId: string, totalPot: string) => {
const payouts = [
{
player_id: winnerId,
amount: totalPot // Winner takes all (in wei)
},
{
player_id: loserId,
amount: "0" // Loser gets nothing (0 wei)
}
];
const response = await fetch(`${MCAP_API_URL}/v1/providers/multiplayer-bets/matches/${matchId}/settle`, {
method: 'POST',
headers: {
'X-API-Key': YOUR_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
match_id: matchId,
payouts
})
});
return await response.json();
};
// For draws, split the pot
const settleDraw = async (matchId: string, playerIds: string[], wagerAmount: string) => {
const payouts = playerIds.map(playerId => ({
player_id: playerId,
amount: wagerAmount // Each player gets their wager back
}));
// ... same settlement call with different payouts
};
Real-time Communication
For real-time gameplay, implement WebSocket connections:
// Server-side WebSocket handler (Node.js example)
import WebSocket from 'ws';
class GameWebSocketServer {
private wss: WebSocket.Server;
private games: Map<string, CustomH2HGame>;
constructor(port: number) {
this.wss = new WebSocket.Server({ port });
this.games = new Map();
this.setupHandlers();
}
private setupHandlers() {
this.wss.on('connection', (ws: WebSocket, req) => {
const playerId = req.url?.split('playerId=')[1];
ws.on('message', async (data) => {
const message = JSON.parse(data.toString());
switch (message.type) {
case 'join_game':
await this.handleJoinGame(ws, playerId, message.matchId);
break;
case 'make_move':
await this.handleMove(ws, playerId, message);
break;
}
});
});
}
private async handleMove(ws: WebSocket, playerId: string, message: any) {
const game = this.games.get(message.matchId);
if (game) {
const success = await game.makeMove(playerId, message.moveData);
ws.send(JSON.stringify({ type: 'move_result', success }));
}
}
}
Best Practices for Custom Development
1. State Synchronization
- Maintain authoritative game state on your server
- Validate all moves server-side
- Use optimistic updates on client with rollback capability
- Implement conflict resolution for simultaneous moves
2. Security Considerations
- Never trust client-side game state
- Validate session tokens on every game action
- Implement anti-cheat mechanisms
- Rate limit player actions
3. Error Handling
class GameErrorHandler {
static handleMatchError(error: any, matchId: string) {
if (error.code === 'INSUFFICIENT_FUNDS') {
// Handle insufficient balance
return { type: 'error', message: 'Insufficient funds to join match' };
}
if (error.code === 'MATCH_EXPIRED') {
// Handle expired match
return { type: 'error', message: 'Match has expired' };
}
// Log unexpected errors
console.error('Unexpected match error:', error);
return { type: 'error', message: 'An unexpected error occurred' };
}
}
4. Performance Optimization
- Implement connection pooling for MCAP API calls
- Cache session information with appropriate TTL
- Use batch operations where possible
- Implement proper database indexing for game state
Option 3: Custom H2H Game Development
Overview
MCAP hosts production-ready game servers for Chess and Battleship. You can connect to these servers via WebSocket and create custom UIs while we handle all game logic, anti-cheat, and real-time multiplayer infrastructure.
Supported Games
Chess
- Full chess rule implementation including castling, en passant
- Move validation and check/checkmate detection
- PGN notation support
- Tournament-ready
Battleship
- Classic 10x10 grid battleship
- Ship placement validation
- Hit/miss tracking
- Automatic win detection
Integration Architecture
graph TD
A[Your Custom UI] -->|WebSocket| B[MCAP Game Server]
B -->|Match Management| C[MCAP API]
B -->|Real-time Updates| A
C -->|Automated Settlement| D[Smart Contracts]
E[Player Wallets] -->|Deposits| D
D -->|Payouts| E
Connection Setup
1. Establish WebSocket Connection
// Connect to MCAP game server
const connectToGameServer = (playerWalletAddress: string) => {
const wsUrl = `${MCAP_GAME_SERVER_URL}/ws?playerWalletAddress=${playerWalletAddress}`;
const ws = new WebSocket(wsUrl);
ws.onopen = () => {
console.log('Connected to MCAP game server');
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
handleGameMessage(message);
};
return ws;
};
2. Authentication and Session Creation
Players still need to authenticate and create sessions as in Option 1, but the session is used by the MCAP game server:
// After getting session_id from authentication flow
const joinGameServer = (ws: WebSocket, sessionId: string, gameType: 'chess' | 'battleship') => {
ws.send(JSON.stringify({
type: 'authenticate',
content: {
sessionId: sessionId,
gameType: gameType
}
}));
};
Game-Specific Integration
Chess Integration
interface ChessGameState {
gameId: string;
matchId: string;
board: ChessPiece[][];
currentTurn: string;
moveHistory: ChessMove[];
gameStatus: 'waiting_for_players' | 'waiting_for_start' | 'player_turn' | 'opponent_turn' | 'game_over';
players: {
white: string;
black: string;
};
}
class ChessGameClient {
private ws: WebSocket;
private gameState: ChessGameState | null = null;
constructor(ws: WebSocket) {
this.ws = ws;
this.setupMessageHandlers();
}
// Create a new chess match
createMatch(sessionId: string, wager: string) {
this.ws.send(JSON.stringify({
type: 'game_action',
content: {
action: 'create_match',
sessionId,
wager
}
}));
}
// Join existing match
joinMatch(matchId: string, sessionId: string) {
this.ws.send(JSON.stringify({
type: 'game_action',
content: {
action: 'join_match',
matchId,
sessionId
}
}));
}
// Start the match (creator only)
startMatch(matchId: string, sessionId: string) {
this.ws.send(JSON.stringify({
type: 'game_action',
content: {
action: 'start_match',
matchId,
sessionId
}
}));
}
// Make a chess move
makeMove(gameId: string, from: string, to: string, promotion?: string) {
this.ws.send(JSON.stringify({
type: 'game_action',
gameId,
content: {
action: 'make_move',
from, // e.g., 'e2'
to, // e.g., 'e4'
promotion // 'Q', 'R', 'B', 'N' for pawn promotion
}
}));
}
// Resign from game
resign(gameId: string) {
this.ws.send(JSON.stringify({
type: 'game_action',
gameId,
content: {
action: 'resign'
}
}));
}
// Offer/accept/decline draw
offerDraw(gameId: string) {
this.ws.send(JSON.stringify({
type: 'game_action',
gameId,
content: {
action: 'offer_draw'
}
}));
}
private setupMessageHandlers() {
this.ws.onmessage = (event) => {
const message = JSON.parse(event.data);
switch (message.type) {
case 'match_created':
this.handleMatchCreated(message.content);
break;
case 'waiting_for_start':
this.handleWaitingForStart(message.content);
break;
case 'match_started':
this.handleMatchStarted(message.content);
break;
case 'move_made':
this.handleMoveMade(message.content);
break;
case 'game_ended':
this.handleGameEnded(message.content);
break;
case 'draw_offered':
this.handleDrawOffered(message.content);
break;
case 'error':
this.handleError(message.content);
break;
}
};
}
private handleMoveMade(content: any) {
// Update your UI with the new move
this.gameState = content;
this.renderChessBoard(content.board);
this.updateGameStatus(content.state);
if (content.isCheck) {
this.showCheckNotification();
}
}
private handleGameEnded(content: any) {
this.gameState = content;
if (content.isDraw) {
this.showDrawResult();
} else {
this.showWinnerResult(content.isWinner, content.settlement);
}
}
// Implement your UI update methods
private renderChessBoard(board: ChessPiece[][]) {
// Update your chess board UI
}
private updateGameStatus(status: string) {
// Update game status display
}
}
Battleship Integration
interface BattleshipGameState {
gameId: string;
matchId: string;
phase: 'placing_ships' | 'battle' | 'game_over';
currentTurn: string;
myBoard: BattleshipCell[][];
opponentBoard: BattleshipCell[][];
ships: Ship[];
gameStatus: string;
}
class BattleshipGameClient {
private ws: WebSocket;
private gameState: BattleshipGameState | null = null;
constructor(ws: WebSocket) {
this.ws = ws;
this.setupMessageHandlers();
}
// Place ships during setup phase
placeShip(gameId: string, shipType: string, positions: string[]) {
this.ws.send(JSON.stringify({
type: 'game_action',
gameId,
content: {
action: 'place_ship',
shipType, // 'carrier', 'battleship', 'cruiser', 'submarine', 'destroyer'
positions // ['A1', 'A2', 'A3', 'A4', 'A5'] for carrier
}
}));
}
// Confirm ship placement and ready for battle
confirmPlacement(gameId: string) {
this.ws.send(JSON.stringify({
type: 'game_action',
gameId,
content: {
action: 'confirm_placement'
}
}));
}
// Fire at opponent's board
fireShot(gameId: string, target: string) {
this.ws.send(JSON.stringify({
type: 'game_action',
gameId,
content: {
action: 'fire_shot',
target // e.g., 'B5'
}
}));
}
private setupMessageHandlers() {
this.ws.onmessage = (event) => {
const message = JSON.parse(event.data);
switch (message.type) {
case 'ship_placed':
this.handleShipPlaced(message.content);
break;
case 'placement_confirmed':
this.handlePlacementConfirmed(message.content);
break;
case 'battle_started':
this.handleBattleStarted(message.content);
break;
case 'shot_result':
this.handleShotResult(message.content);
break;
case 'game_ended':
this.handleGameEnded(message.content);
break;
}
};
}
private handleShotResult(content: any) {
const { target, result, isYourTurn } = content;
// Update board with hit/miss/sunk
this.updateBoardWithShot(target, result);
// Update turn indicator
this.updateTurnStatus(isYourTurn);
if (result === 'sunk') {
this.showShipSunkAnimation(content.sunkShip);
}
}
private updateBoardWithShot(target: string, result: 'hit' | 'miss' | 'sunk') {
// Update your battleship board UI
}
}
UI Development Best Practices
1. Responsive Design
/* Example responsive chess board */
.chess-board {
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-template-rows: repeat(8, 1fr);
aspect-ratio: 1;
max-width: min(80vw, 80vh);
margin: 0 auto;
}
.chess-square {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background-color 0.2s;
}
.chess-square.light {
background-color: #f0d9b5;
}
.chess-square.dark {
background-color: #b58863;
}
.chess-square.selected {
background-color: #646f40;
}
.chess-square.valid-move {
background-color: #fffacd;
}
2. Real-time Updates
// Handle real-time state synchronization
class GameStateManager {
private listeners: Map<string, Function[]> = new Map();
subscribe(event: string, callback: Function) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event)!.push(callback);
}
emit(event: string, data: any) {
const callbacks = this.listeners.get(event) || [];
callbacks.forEach(callback => callback(data));
}
updateGameState(newState: any) {
// Merge new state with existing state
this.gameState = { ...this.gameState, ...newState };
this.emit('stateChanged', this.gameState);
}
}
3. Error Handling and Reconnection
class RobustWebSocketClient {
private ws: WebSocket | null = null;
private reconnectAttempts = 0;
private maxReconnectAttempts = 5;
private reconnectInterval = 1000;
constructor(private url: string) {
this.connect();
}
private connect() {
try {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
this.reconnectAttempts = 0;
this.onConnected();
};
this.ws.onclose = () => {
this.attemptReconnect();
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
} catch (error) {
this.attemptReconnect();
}
}
private attemptReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
setTimeout(() => {
this.reconnectAttempts++;
this.connect();
}, this.reconnectInterval * Math.pow(2, this.reconnectAttempts));
}
}
send(data: any) {
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
} else {
console.warn('WebSocket not connected, message queued');
// Queue message for when connection is restored
}
}
}
For questions about H2H integration or to discuss your specific use case, reach out to our team at support@mcap.ai