WASTEDWAGERS

🏇 Horse Race Game

Copy the code below to use this horse racing mini-game

import React, { useRef, useEffect, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';

export default function HorseRaceGame({ horses, onWinner }) {
    const canvasRef = useRef(null);
    const [winner, setWinner] = useState(null);
    const gameRef = useRef({
        horses: [],
        isRacing: false,
        finishLine: 0
    });

    const horseColors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E2'];

    useEffect(() => {
        const canvas = canvasRef.current;
        const ctx = canvas.getContext('2d');
        const game = gameRef.current;

        game.finishLine = canvas.width - 100;

        // Initialize horses
        game.horses = horses.map((horse, i) => ({
            name: horse.kick_username,
            data: horse,
            x: 50,
            y: 80 + (i * 70),
            speed: 0,
            color: horseColors[i % horseColors.length],
            finished: false
        }));

        const drawTrack = () => {
            // Background
            ctx.fillStyle = '#2c5f2d';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            // Draw lanes
            game.horses.forEach((_, i) => {
                const y = 50 + (i * 70);
                ctx.strokeStyle = '#ffffff';
                ctx.lineWidth = 2;
                ctx.setLineDash([10, 10]);
                ctx.beginPath();
                ctx.moveTo(0, y);
                ctx.lineTo(canvas.width, y);
                ctx.stroke();
            });

            // Finish line
            ctx.setLineDash([]);
            ctx.strokeStyle = '#000000';
            ctx.lineWidth = 8;
            ctx.beginPath();
            ctx.moveTo(game.finishLine, 0);
            ctx.lineTo(game.finishLine, canvas.height);
            ctx.stroke();

            // Checkered pattern on finish line
            const squareSize = 20;
            for (let i = 0; i < canvas.height / squareSize; i++) {
                ctx.fillStyle = i % 2 === 0 ? '#000000' : '#ffffff';
                ctx.fillRect(game.finishLine - 4, i * squareSize, 8, squareSize);
            }
        };

        const drawHorse = (horse) => {
            ctx.save();
            ctx.translate(horse.x, horse.y);

            // Horse body
            ctx.fillStyle = horse.color;
            ctx.fillRect(0, 0, 40, 30);

            // Horse head
            ctx.fillRect(35, -10, 20, 20);

            // Legs
            ctx.fillRect(5, 30, 5, 15);
            ctx.fillRect(15, 30, 5, 15);
            ctx.fillRect(25, 30, 5, 15);
            ctx.fillRect(35, 30, 5, 15);

            // Name label
            ctx.fillStyle = '#000000';
            ctx.font = 'bold 12px Arial';
            ctx.fillText(horse.name, -10, -15);

            ctx.restore();
        };

        const animate = () => {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            drawTrack();

            game.horses.forEach(horse => {
                if (!horse.finished) {
                    // Random speed variation for realism
                    horse.speed = 2 + Math.random() * 3;
                    horse.x += horse.speed;

                    // Check if finished
                    if (horse.x >= game.finishLine) {
                        horse.x = game.finishLine;
                        horse.finished = true;
                        
                        if (!game.isRacing) {
                            game.isRacing = true;
                            setWinner(horse);
                            if (onWinner) onWinner(horse.data);
                        }
                    }
                }

                drawHorse(horse);
            });

            if (!game.horses.every(h => h.finished)) {
                requestAnimationFrame(animate);
            }
        };

        // Start race after 2 seconds
        setTimeout(() => {
            animate();
        }, 2000);

    }, [horses, onWinner]);

    return (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/90">
            <div className="bg-gradient-to-b from-green-800 to-green-900 p-6 rounded-2xl border-4 border-yellow-400 shadow-2xl max-w-6xl w-full mx-4">
                <h2 className="text-3xl font-bold text-center text-yellow-400 mb-4">🏇 HORSE RACE 🏇</h2>
                
                <canvas
                    ref={canvasRef}
                    width={1000}
                    height={horses.length * 70 + 50}
                    className="w-full rounded-lg border-2 border-yellow-600"
                />

                <AnimatePresence>
                    {winner && (
                        <motion.div
                            initial={{ opacity: 0, scale: 0.8 }}
                            animate={{ opacity: 1, scale: 1 }}
                            className="mt-6 text-center bg-gradient-to-r from-yellow-500 to-orange-500 p-6 rounded-lg"
                        >
                            <h3 className="text-4xl font-bold text-white mb-2">🏆 WINNER! 🏆</h3>
                            <p className="text-3xl text-white font-bold">{winner.name}</p>
                        </motion.div>
                    )}
                </AnimatePresence>
            </div>
        </div>
    );
}

How to Use:

  • • This component creates a visual horse race game
  • • Pass in an array of participant objects as the horses prop
  • • The onWinner callback fires when a horse crosses the finish line
  • • Each horse moves at a random speed for realistic racing
  • • The game automatically starts 2 seconds after mounting

Example Usage:

import HorseRaceGame from './HorseRaceGame';

const participants = [
  { kick_username: 'Player1', tier: 'vip' },
  { kick_username: 'Player2', tier: 'supporter' },
  // ... more participants
];

<HorseRaceGame 
  horses={participants} 
  onWinner={(winner) => {
    console.log('Winner:', winner);
  }} 
/>