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-BasisTransport (Basis)
Datei: 3_Game/entities/transport.c
Die abstrakte Basis für alle Fahrzeuge. Bietet Sitzverwaltung und Besatzungszugriff.
Besatzungsverwaltung
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ötenBesatzungseinstieg
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 WeltraumBeispiel --- alle Passagiere auswerfen:
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
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:
enum CarFluid
{
FUEL,
OIL,
BRAKE,
COOLANT
}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:
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
proto native float GetSpeedometer(); // Geschwindigkeit in km/h (Absolutwert)Steuerung (Simulation)
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 veraltetRäder
proto native int WheelCount();
proto native bool WheelIsAnyLocked();
proto native SurfaceInfo WheelGetSurface(int wheelIdx);Callbacks (Überschreiben in CarScript)
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:
// 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 reparierenSchadenszonen-Diagramm
Häufige Schadenszonen für Fahrzeuge:
| Zone | Beschreibung |
|---|---|
"" (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:
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 umschaltenTürsteuerung
Der Türzustand wird mit GetCarDoorsState abgefragt, das einen CarDoorState-Wert zurückgibt (DOORS_MISSING, DOORS_OPEN oder DOORS_CLOSED):
enum CarDoorState
{
DOORS_MISSING,
DOORS_OPEN,
DOORS_CLOSED
}
int GetCarDoorsState(string slotType); // Gibt einen CarDoorState-Wert zurückWichtige Überschreibungen für benutzerdefinierte Fahrzeuge
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:
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
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:
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:
proto native float EngineGetRPM(); // Motordrehzahl
proto native float PropellerGetAngularVelocity(); // Winkelgeschwindigkeit des PropellersBeispiel --- 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):
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
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
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
| Konzept | Kernpunkt |
|---|---|
| Hierarchie | Transport > Car/Boat > CarScript/BoatScript |
| Motor | EngineStart(), EngineStop(), EngineIsOn(), EngineGetRPM() |
| Flüssigkeiten | CarFluid-Enum: FUEL, OIL, BRAKE, COOLANT |
| Füllen/Lecken | Fill(fluid, amount), Leak(fluid, amount), GetFluidFraction(fluid) |
| Geschwindigkeit | GetSpeedometer() gibt km/h zurück |
| Besatzung | CrewSize(), CrewMember(idx), CrewGetOut(idx) |
| Teile | Standard-Schadenszonen: "Engine", "FuelTank", "Radiator", usw. |
| Erstellung | CreateObjectEx mit ECE_PLACE_ON_SURFACE | ECE_INITAI | ECE_CREATEPHYSICS |
| 1.28 Konfiguration | useNewNetworking, wheelHubFriction, verdoppelte Bremsdrehmoment-Werte |
| 1.28 Physik | Aktualisierte Bullet-Physik, neue Contact-API-Felder, Federung immer aktiv |
| 1.29 Experimentell | Physik-Multithreading, Transport-Sleep, dynamische Kollision für alle Transporte |
Bewährte Praktiken
- Fügen Sie beim Spawnen von Fahrzeugen immer
ECE_CREATEPHYSICS | ECE_INITAIhinzu. 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 gebennullzurück. Das Iterieren überCrewSize()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
CarScriptmit modded-Klassen. Konflikte entstehen, wenn mehrere Mods dieselben Callbacks wieOnEngineStart()oderEOnSimulate()überschreiben.
- Ladereihenfolge: Wenn zwei Mods beide
modded class CarScriptverwenden undOnEngineStart()überschreiben, läuft nur die zuletzt geladene Mod, es sei denn, beide rufensuperauf. Fahrzeug-Überarbeitungs-Mods sollten immersuperin 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()undCrewGetOut()sind server-autoritativ.GetSpeedometer(),EngineIsOn()undGetFluidFraction()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).
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:
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- undmaxHandbrakeTorque-Werte, um das gleiche Bremsgefühl beizubehalten.
// 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,MaterialIndex2Index1,Index2
Hinzugefügt:
ShapeIndex1,ShapeIndex2--- identifizieren, welche Form in einem zusammengesetzten Körper getroffen wurdeVelocityBefore1,VelocityBefore2--- Geschwindigkeiten vor der KollisionVelocityAfter1,VelocityAfter2--- Geschwindigkeiten nach der Kollision
Geändert:
Material1,Material2--- Typ geändert vondMaterialzuSurfaceProperties
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.
| Muster | Mod | Datei/Ort |
|---|---|---|
EEInit() überschreiben, um benutzerdefinierte Flüssigkeitskapazitäten und Teile zu setzen | Expansion Vehicles | CarScript-Unterklassen |
EOnSimulate-Akkumulator für periodische Kraftstoffverbrauchsprüfungen | Vanilla+ Fahrzeug-Mods | CarScript-Überschreibungen |
CrewGetOut()-Schleife im Admin-Alle-Auswerfen-Befehl | VPP Admin Tools | Fahrzeugverwaltungsmodul |
Benutzerdefinierter OnContact()-Override für Kollisionsschadens-Tuning | Expansion | ExpansionCarScript |
