Skip to content

Kapitel 6.2: Fahrzeugsystem ​


Einführung ​

DayZ-Fahrzeuge sind Entities, die das Transportsystem erweitern. Autos erweitern CarScript, Boote erweitern BoatScript, und beide erben von Transport. Fahrzeuge verfügen über Flüssigkeitssysteme, Teile mit unabhängiger Gesundheit, Getriebesimulation und von der Engine verwaltete Physik. Dieses Kapitel behandelt die API-Methoden, die Sie benötigen, um mit Fahrzeugen in Scripts zu interagieren.


Klassenhierarchie ​

EntityAI
└── Transport                    // 3_Game - Basis für alle Fahrzeuge
    ├── Car                      // 3_Game - Engine-native Auto-Physik
    │   └── CarScript            // 4_World - skriptfähige Auto-Basis
    │       ├── CivilianSedan
    │       ├── OffroadHatchback
    │       ├── Hatchback_02
    │       ├── Sedan_02
    │       ├── Truck_01_Base
    │       └── ...
    └── Boat                     // 3_Game - Engine-native Boot-Physik
        └── BoatScript           // 4_World - skriptfähige Boot-Basis

Transport (Basis) ​

Datei: 3_Game/entities/transport.c

Die abstrakte Basis für alle Fahrzeuge. Bietet Sitzverwaltung und Besatzungszugriff.

Besatzungsverwaltung ​

c
proto native int   CrewSize();                          // Gesamtanzahl der Sitze
proto native int   CrewMemberIndex(Human crew_member);  // Sitzindex eines Menschen ermitteln
proto native Human CrewMember(int posIdx);              // Mensch an Sitzindex ermitteln
proto native Human CrewGetOut(int posIdx);              // Besatzungsmitglied aus dem Sitz zwingen (gibt den ausgeworfenen Menschen zurück)
proto native void  CrewDeath(int posIdx);               // Besatzungsmitglied im Sitz töten

Besatzungseinstieg ​

c
int  GetAnimInstance();                                 // Skript-Methode (überschreibbar), nicht proto native
proto native int  CrewPositionIndex(int componentIdx);  // Komponente zu Sitzindex
proto void CrewEntry(int posIdx, out vector pos, out vector dir);    // Einstiegspunkt/-richtung im Modellraum
proto void CrewEntryWS(int posIdx, out vector pos, out vector dir);  // Einstiegspunkt/-richtung im Weltraum

Beispiel --- alle Passagiere auswerfen:

c
void EjectAllCrew(Transport vehicle)
{
    for (int i = 0; i < vehicle.CrewSize(); i++)
    {
        Human crew = vehicle.CrewMember(i);
        if (crew)
        {
            vehicle.CrewGetOut(i);
        }
    }
}

Car (Engine-nativ) ​

Datei: 3_Game/entities/car.c

Engine-Level Auto-Physik. Alle proto native-Methoden, die die Fahrzeugsimulation antreiben.

Motor ​

c
proto native bool  EngineIsOn();
proto native void  EngineStart();
proto native void  EngineStop();
proto native float EngineGetRPM();
proto native float EngineGetRPMRedline();
proto native float EngineGetRPMMax();
proto native int   GetGear();

Flüssigkeiten ​

DayZ-Fahrzeuge haben vier Flüssigkeitstypen, definiert im CarFluid-Enum:

c
enum CarFluid
{
    FUEL,
    OIL,
    BRAKE,
    COOLANT
}
c
proto native float GetFluidCapacity(CarFluid fluid);
proto native float GetFluidFraction(CarFluid fluid);     // 0.0 - 1.0
proto native void  Fill(CarFluid fluid, float amount);
proto native void  Leak(CarFluid fluid, float amount);
proto native void  LeakAll(CarFluid fluid);

Beispiel --- ein Fahrzeug betanken:

c
void RefuelVehicle(Car car)
{
    float capacity = car.GetFluidCapacity(CarFluid.FUEL);
    float current = car.GetFluidFraction(CarFluid.FUEL) * capacity;
    float needed = capacity - current;
    car.Fill(CarFluid.FUEL, needed);
}

Geschwindigkeit ​

c
proto native float GetSpeedometer();    // Geschwindigkeit in km/h (Absolutwert)

Steuerung (Simulation) ​

c
proto native void  SetBrake(float value, float unused0 = 0, bool unused1 = false);  // 0.0 - 1.0 (zusätzliche Parameter ungenutzt)
proto native void  SetHandbrake(float value);                 // 0.0 - 1.0
proto native void  SetSteering(float value, bool unused0 = false);  // -1.0 - 1.0 (zweiter Parameter ungenutzt)
proto native void  SetThrottle(float value);                  // 0.0 - 1.0 (SetThrust ist veraltet)
proto native void  SetClutch(float value);                    // SetClutchState ist veraltet

Räder ​

c
proto native int   WheelCount();
proto native bool  WheelIsAnyLocked();
proto native SurfaceInfo WheelGetSurface(int wheelIdx);

Callbacks (Überschreiben in CarScript) ​

c
void OnEngineStart();
void OnEngineStop();
void OnContact(string zoneName, vector localPos, IEntity other, Contact data);
void OnFluidChanged(CarFluid fluid, float newValue, float oldValue);
void OnGearChanged(int newGear, int oldGear);
void OnSound(CarSoundCtrl ctrl, float oldValue);

CarScript ​

Datei: 4_World/entities/vehicles/carscript.c

Die skriptfähige Auto-Klasse, die die meisten Fahrzeug-Mods erweitern. Fügt Teile-, Tür-, Licht- und Soundverwaltung hinzu.

Teilegesundheit ​

CarScript verwendet Schadenszonen, um Fahrzeugteile darzustellen. Jedes Teil kann unabhängig beschädigt werden:

c
// Teilegesundheit über die Standard-EntityAI-API prüfen
float engineHP = car.GetHealth("Engine", "Health");
float fuelTankHP = car.GetHealth("FuelTank", "Health");

// Teilegesundheit setzen
car.SetHealth("Engine", "Health", 0);       // Den Motor zerstören
car.SetHealth("FuelTank", "Health", 100);   // Den Kraftstofftank reparieren

Schadenszonen-Diagramm ​

Häufige Schadenszonen für Fahrzeuge:

ZoneBeschreibung
"" (global)Gesamte Fahrzeuggesundheit
"Engine"Motorteil
"FuelTank"Kraftstofftank
"Radiator"Kühler (Kühlmittel)
"Battery"Batterie
"SparkPlug"Zündkerze
"FrontLeft" / "FrontRight"Vorderräder
"RearLeft" / "RearRight"Hinterräder
"DriverDoor" / "CoDriverDoor"Vordertüren
"Hood" / "Trunk"Motorhaube und Kofferraum

Lichter ​

Die Licht-API befindet sich auf Transport:

c
proto native bool LightIsOn();    // True, wenn die Lichter an sind
proto native void LightOn();      // Lichter einschalten
proto native void LightOff();     // Lichter ausschalten
proto native void LightToggle();  // Aktuellen Lichtzustand umschalten

Türsteuerung ​

Der Türzustand wird mit GetCarDoorsState abgefragt, das einen CarDoorState-Wert zurückgibt (DOORS_MISSING, DOORS_OPEN oder DOORS_CLOSED):

c
enum CarDoorState
{
    DOORS_MISSING,
    DOORS_OPEN,
    DOORS_CLOSED
}

int GetCarDoorsState(string slotType);   // Gibt einen CarDoorState-Wert zurück

Wichtige Überschreibungen für benutzerdefinierte Fahrzeuge ​

c
override void EEInit();                    // Fahrzeugteile, Flüssigkeiten initialisieren
override void OnEngineStart();             // Benutzerdefiniertes Motorstartverhalten
override void OnEngineStop();              // Benutzerdefiniertes Motorstoppverhalten
override void EOnPostSimulate(IEntity other, float timeSlice);  // Simulation pro Tick (CarScript)

Beispiel --- ein Fahrzeug mit vollen Flüssigkeiten erstellen:

c
void SpawnReadyVehicle(vector pos)
{
    Car car = Car.Cast(GetGame().CreateObjectEx("CivilianSedan", pos,
                        ECE_PLACE_ON_SURFACE | ECE_INITAI | ECE_CREATEPHYSICS));
    if (!car)
        return;

    // Alle Flüssigkeiten auffüllen
    car.Fill(CarFluid.FUEL, car.GetFluidCapacity(CarFluid.FUEL));
    car.Fill(CarFluid.OIL, car.GetFluidCapacity(CarFluid.OIL));
    car.Fill(CarFluid.BRAKE, car.GetFluidCapacity(CarFluid.BRAKE));
    car.Fill(CarFluid.COOLANT, car.GetFluidCapacity(CarFluid.COOLANT));

    // Erforderliche Teile spawnen
    EntityAI carEntity = EntityAI.Cast(car);
    carEntity.GetInventory().CreateAttachment("CarBattery");
    carEntity.GetInventory().CreateAttachment("SparkPlug");
    carEntity.GetInventory().CreateAttachment("CarRadiator");
    carEntity.GetInventory().CreateAttachment("HatchbackWheel");
}

BoatScript ​

Datei: 4_World/entities/vehicles/boatscript.c

Skriptfähige Basis für Boot-Entities. Ähnliche API wie CarScript, aber mit propellerbasierter Physik.

Motor und Antrieb ​

c
proto native bool  EngineIsOn();
proto native void  EngineStart();
proto native void  EngineStop();
proto native float EngineGetRPM();

Flüssigkeiten ​

Boote verwenden ein separates BoatFluid-Enum, das nur FUEL definiert:

c
float fuel = boat.GetFluidFraction(BoatFluid.FUEL);
boat.Fill(BoatFluid.FUEL, boat.GetFluidCapacity(BoatFluid.FUEL));

Geschwindigkeit & Antrieb ​

Boat stellt GetSpeedometer() nicht bereit (diese Methode existiert nur auf Car). Lesen Sie stattdessen die Motordrehzahl und die Propellergeschwindigkeit:

c
proto native float EngineGetRPM();                   // Motordrehzahl
proto native float PropellerGetAngularVelocity();    // Winkelgeschwindigkeit des Propellers

Beispiel --- ein Boot spawnen:

Boat_01 ist keine direkt spawnbare Klasse; spawnen Sie eine der konkreten Farbvarianten (Boat_01_Blue, Boat_01_Orange, Boat_01_Black, Boat_01_Camo):

c
void SpawnBoat(vector waterPos)
{
    BoatScript boat = BoatScript.Cast(
        GetGame().CreateObjectEx("Boat_01_Blue", waterPos,
                                  ECE_CREATEPHYSICS | ECE_INITAI)
    );
    if (boat)
    {
        boat.Fill(BoatFluid.FUEL, boat.GetFluidCapacity(BoatFluid.FUEL));
    }
}

Fahrzeug-Interaktionsprüfungen ​

Prüfen ob ein Spieler in einem Fahrzeug ist ​

c
PlayerBase player;
if (player.IsInVehicle())
{
    EntityAI vehicle = player.GetDrivingVehicle();
    CarScript car;
    if (Class.CastTo(car, vehicle))
    {
        float speed = car.GetSpeedometer();
        Print(string.Format("Fährt mit %1 km/h", speed));
    }
}

Alle Fahrzeuge in der Welt finden ​

c
void FindAllVehicles(out array<Transport> vehicles)
{
    vehicles = new array<Transport>;
    array<Object> objects = new array<Object>;
    array<CargoBase> proxyCargos = new array<CargoBase>;

    // Großen Radius von der Kartenmitte verwenden
    GetGame().GetObjectsAtPosition(Vector(7500, 0, 7500), 15000, objects, proxyCargos);

    foreach (Object obj : objects)
    {
        Transport transport;
        if (Class.CastTo(transport, obj))
        {
            vehicles.Insert(transport);
        }
    }
}

Zusammenfassung ​

KonzeptKernpunkt
HierarchieTransport > Car/Boat > CarScript/BoatScript
MotorEngineStart(), EngineStop(), EngineIsOn(), EngineGetRPM()
FlüssigkeitenCarFluid-Enum: FUEL, OIL, BRAKE, COOLANT
Füllen/LeckenFill(fluid, amount), Leak(fluid, amount), GetFluidFraction(fluid)
GeschwindigkeitGetSpeedometer() gibt km/h zurück
BesatzungCrewSize(), CrewMember(idx), CrewGetOut(idx)
TeileStandard-Schadenszonen: "Engine", "FuelTank", "Radiator", usw.
ErstellungCreateObjectEx mit ECE_PLACE_ON_SURFACE | ECE_INITAI | ECE_CREATEPHYSICS
1.28 KonfigurationuseNewNetworking, wheelHubFriction, verdoppelte Bremsdrehmoment-Werte
1.28 PhysikAktualisierte Bullet-Physik, neue Contact-API-Felder, Federung immer aktiv
1.29 ExperimentellPhysik-Multithreading, Transport-Sleep, dynamische Kollision für alle Transporte

Bewährte Praktiken ​

  • Fügen Sie beim Spawnen von Fahrzeugen immer ECE_CREATEPHYSICS | ECE_INITAI hinzu. Ohne Physik fällt das Fahrzeug durch den Boden. Ohne AI-Init startet die Motorsimulation nicht und das Fahrzeug kann nicht gefahren werden.
  • Füllen Sie alle vier Flüssigkeiten nach dem Spawnen auf. Ein Fahrzeug ohne Öl, Bremsflüssigkeit oder Kühlmittel beschädigt sich sofort, wenn der Motor gestartet wird. Verwenden Sie GetFluidCapacity(), um korrekte Maximalwerte pro Fahrzeugtyp zu erhalten.
  • Null-Prüfung von CrewMember() vor Operationen an der Besatzung. Leere Sitze geben null zurück. Das Iterieren über CrewSize() ohne Prüfung jedes Index verursacht Abstürze bei unbesetzten Sitzen.
  • Verwenden Sie GetSpeedometer() anstatt die Geschwindigkeit manuell zu berechnen. Der Tachometer der Engine berücksichtigt Radkontakt, Getriebezustand und Physik korrekt. Manuelle Geschwindigkeitsberechnungen aus Positionsdifferenzen sind unzuverlässig.

Kompatibilität und Auswirkungen ​

Mod-Kompatibilität: Fahrzeug-Mods erweitern häufig CarScript mit modded-Klassen. Konflikte entstehen, wenn mehrere Mods dieselben Callbacks wie OnEngineStart() oder EOnSimulate() überschreiben.

  • Ladereihenfolge: Wenn zwei Mods beide modded class CarScript verwenden und OnEngineStart() überschreiben, läuft nur die zuletzt geladene Mod, es sei denn, beide rufen super auf. Fahrzeug-Überarbeitungs-Mods sollten immer super in jedem Callback aufrufen.
  • Modded-Class-Konflikte: Expansion Vehicles und Vanilla-Fahrzeug-Mods kollidieren häufig bei EEInit() und der Flüssigkeitsinitialisierung. Testen Sie mit beiden geladen.
  • Leistungsauswirkung: EOnSimulate() läuft jeden Physik-Tick für jedes aktive Fahrzeug. Halten Sie die Logik in diesem Callback minimal; verwenden Sie Timer-Akkumulatoren für aufwendige Operationen.
  • Server/Client: EngineStart(), EngineStop(), Fill(), Leak() und CrewGetOut() sind server-autoritativ. GetSpeedometer(), EngineIsOn() und GetFluidFraction() können sicher auf beiden Seiten gelesen werden.

Fahrzeugkonfigurationsänderungen (1.28+) ​

Warnung (1.28): DayZ 1.28 führte erhebliche Änderungen an der Fahrzeugphysik ein. Wenn Sie einen Fahrzeug-Mod von 1.27 oder früher aktualisieren, lesen Sie diesen Abschnitt sorgfältig.

useNewNetworking-Parameter ​

DayZ 1.28 fügte den useNewNetworking-Konfigurationsparameter für alle CarScript-Klassen hinzu. Der Standardwert ist 1 (aktiviert).

cpp
class CfgVehicles
{
    class CarScript;
    class MyVehicle : CarScript
    {
        // Neues Networking verbessert Rubber-Banding bei hohem Ping
        useNewNetworking = 1;  // Standard — für die meisten Mods aktiviert lassen

        // NUR deaktivieren, wenn Ihr Mod die Fahrzeugphysik
        // ausserhalb des SimulationModule-Configs modifiziert:
        // useNewNetworking = 0;
    };
};

Wann deaktivieren: Wenn Ihr Mod die Fahrzeugphysik direkt über Script manipuliert (benutzerdefinierte EOnSimulate-Überschreibungen, direkte Kraftanwendung, benutzerdefinierte Radlogik) anstatt über das konfigurationsbasierte SimulationModule, kann das neue Abgleichsystem Ihre Änderungen stören. Setzen Sie in diesem Fall useNewNetworking = 0;.

wheelHubFriction-Parameter (1.28+) ​

Neue Konfigurationsvariable, die den Achswiderstand definiert, wenn keine Räder montiert sind:

cpp
class SimulationModule
{
    class Axles
    {
        class Front
        {
            wheelHubFriction = 0.5;  // Wie schnell das Fahrzeug ohne Räder verzögert
        };
    };
};

Bremsdrehmoment-Migration (1.28) ​

Brechende Änderung: Vor 1.28 wurde das Brems- und Handbremsdrehmoment aufgrund eines Fehlers zweimal angewendet. Dies wurde in 1.28 behoben. Wenn Sie einen Fahrzeug-Mod migrieren, verdoppeln Sie Ihre maxBrakeTorque- und maxHandbrakeTorque-Werte, um das gleiche Bremsgefühl beizubehalten.

cpp
// Vor 1.28 (Fehler: zweimal angewendet, effektiver Wert war 2x)
maxBrakeTorque = 2000;
maxHandbrakeTorque = 3000;

// Nach 1.28 (Fix: einmal angewendet, also verdoppeln für altes Verhalten)
maxBrakeTorque = 4000;
maxHandbrakeTorque = 6000;

Federung immer aktiv (1.28+) ​

Die Fahrzeugfederung ist jetzt immer aktiv, solange das Fahrzeug wach ist. Zuvor konnte die Federung in bestimmten Zuständen inaktiv sein. Dies verbessert die Stabilität, kann aber das Gefühl benutzerdefinierter Federungsabstimmungen verändern.

Bullet-Physik-Update (1.28) ​

Die Bullet-Physik-Bibliothek wurde auf die neueste Enfusion-Version aktualisiert. Subtile Unterschiede in Kollisionsreaktion, Reibung und Rückprall können auftreten. Testen Sie alle benutzerdefinierten Fahrzeugkonfigurationen gründlich.

Physik-Kontakt-API-Änderungen (1.28) ​

Die Contact-Klasse wurde modifiziert:

Entfernt:

  • MaterialIndex1, MaterialIndex2
  • Index1, Index2

Hinzugefügt:

  • ShapeIndex1, ShapeIndex2 --- identifizieren, welche Form in einem zusammengesetzten Körper getroffen wurde
  • VelocityBefore1, VelocityBefore2 --- Geschwindigkeiten vor der Kollision
  • VelocityAfter1, VelocityAfter2 --- Geschwindigkeiten nach der Kollision

Geändert:

  • Material1, Material2 --- Typ geändert von dMaterial zu SurfaceProperties

Mods, die Contact-Daten in OnContact lesen, müssen auf die neuen Variablennamen und -typen aktualisiert werden.


Fahrzeugänderungen in 1.29 (Experimentell) ​

Hinweis: Diese Änderungen stammen aus dem experimentellen DayZ 1.29 und können sich vor der stabilen Veröffentlichung ändern.

Bullet-Physik-Multithreading (1.29 Experimentell) ​

Multithreading-Unterstützung wurde für die Bullet-Physik-Bibliothek aktiviert. Server-Stresstests zeigten bis zu 400% FPS-Verbesserung (9 FPS auf 50 FPS). Fahrzeug-Mods, die auf bestimmtes Physik-Timing angewiesen sind oder Physik-Aufrufe aus Script-Callbacks machen, sollten ausgiebig getestet werden.

Transport-Sleep (1.29 Experimentell) ​

Physik-Funktionen wurden direkt zu Transport hinzugefügt, um Fahrzeugen das Schlafen im Ruhezustand zu ermöglichen. Inaktive Körper erhalten keine EOnSimulate- / EOnPostSimulate-Callbacks mehr. Wenn Ihr Fahrzeug-Mod darauf angewiesen ist, dass diese Callbacks kontinuierlich feuern, testen Sie auf dem experimentellen 1.29.

Dynamische Kollision für alle Transporte (1.29 Experimentell) ​

Die Transport-Klasse (Elternklasse von CarScript und BoatScript) verfügt jetzt über dynamische Kollisionsauflösung. Zuvor hatte nur CarScript dies. Boot-Mods profitieren von einer korrekten Kollisionsbehandlung.


In echten Mods beobachtet ​

Diese Muster wurden durch das Studium des Quellcodes professioneller DayZ-Mods bestätigt.

MusterModDatei/Ort
EEInit() überschreiben, um benutzerdefinierte Flüssigkeitskapazitäten und Teile zu setzenExpansion VehiclesCarScript-Unterklassen
EOnSimulate-Akkumulator für periodische KraftstoffverbrauchsprüfungenVanilla+ Fahrzeug-ModsCarScript-Überschreibungen
CrewGetOut()-Schleife im Admin-Alle-Auswerfen-BefehlVPP Admin ToolsFahrzeugverwaltungsmodul
Benutzerdefinierter OnContact()-Override für Kollisionsschadens-TuningExpansionExpansionCarScript

Released under CC BY-SA 4.0 | Code examples under MIT License