Josh Bruce Online

Bong - Multiplayer Pong Game Documentation

Overview

A real-time multiplayer Pong game featuring Firebase-powered matchmaking, spectator support, and synchronized gameplay. Players join a queue system and are automatically matched for competitive Pong matches with live spectator viewing capabilities.

Technical Architecture

Core Technologies

File Structure

bong/
└── index.html    # Complete multiplayer Pong game

Firebase Integration

Database Configuration

const firebaseConfig = {
    apiKey: "AIzaSyALJtZBGc540MEHi_e67P3qgOKJGxxbpiw",
    authDomain: "joshbruceonline-pong.firebaseapp.com",
    databaseURL: "https://joshbruceonline-pong-default-rtdb.europe-west1.firebasedatabase.app",
    projectId: "joshbruceonline-pong",
    storageBucket: "joshbruceonline-pong.appspot.com",
    messagingSenderId: "296966054099",
    appId: "1:296966054099:web:df08fa55967e7aa5253426"
};

Database Structure

// Firebase Realtime Database schema
{
  "pong-game": {
    "players": {
      "[playerId]": {
        "name": "Player ABC",
        "score": 0
      }
    },
    "games": {
      "[gameId]": {
        "player1": { "name": "Player 1", "score": 0 },
        "player2": { "name": "Player 2", "score": 0 },
        "gameStarted": false,
        "ball": { "x": 300, "y": 300, "radius": 10, "dx": 2, "dy": 2 },
        "paddle1": { "x": 10, "y": 250, "width": 10, "height": 100, "dy": 5, "score": 0 },
        "paddle2": { "x": 580, "y": 250, "width": 10, "height": 100, "dy": 5, "score": 0 }
      }
    }
  }
}

Game Mechanics

Core Game Constants

// Game configuration
const GAME_WIDTH = 600;
const GAME_HEIGHT = 600;
const WIN_SCORE = 11;           // First to 11 points wins
const COUNTDOWN_DURATION = 3000; // 3-second countdown
const GAME_TIMEOUT = 60000;     // 1-minute cleanup timer

Pong Physics Engine

// Ball movement and collision detection
function updateGameObjects(game) {
    var ball = game.ball;
    var paddle1 = game.paddle1;
    var paddle2 = game.paddle2;

    // Update ball position
    ball.x += ball.dx;
    ball.y += ball.dy;

    // Paddle collision detection
    if (ball.y + ball.radius > paddle1.y &&
        ball.y - ball.radius < paddle1.y + paddle1.height &&
        ball.dx < 0) {
        ball.dx *= -1;  // Reverse X direction
    }

    // Wall collision detection
    if (ball.y + ball.radius > GAME_HEIGHT || ball.y - ball.radius < 0) {
        ball.dy *= -1;  // Reverse Y direction
    }

    // Scoring detection
    if (ball.x - ball.radius < 0) {
        paddle2.score++;  // Player 2 scores
        resetBall();
    }
    if (ball.x + ball.radius > GAME_WIDTH) {
        paddle1.score++;  // Player 1 scores
        resetBall();
    }
}

Multiplayer System

Player Queue Management

// Automatic player addition to queue
function addPlayer() {
    var newPlayerRef = playersRef.push();
    playerId = newPlayerRef.key;
    newPlayerRef.set({
        name: 'Player ' + playerId.substr(-3),  // Generate display name
        score: 0
    });
}

// Matchmaking system
function dequeueAndJoinGame() {
    playersRef.once('value', function(snapshot) {
        var players = snapshot.val();
        var playerIds = Object.keys(players);
        var nextPlayers = playerIds.slice(0, 2);  // Take first 2 players
        
        if (nextPlayers.length === 2) {
            createGameSession(nextPlayers, players);
            startCountdown();
        }
    });
}

Real-time Game Synchronization

// Synchronized game loop
function gameLoop() {
    gameRef.on('value', function(snapshot) {
        var game = snapshot.val();
        updateGameObjects(game);  // Update physics
        drawGameObjects(game);    // Render frame
        
        if (game.gameStarted) {
            requestAnimationFrame(gameLoop);  // Continue loop
        }
    });
}

Control System

Dual Input Support

// Keyboard controls for both players
function handleKeyDown(event) {
    if (event.key === 'w' || event.key === 'ArrowUp') {
        arrowUpKey = true;
    } else if (event.key === 's' || event.key === 'ArrowDown') {
        arrowDownKey = true;
    }
}

// Player-specific paddle movement
if (playerId === 'player1') {
    if (arrowUpKey && paddle1.y > 0) {
        paddle1.y -= paddle1.dy;  // Move up
    }
    if (arrowDownKey && paddle1.y + paddle1.height < GAME_HEIGHT) {
        paddle1.y += paddle1.dy;  // Move down
    }
}

Input Mapping

Visual System

Canvas Rendering

// Game object rendering
function drawGameObjects(game) {
    var ball = game.ball;
    var paddle1 = game.paddle1;
    var paddle2 = game.paddle2;

    // Clear previous frame
    ctx.clearRect(0, 0, GAME_WIDTH, GAME_HEIGHT);

    // Draw ball
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
    ctx.fillStyle = '#333';
    ctx.fill();
    ctx.closePath();

    // Draw paddles
    ctx.fillStyle = '#333';
    ctx.fillRect(paddle1.x, paddle1.y, paddle1.width, paddle1.height);
    ctx.fillRect(paddle2.x, paddle2.y, paddle2.width, paddle2.height);

    // Draw scores
    ctx.font = '30px Arial';
    ctx.fillText(paddle1.score, GAME_WIDTH / 4, 50);
    ctx.fillText(paddle2.score, (3 * GAME_WIDTH) / 4, 50);
}

UI Design System

/* Game layout */
body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #222;
    color: #fff;
    font-family: Arial, sans-serif;
}

#game-container {
    width: 600px;
    height: 600px;
    background-color: #f1f1f1;
    float: left;
    margin-right: 200px;
}

/* Countdown display */
#countdown {
    font-size: 300px;
    font-weight: bold;
    text-align: center;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: red;
    z-index: 999;
    display: none;
}

Spectator System

Live Spectator List

// Real-time spectator tracking
function updateSpectatorsList(players) {
    spectatorsList.innerHTML = '';
    for (var playerId in players) {
        var listItem = document.createElement('li');
        listItem.classList.add('spectator-item');
        var playerName = players[playerId].name;
        listItem.innerText = playerName;
        spectatorsList.appendChild(listItem);
    }
}

// Listen for player queue changes
playersRef.on('value', function(snapshot) {
    var players = snapshot.val();
    updateSpectatorsList(players);  // Update spectator display
});

Spectator Features

Game Flow Management

Pre-Game Countdown

function startCountdown() {
    var countdownElement = document.getElementById('countdown');
    countdownElement.style.display = 'block';

    var countdown = 3;
    var countdownInterval = setInterval(function() {
        if (countdown === 0) {
            clearInterval(countdownInterval);
            countdownElement.style.display = 'none';
            gameRef.child('gameStarted').set(true);  // Start game
            startGame();
        } else {
            countdownElement.innerText = countdown;
            countdown--;
        }
    }, 1000);
}

Game Completion

function endGame() {
    gameStarted = false;
    var winningPlayer = game.paddle1.score === WIN_SCORE ? 'Player 1' : 'Player 2';
    alert(winningPlayer + ' wins!');
    removePlayer();

    // Cleanup game data after timeout
    setTimeout(function() {
        gamesRef.child(gameId).remove();
    }, GAME_TIMEOUT);
}

Performance Optimizations

Efficient Frame Updates

// Optimized game loop with requestAnimationFrame
function gameLoop() {
    gameRef.on('value', function(snapshot) {
        var game = snapshot.val();
        updateGameObjects(game);
        drawGameObjects(game);
        
        if (game.gameStarted) {
            requestAnimationFrame(gameLoop);  // 60fps targeting
        }
    });
}

Memory Management

Real-time Features

Synchronized Physics

Network Optimization

// Efficient Firebase queries
playersRef.once('value', function(snapshot) {
    // Single read for matchmaking
});

gameRef.on('value', function(snapshot) {
    // Real-time game state updates
});

Security Considerations

Data Validation

Firebase Security

Browser Compatibility

Supported Features

Performance Requirements

User Experience

Onboarding Flow

  1. Automatic Entry: Players join queue immediately
  2. Queue Display: See waiting players in spectator list
  3. Matchmaking: Automatic pairing when 2+ players available
  4. Countdown: 3-second preparation period
  5. Gameplay: Competitive Pong match to 11 points

Accessibility Features

/* High contrast game elements */
.game-container {
    background-color: #f1f1f1;  /* Light background */
}

/* Clear paddle and ball visibility */
ctx.fillStyle = '#333';  /* Dark game objects */

Competitive Features

Scoring System

Fair Play Mechanics

Future Enhancement Opportunities

Gameplay Features

  1. Power-ups: Special abilities and bonuses
  2. Difficulty Levels: Variable ball speed settings
  3. Tournament Mode: Bracket-based competitions
  4. Custom Rooms: Private match creation
  5. Replay System: Game recording and playback

Technical Improvements

  1. Lag Compensation: Client-side prediction
  2. Reconnection: Automatic game rejoin
  3. Mobile Controls: Touch-based paddle control
  4. Sound Effects: Audio feedback for collisions
  5. Visual Effects: Enhanced graphics and animations

Social Features

  1. Player Profiles: Persistent user accounts
  2. Leaderboards: Global ranking system
  3. Friends System: Social connections
  4. Chat Integration: In-game communication
  5. Statistics: Match history and performance metrics

Code Quality Assessment

Strengths

Areas for Enhancement

Conclusion

Bong represents an impressive implementation of real-time multiplayer Pong with sophisticated Firebase integration. The automatic matchmaking, spectator system, and synchronized gameplay create an engaging competitive gaming experience. The technical architecture demonstrates strong understanding of real-time web applications and multiplayer game development.

Technical Rating: 8.7/10