Zurück zum Blog
Tutorial7 Min. Lesezeit

FiveM-Rennsystem: Strecken, Ranglisten und Wetten

Füge deinem FiveM-Server Straßenrennen hinzu. Streckenbau, Kontrollpunkte, Wetten, Ranglisten und die besten Rennskripte für ambitionierte Tuning-Communitys.

Agency Scripts

Gründer und leitender Entwickler bei Agency Scripts

Das Rennen-Erstellungssystem entwerfen

Ein überzeugendes Straßenrennsystem beginnt damit, dass Spieler ihre eigenen Rennstrecken erstellen und verwalten können. Statt sich ausschließlich auf vorgegebene Strecken zu verlassen, bieten die besten Rennskripte Organisatoren die Möglichkeit, Kontrollpunkte dynamisch zu platzieren, indem sie eine Strecke abfahren und dabei Positionen markieren. Speichere jedes Rennen als Datenstruktur mit einer eindeutigen Kennung, der Spieler-ID des Erstellers, einem Namen, einer sortierten Liste der Kontrollpunktkoordinaten samt Richtungswinkeln und Metadaten wie Distanz und geschätzter Rundenzeit. Die Erstellung sollte intuitiv sein: Der Spieler wechselt in den Renneditor-Modus, fährt zu jedem Kontrollpunkt, bestätigt dessen Platzierung mit einem Tastendruck und beendet die Erstellung, indem er zur Startlinie zurückkehrt. Speichere fertige Rennen in deiner Datenbank, damit sie Serverneustarts überstehen und mit der Community geteilt werden können. Implementiere ein Prüfsystem, in dem Admins von Spielern erstellte Strecken genehmigen können, bevor sie in der öffentlichen Rennliste erscheinen. So verhinderst du Trolling durch unmögliche oder unfaires Streckendesign.

Kontrollpunktsystem und Rennlogik

Kontrollpunkte sind die zentrale Spielmechanik, die den Rennfortschritt überprüft und Abkürzungen verhindert. Definiere jeden Kontrollpunkt als 3D-Zone mit einem konfigurierbaren Radius, üblicherweise zwischen 8 und 15 Metern, abhängig von der Straßenbreite. Verwende die nativen GTA-Funktionen zum Zeichnen von Markern, um Kontrollpunkte sichtbar darzustellen. Hebe den aktuellen Kontrollpunkt farblich hervor und zeige den nächsten als transparente Vorschau an. Verfolge den Fortschritt jedes Rennfahrers über eine indizierte Kontrollpunktliste und lasse ihn nur dann vorrücken, wenn er die nächste Kontrollpunktzone in der richtigen Reihenfolge betritt. Implementiere Anti-Cheat-Maßnahmen, indem du die Zeit zwischen Kontrollpunkten erfasst und Rennfahrer markierst oder disqualifizierst, die Streckenabschnitte in unmöglich kurzer Zeit absolvieren. Das weist auf Teleportation oder Speedhacking hin.

-- Client-side checkpoint detection
local currentCheckpoint = 1
local raceCheckpoints = {} -- populated when race starts

CreateThread(function()
    while isRacing do
        local playerCoords = GetEntityCoords(PlayerPedId())
        local checkpoint = raceCheckpoints[currentCheckpoint]

        if checkpoint then
            local dist = #(playerCoords - checkpoint.coords)

            -- Draw current checkpoint marker
            DrawMarker(1, checkpoint.coords.x, checkpoint.coords.y,
                checkpoint.coords.z - 1.0, 0, 0, 0, 0, 0, 0,
                checkpoint.radius * 2, checkpoint.radius * 2, 2.0,
                45, 212, 191, 120, false, true, 2, false, nil, nil, false)

            if dist < checkpoint.radius then
                PlaySoundFrontend(-1, 'CHECKPOINT_NORMAL', 'HUD_MINI_GAME_SOUNDSET', true)
                currentCheckpoint = currentCheckpoint + 1

                if currentCheckpoint > #raceCheckpoints then
                    -- Race finished
                    local finishTime = GetGameTimer() - raceStartTime
                    TriggerServerEvent('racing:finished', raceId, finishTime)
                    isRacing = false
                else
                    -- Notify server of checkpoint progress
                    TriggerServerEvent('racing:checkpoint', raceId, currentCheckpoint)
                end
            end
        end
        Wait(50)
    end
end)

Bestenlisten- und Rangsystem

Bestenlisten fördern den Wettbewerb und sorgen dafür, dass Spieler zurückkommen, um ihre Zeiten zu verbessern. Speichere Rennergebnisse in einer Datenbanktabelle mit der Spielerkennung, der Renn-ID, der Abschlusszeit in Millisekunden, dem verwendeten Fahrzeugmodell, dem Datum und der Angabe, ob es sich um eine persönliche Bestzeit handelt. Zeige Bestenlisten über eine NUI-Oberfläche an, die die schnellsten Zeiten pro Strecke aufführt und nach Fahrzeugklasse gefiltert werden kann, damit Spieler fair in Kategorien wie Sportwagen, Supersportwagen, Muscle Cars oder Kompaktwagen vergleichen können. Implementiere ein saisonales Rangsystem, das regelmäßig zurückgesetzt wird, damit der Wettbewerb spannend bleibt, und führe gleichzeitig eine Bestenliste mit allen bisherigen Rekorden für langfristige Bestleistungen. Berechne eine ELO-ähnliche Rennwertung anhand der direkten Leistungen bei Mehrspielerrennen. So erhalten erfahrene Rennfahrer einen sichtbaren Rang, der steigt, wenn sie höher eingestufte Gegner schlagen, und sinkt, wenn sie gegen niedriger eingestufte Gegner verlieren. Zeige diese Wertung in der Rennoberfläche an und verwende sie optional für die Spielersuche bei zufällig zusammengestellten Rennen.

Wetten und Preisgelder

Ein Wettsystem bringt finanzielle Einsätze in Rennen und verknüpft die Rennszene mit der übrigen Wirtschaft deines Servers. Ermögliche Rennveranstaltern, ein Startgeld festzulegen, das alle Teilnehmer bezahlen müssen. Der gesamte Topf wird gemäß einer konfigurierbaren Aufteilung wie 70-20-10 für den ersten, zweiten und dritten Platz verteilt. Implementiere ein Wettsystem für Zuschauer, bei dem Spieler, die nicht am Rennen teilnehmen, auf den Ausgang setzen und einen Rennfahrer auswählen können, den sie unterstützen. Wickele alle Finanztransaktionen ausschließlich serverseitig ab, um Exploits zu verhindern. Erhebe auf alle Wetten einen Anteil von 5-10% als Geldsenke für deine Wirtschaft. Bei größeren organisierten Veranstaltungen können Admins zusätzliche Preisgelder aus der Serverkasse bereitstellen. Verfolge die Wettstatistiken pro Spieler, um Absprachen zu erkennen und zu verhindern, etwa wenn ein Rennfahrer regelmäßig Rennen verliert, auf die hohe Beträge gesetzt wurden.

-- Server-side betting handler
local raceBets = {}

RegisterNetEvent('racing:placeBet')
AddEventHandler('racing:placeBet', function(raceId, targetRacerId, amount)
    local src = source
    if not activeRaces[raceId] then return end
    if activeRaces[raceId].state ~= 'lobby' then
        return notify(src, 'Betting is closed once the race starts.', 'error')
    end

    -- Validate the target racer is in this race
    local racerFound = false
    for _, racer in ipairs(activeRaces[raceId].participants) do
        if racer.src == targetRacerId then racerFound = true break end
    end
    if not racerFound then return end

    -- Check and deduct funds
    local playerMoney = GetPlayerMoney(src)
    if playerMoney < amount or amount < Config.MinBet then
        return notify(src, 'Insufficient funds or below minimum bet.', 'error')
    end

    RemoveMoney(src, amount)

    if not raceBets[raceId] then raceBets[raceId] = {} end
    table.insert(raceBets[raceId], {
        bettor = src,
        target = targetRacerId,
        amount = amount,
    })

    notify(src, ('Bet $%s on %s'):format(amount, GetPlayerName(targetRacerId)), 'success')
end)

Renn-UI mit NUI erstellen

Die Renn-UI muss wichtige Echtzeitinformationen vermitteln, ohne den Bildschirm zu überladen oder den Fahrer abzulenken. Entwirf ein minimalistisches HUD, das die aktuelle Platzierung unter den Rennfahrern, gegebenenfalls die Rundennummer, einen Zwischenzeitmesser zum Vergleich des aktuellen Laufs mit der persönlichen Bestzeit oder dem Streckenrekord sowie eine Minimap-Einblendung mit der Richtung des nächsten Checkpoints anzeigt. Verwende einen zum Rennthema passenden Tacho, der die Geschwindigkeit je nach Spielereinstellung in mph oder km/h anzeigt. Auf dem Lobby-Bildschirm vor dem Rennen sollten alle angemeldeten Teilnehmer mit ihren Fahrzeugen, der Streckenname und die Streckenlänge, die Aufschlüsselung des Preisgelds und ein Countdown-Timer angezeigt werden. Erstelle die UI mit HTML, CSS und JavaScript über das NUI-System und übermittle Rennstatus-Updates vom clientseitigen Lua an den NUI-Frame über SendNUIMessage. Halte die UI reaktionsschnell, indem du Positionsupdates auf 4-5 Mal pro Sekunde begrenzt, anstatt sie in jedem Frame zu übertragen. So wird der NUI-Overhead deutlich reduziert, ohne dass die angezeigten Informationen sichtbar beeinträchtigt werden. Erwäge, nach dem Rennen einen Ergebnisbildschirm mit detaillierten Statistiken wie der erreichten Höchstgeschwindigkeit, der Durchschnittsgeschwindigkeit und dem Zeitvergleich pro Checkpoint-Abschnitt hinzuzufügen.

Rennkategorien und Fahrzeugklassen

Organisiere Rennen in verschiedene Kategorien, um faire Wettkämpfe und Abwechslung zu ermöglichen. Definiere Fahrzeugklassen anhand von Leistungskennzahlen wie Höchstgeschwindigkeit, Beschleunigung und Handling-Werten aus den nativen Handling-Daten des Spiels. Lege für bestimmte Rennen Klassenbeschränkungen fest, damit ein Spieler mit einem Dominator nicht an einem Rennen teilnehmen kann, das auf Kompaktwagen beschränkt ist, und umgekehrt. Biete neben Fahrzeugklassen verschiedene Rennformate an: Sprints von A nach B durch die Stadt, Rundstreckenrennen mit mehreren Runden, Drag-Rennen auf geraden Straßen mit Starts nach Reaktionszeit und Drift-Wettbewerbe, bei denen Winkel, Geschwindigkeit und Nähe zu Clipping-Punkten bewertet werden. Jedes Format erfordert eine etwas andere Logik für Wertung und Abschluss-Erkennung. Die Drift-Wertung benötigt insbesondere einen eigenen Algorithmus, der den Schräglaufwinkel des Fahrzeugs relativ zu seinem Geschwindigkeitsvektor, die während des Drifts gehaltene Geschwindigkeit und Bonusmultiplikatoren für aufeinanderfolgende Drifts ohne Kontrollverlust bewertet. Gib Rennveranstaltern die Möglichkeit, Optionen wie Aufholmechaniken, Ghosting durch andere Rennfahrer zur Vermeidung absichtlicher Kollisionen sowie Wetter- oder Tageszeiteinstellungen für die Atmosphäre umzuschalten.

Polizei-Integration und illegale Rennen

Straßenrennen sollten eine illegale Aktivität sein, die auf natürliche Weise Interaktionen mit der Polizei entstehen lässt. Wenn ein Rennen beginnt, sollten NPCs in der Umgebung Lärmbeschwerden melden, die nach einer konfigurierbaren Verzögerung im Polizeidispensystem erscheinen. So erhalten die Rennfahrer einen Vorsprung, längere Rennen ziehen aber trotzdem Aufmerksamkeit auf sich. Polizeibeamte, die darauf reagieren, können versuchen, das Rennen mit Nagelbändern, Straßensperren oder der Verfolgung einzelner Rennfahrer zu stoppen. Wird ein Rennfahrer von der Polizei gefasst, drohen ihm Geldstrafen, die Beschlagnahmung des Fahrzeugs und möglicherweise eine Gefängnisstrafe. Das schafft echte Konsequenzen und lässt die Rennszene gefährlich und aufregend wirken. Implementiere ein speziell für Rennen vorgesehenes Fahndungsstufensystem, das sich bei wiederholten Verstößen verschärft, sodass notorische Straßenrennfahrer mit der Zeit aggressivere Polizeieinsätze auf sich ziehen. Gib der Polizei die Möglichkeit, Überwachungskameras an bekannten Rennorten zu nutzen, um Beweise gegen Veranstalter zu sammeln. So entsteht eine Ermittlungsebene, bei der geduldige Polizeiarbeit mit größeren Razzien belohnt wird, die ganze Renncrews statt einzelner Fahrer ausschalten.

Performanceoptimierung für Rennen

Rennsysteme benötigen eine flüssige Performance, da schon geringfügige Verzögerungen das Wettkampferlebnis beeinträchtigen können. Minimiere die Kommunikation zwischen Server und Client während aktiver Rennen, indem du die Checkpoint-Erkennung und Positionsverfolgung clientseitig abwickelst und Updates nur dann an den Server sendest, wenn ein Checkpoint erreicht wird oder das Rennen endet. Verwende Entity State Bags zur Positionsübertragung statt benutzerdefinierter Netzwerk-Events, da State Bags für häufige Updates optimiert sind und die Bandbreite effizienter nutzen. Zeige beim Rendern der Checkpoints nur Markierungen für den aktuellen und den nächsten Checkpoint statt für alle Checkpoints gleichzeitig an und verwende LOD (Level of Detail), um die Komplexität der Markierungen mit zunehmender Entfernung zu reduzieren. Bündele deine Renn-Datenabfragen, indem du Bestenlisten und Rennlisten in Sammelabfragen statt einzeln abrufst, und speichere die Ergebnisse clientseitig mit einer kurzen TTL im Cache, um die Datenbanklast während der Hauptzeiten für Rennen zu senken. Teste dein System mit der maximal erwarteten Anzahl gleichzeitiger Rennfahrer, üblicherweise 8-16 pro Rennen, um sicherzustellen, dass Positionssynchronisierung und Checkpoint-Validierung ohne Einbrüche der Bildrate oder Desynchronisierungsprobleme skalieren.

Bereit loszulegen?

Hol dir die Scripts in unserem Shop, oder komm auf den Discord für Support, Updates und einen Blick auf das, was kommt.