🎮ArcadeLab

Track Legends

by CosmicMaker16
811 lines13.2 KB
▶ Play
<!DOCTYPE html>
<html>
<head>
    <title>Track Legends</title>

    <style>
        body {
            margin: 0;
            background: #07111f;
            color: white;
            font-family: Arial, sans-serif;
            text-align: center;
        }

        h1 {
            font-size: 40px;
        }

        #game {
            max-width: 1000px;
            margin: auto;
            padding: 20px;
        }

        #stats {
            display: flex;
            justify-content: center;
            gap: 15px;
            flex-wrap: wrap;
            margin-bottom: 20px;
        }

        .stat {
            background: #12243b;
            padding: 12px 18px;
            border-radius: 10px;
        }

        #track {
            position: relative;
            height: 300px;
            background: linear-gradient(
                #68b5ed 0%,
                #68b5ed 35%,
                #65a94e 35%,
                #65a94e 50%,
                #b8493c 50%,
                #b8493c 100%
            );
            border-radius: 15px;
            overflow: hidden;
        }

        .lane {
            position: absolute;
            left: 0;
            width: 100%;
            border-top: 3px solid white;
        }

        .lane1 { top: 100px; }
        .lane2 { top: 150px; }
        .lane3 { top: 200px; }

        #finish {
            position: absolute;
            right: 35px;
            top: 70px;
            height: 180px;
            width: 10px;

            background: repeating-linear-gradient(
                to bottom,
                white 0px,
                white 15px,
                black 15px,
                black 30px
            );
        }

        #runner {
            position: absolute;
            left: 25px;
            top: 110px;
            font-size: 45px;
            transform: scaleX(-1);
        }

        #bar {
            width: 100%;
            height: 20px;
            background: #172b44;
            margin-top: 15px;
            border-radius: 20px;
            overflow: hidden;
        }

        #progress {
            height: 100%;
            width: 0%;
            background: #35e57d;
        }

        button {
            background: #278cff;
            color: white;
            border: none;
            padding: 12px 20px;
            border-radius: 10px;
            margin: 5px;
            cursor: pointer;
            font-weight: bold;
        }

        button:hover {
            filter: brightness(1.15);
        }

        button:disabled {
            opacity: .4;
            cursor: not-allowed;
        }

        .upgrade-container {
            display: flex;
            justify-content: center;
            flex-wrap: wrap;
            gap: 15px;
        }

        .upgrade {
            background: #12243b;
            padding: 18px;
            border-radius: 12px;
            width: 220px;
        }

        #message {
            font-size: 20px;
            min-height: 30px;
            margin: 15px;
        }

        #controls {
            font-size: 18px;
            margin: 10px;
        }
    </style>
</head>

<body>

<div id="game">

    <h1>🏃 TRACK LEGENDS</h1>

    <div id="stats">
        <div class="stat">💰 $<span id="money">100</span></div>
        <div class="stat">⚡ Speed <span id="speed">1.00</span>x</div>
        <div class="stat">🏆 Wins <span id="wins">0</span></div>
        <div class="stat">🌎 <span id="rank">Local</span></div>
    </div>

    <div id="controls">
        <b>ALTERNATE ← LEFT AND RIGHT → AS FAST AS YOU CAN!</b>
    </div>

    <div id="track">

        <div class="lane lane1"></div>
        <div class="lane lane2"></div>
        <div class="lane lane3"></div>

        <div id="finish"></div>

        <div id="runner">🏃</div>

    </div>

    <div id="bar">
        <div id="progress"></div>
    </div>

    <div id="message">
        Press START RACE!
    </div>

    <button id="startButton" onclick="startRace()">
        START RACE
    </button>

    <button onclick="resetRace()">
        RESET
    </button>


    <div class="card">

        <h2>⚙️ UPGRADES</h2>

        <div class="upgrade-container">

            <div class="upgrade">
                <h3>👟 Sprint Shoes</h3>
                <p>Increase your running power.</p>

                <button id="shoeButton" onclick="buyShoes()">
                    Buy $<span id="shoeCost">75</span>
                </button>

                <p>Level: <span id="shoeLevel">0</span></p>
            </div>


            <div class="upgrade">
                <h3>💪 Training</h3>
                <p>Increase your base speed.</p>

                <button id="trainingButton" onclick="buyTraining()">
                    Buy $<span id="trainingCost">100</span>
                </button>

                <p>Level: <span id="trainingLevel">0</span></p>
            </div>


            <div class="upgrade">
                <h3>🔥 Adrenaline</h3>
                <p>Make every alternating press stronger.</p>

                <button id="adrenalineButton" onclick="buyAdrenaline()">
                    Buy $<span id="adrenalineCost">150</span>
                </button>

                <p>Level: <span id="adrenalineLevel">0</span></p>
            </div>

        </div>

    </div>


    <div class="card">

        <h2>🏟️ CAREER</h2>

        <p>
            Local Meets →
            <span id="local">🔒</span>
        </p>

        <p>
            Regional Finals →
            <span id="regional">🔒</span>
        </p>

        <p>
            Elite Championships →
            <span id="elite">🔒</span>
        </p>

        <p>
            Olympic Games →
            <span id="olympic">🔒</span>
        </p>

        <button id="olympicButton"
                onclick="startOlympics()"
                disabled>

            🏅 OLYMPICS LOCKED

        </button>

    </div>

</div>


<script>

/* =========================
   GAME VARIABLES
========================= */

let money = 100;

let wins = 0;

let running = false;

let distance = 0;

let runPower = 0;

let lastKey = "";

let raceStartTime = 0;

let raceType = "normal";


/* UPGRADES */

let shoeLevel = 0;

let trainingLevel = 0;

let adrenalineLevel = 0;


/* =========================
   ELEMENTS
========================= */

const runner = document.getElementById("runner");

const progressBar =
    document.getElementById("progress");

const message =
    document.getElementById("message");

const startButton =
    document.getElementById("startButton");


/* =========================
   SPEED
========================= */

function getSpeed() {

    return (
        1
        + trainingLevel * 0.15
        + shoeLevel * 0.10
        + adrenalineLevel * 0.08
    );

}


/* =========================
   START RACE
========================= */

function startRace() {

    if (running) return;

    running = true;

    distance = 0;

    runPower = 0;

    lastKey = "";

    raceStartTime = performance.now();

    startButton.disabled = true;

    message.innerHTML =
        "🔥 GO! Alternate LEFT and RIGHT!";

    gameLoop();

}


/* =========================
   GAME LOOP
========================= */

function gameLoop() {

    if (!running) return;


    /*
        IMPORTANT:

        The runner DOES NOT move automatically.

        runPower only increases when
        the player correctly alternates
        left and right.
    */

    if (runPower > 0) {

        let movement =
            runPower * getSpeed();

        distance += movement;

        /*
            Slowly lose speed if the player
            stops pressing keys.
        */

        runPower *= 0.94;

    }


    /*
        Convert distance to percentage.
    */

    let percent =
        Math.min(distance, 100);


    progressBar.style.width =
        percent + "%";


    /*
        Move runner.

        Track width is 1000-ish, so
        we calculate position based on %.
    */

    let trackWidth =
        document.getElementById("track").clientWidth;

    let maxPosition =
        trackWidth - 100;

    let position =
        25 + (percent / 100) * maxPosition;

    runner.style.left =
        position + "px";


    /*
        Finish
    */

    if (distance >= 100) {

        finishRace();

        return;

    }


    requestAnimationFrame(gameLoop);

}


/* =========================
   ARROW KEYS
========================= */

document.addEventListener("keydown", function(event) {

    if (!running) return;


    if (
        event.key !== "ArrowLeft" &&
        event.key !== "ArrowRight"
    ) {
        return;
    }


    event.preventDefault();


    /*
        Only alternating arrows
        increase speed.

        LEFT → RIGHT → LEFT → RIGHT
    */

    if (event.key !== lastKey) {

        runPower +=
            0.75 + adrenalineLevel * 0.12;

        lastKey = event.key;


        /*
            Small visual bounce
        */

        runner.style.transform =
            "scaleX(-1) translateY(-5px)";

        setTimeout(() => {

            runner.style.transform =
                "scaleX(-1) translateY(0)";

        }, 60);

    }

});


/* =========================
   FINISH
========================= */

function finishRace() {

    running = false;

    let finishTime =
        (performance.now() - raceStartTime) / 1000;


    wins++;


    let reward =
        50 + Math.floor(
            Math.max(0, 100 - finishTime * 8)
        );


    /*
        Olympics gives bigger rewards.
    */

    if (raceType === "olympic") {

        reward *= 5;

    }


    money += reward;


    startButton.disabled = false;


    message.innerHTML =
        "🏁 FINISH! " +
        finishTime.toFixed(2) +
        " seconds — 💰 +$" +
        reward;


    updateGame();

}


/* =========================
   RESET
========================= */

function resetRace() {

    running = false;

    distance = 0;

    runPower = 0;

    lastKey = "";

    progressBar.style.width = "0%";

    runner.style.left = "25px";

    startButton.disabled = false;

    message.innerHTML =
        "Press START RACE!";

}


/* =========================
   SHOES
========================= */

function shoeCost() {

    return Math.floor(
        75 * Math.pow(1.6, shoeLevel)
    );

}


function buyShoes() {

    let cost = shoeCost();

    if (money < cost) return;

    money -= cost;

    shoeLevel++;

    updateGame();

}


/* =========================
   TRAINING
========================= */

function trainingCost() {

    return Math.floor(
        100 * Math.pow(1.6, trainingLevel)
    );

}


function buyTraining() {

    let cost = trainingCost();

    if (money < cost) return;

    money -= cost;

    trainingLevel++;

    updateGame();

}


/* =========================
   ADRENALINE
========================= */

function adrenalineCost() {

    return Math.floor(
        150 * Math.pow(1.6, adrenalineLevel)
    );

}


function buyAdrenaline() {

    let cost = adrenalineCost();

    if (money < cost) return;

    money -= cost;

    adrenalineLevel++;

    updateGame();

}


/* =========================
   OLYMPICS
========================= */

function startOlympics() {

    if (wins < 5) return;

    raceType = "olympic";

    resetRace();

    message.innerHTML =
        "🏅 OLYMPIC FINAL! GET READY!";

}


/* =========================
   UPDATE UI
========================= */

function updateGame() {

    document.getElementById("money")
        .textContent = Math.floor(money);

    document.getElementById("wins")
        .textContent = wins;

    document.getElementById("speed")
        .textContent =
        getSpeed().toFixed(2);


    document.getElementById("shoeLevel")
        .textContent = shoeLevel;

    document.getElementById("trainingLevel")
        .textContent = trainingLevel;

    document.getElementById("adrenalineLevel")
        .textContent = adrenalineLevel;


    document.getElementById("shoeCost")
        .textContent = shoeCost();

    document.getElementById("trainingCost")
        .textContent = trainingCost();

    document.getElementById("adrenalineCost")
        .textContent = adrenalineCost();


    /*
        RANK
    */

    let rank = "Local";

    if (wins >= 10)
        rank = "Elite";

    else if (wins >= 5)
        rank = "Regional";

    else if (wins >= 2)
        rank = "Rookie";


    if (wins >= 15)
        rank = "Olympian";


    document.getElementById("rank")
        .textContent = rank;


    /*
        CAREER
    */

    document.getElementById("local")
        .textContent =
        wins >= 1 ? "✅" : "🔒";


    document.getElementById("regional")
        .textContent =
        wins >= 2 ? "✅" : "🔒";


    document.getElementById("elite")
        .textContent =
        wins >= 10 ? "✅" : "🔒";


    document.getElementById("olympic")
        .textContent =
        wins >= 5 ? "🏅 UNLOCKED" : "🔒";


    /*
        OLYMPIC BUTTON
    */

    let olympicButton =
        document.getElementById("olympicButton");


    if (wins >= 5) {

        olympicButton.disabled = false;

        olympicButton.innerHTML =
            "🏅 ENTER OLYMPICS";

    } else {

        olympicButton.disabled = true;

        olympicButton.innerHTML =
            "🏅 WIN " +
            (5 - wins) +
            " MORE RACES";

    }

}


/* START */

updateGame();

</script>

</body>
</html>

Game Source: Track Legends

Creator: CosmicMaker16

Libraries: none

Complexity: complex (811 lines, 13.2 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: track-legends-cosmicmaker16" to link back to the original. Then publish at arcadelab.ai/publish.