Kapitel 6.2: Fahrzeugsystem
Startseite | << Zurück: Entity-System | Fahrzeuge | Weiter: Wetter >>
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 void CrewGetOut(int posIdx); // Besatzungsmitglied aus dem Sitz zwingen
proto native void CrewDeath(int posIdx); // Besatzungsmitglied im Sitz tötenBesatzungseinstieg
proto native int GetAnimInstance();
proto native int CrewPositionIndex(int componentIdx); // Komponente zu Sitzindex
proto native vector CrewEntryPoint(int posIdx); // Welteinstiegspunkt für SitzBeispiel --- 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, int wheel = -1); // 0.0 - 1.0, -1 = alle Räder
proto native void SetHandbrake(float value); // 0.0 - 1.0
proto native void SetSteering(float value, bool analog = true);
proto native void SetThrust(float value, int wheel = -1); // 0.0 - 1.0
proto native void SetClutchState(bool engaged);Räder
proto native int WheelCount();
proto native bool WheelIsAnyLocked();
proto native float 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
void SetLightsState(int state); // 0 = aus, 1 = an
int GetLightsState();Türsteuerung
bool IsDoorOpen(string doorSource);
void OpenDoor(string doorSource);
void CloseDoor(string doorSource);Wichtige Überschreibungen für benutzerdefinierte Fahrzeuge
override void EEInit(); // Fahrzeugteile, Flüssigkeiten initialisieren
override void OnEngineStart(); // Benutzerdefiniertes Motorstartverhalten
override void OnEngineStop(); // Benutzerdefiniertes Motorstoppverhalten
override void EOnSimulate(IEntity other, float dt); // Simulation pro Tick
override bool CanObjectAttachWeapon(string slot_name);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 dasselbe CarFluid-Enum, nutzen aber typischerweise nur FUEL:
float fuel = boat.GetFluidFraction(CarFluid.FUEL);
boat.Fill(CarFluid.FUEL, boat.GetFluidCapacity(CarFluid.FUEL));Geschwindigkeit
proto native float GetSpeedometer(); // Geschwindigkeit in km/hBeispiel --- ein Boot spawnen:
void SpawnBoat(vector waterPos)
{
BoatScript boat = BoatScript.Cast(
GetGame().CreateObjectEx("Boat_01", waterPos,
ECE_CREATEPHYSICS | ECE_INITAI)
);
if (boat)
{
boat.Fill(CarFluid.FUEL, boat.GetFluidCapacity(CarFluid.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 EOnContact 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 |
Startseite | << Zurück: Entity-System | Fahrzeuge | Weiter: Wetter >>
