-- ===================================================================== -- Aether Character — 3D-Vorschau -- Spawnt einen lokalen Ped als lebende Vorschau und richtet eine Kamera -- darauf. Die NUI liegt mit einem transparenten Bereich darueber. -- ===================================================================== Vorschau = {} -- Ort, an dem der Vorschau-Ped steht (ruhige Ecke am Spawnbereich) local VORSCHAU_POS = { x = -1040.0, y = -2748.0, z = 21.36 } -- Kameraeinstellungen je Ansicht -- abstand = Entfernung vor dem Ped, hoehe = Kamerahoehe, ziel = Blickpunkt am Ped local MODI = { gesicht = { abstand = 1.05, hoehe = 0.68, ziel = 0.68, sicht = 28.0 }, koerper = { abstand = 2.90, hoehe = 0.25, ziel = 0.20, sicht = 40.0 }, } -- Laufender Zustand der Vorschau local vorschauPed = nil -- Handle des Vorschau-Peds local vorschauKamera= nil -- Handle der Kamera local aktuellesModell = nil -- Aktuell geladenes Ped-Modell (fuer Geschlechtswechsel) local aktuelleDrehung = 0.0 -- Zusaetzliche Drehung durch den Spieler local aktuellerModus = 'koerper' -- --------------------------------------------------------------------- -- Interne Helfer -- --------------------------------------------------------------------- --- Laedt ein Ped-Modell und wartet, bis es bereit ist --- @param modellName string Name des Modells --- @return number|nil Modell-Hash oder nil bei Fehlschlag local function LadeModell(modellName) local modell = GetHashKey(modellName) RequestModel(modell) local versuche = 0 while not HasModelLoaded(modell) and versuche < 100 do Wait(50) versuche = versuche + 1 end if not HasModelLoaded(modell) then return nil end return modell end --- Setzt die Kamera auf die gewuenschte Ansicht --- @param modus string 'gesicht' | 'koerper' --- @param weich boolean|nil Sanft ueberblenden statt springen local function SetzeKameraAuf(modus, weich) if not vorschauKamera then return end local einstellung = MODI[modus] or MODI.koerper aktuellerModus = modus -- Kamera steht noerdlich vor dem Ped; der Ped schaut sie an. -- Fest im Raum verankert, damit das Drehen des Peds die Kamera nicht mitbewegt. SetCamCoord(vorschauKamera, VORSCHAU_POS.x, VORSCHAU_POS.y + einstellung.abstand, VORSCHAU_POS.z + einstellung.hoehe) PointCamAtCoord(vorschauKamera, VORSCHAU_POS.x, VORSCHAU_POS.y, VORSCHAU_POS.z + einstellung.ziel) SetCamFov(vorschauKamera, einstellung.sicht) if weich then -- Kurze Ueberblendung fuer einen weichen Wechsel SetCamActiveWithInterp(vorschauKamera, vorschauKamera, 400, 1, 1) end end -- --------------------------------------------------------------------- -- Oeffentliche Schnittstelle -- --------------------------------------------------------------------- --- Startet die Vorschau: erzeugt Ped und Kamera --- @param aussehen table|nil Startaussehen (bestimmt auch das Geschlecht) --- @param modus string|nil Startansicht ('gesicht' | 'koerper') function Vorschau.Starten(aussehen, modus) -- Umgebung laden, damit der Ped nicht durch den Boden faellt RequestCollisionAtCoord(VORSCHAU_POS.x, VORSCHAU_POS.y, VORSCHAU_POS.z) local modellName = AetherAussehen.HoleModell(aussehen and aussehen.geschlecht) local modell = LadeModell(modellName) if not modell then print('^1[Aether]^7 Vorschau-Modell konnte nicht geladen werden: ' .. modellName) return end -- Ped nur lokal erzeugen (nicht im Netzwerk sichtbar) vorschauPed = CreatePed(4, modell, VORSCHAU_POS.x, VORSCHAU_POS.y, VORSCHAU_POS.z, 0.0, false, false) aktuellesModell = modellName aktuelleDrehung = 0.0 SetEntityHeading(vorschauPed, 0.0) -- schaut Richtung Kamera FreezeEntityPosition(vorschauPed, true) SetEntityInvincible(vorschauPed, true) SetBlockingOfNonTemporaryEvents(vorschauPed, true) SetModelAsNoLongerNeeded(modell) if aussehen then AetherAussehen.Anwenden(vorschauPed, aussehen) end -- Kamera erzeugen und aktivieren vorschauKamera = CreateCam('DEFAULT_SCRIPTED_CAMERA', true) SetzeKameraAuf(modus or 'koerper', false) SetCamActive(vorschauKamera, true) RenderScriptCams(true, false, 0, true, true) end --- Uebertraegt ein Aussehen auf den Vorschau-Ped. --- Wechselt das Geschlecht, wird der Ped neu erzeugt. --- @param aussehen table Aussehen aus dem Ersteller function Vorschau.Anwenden(aussehen) if not aussehen then return end -- Geschlechtswechsel erfordert ein anderes Modell local gewuenschtesModell = AetherAussehen.HoleModell(aussehen.geschlecht) if gewuenschtesModell ~= aktuellesModell then local drehung = aktuelleDrehung local modus = aktuellerModus if vorschauPed and DoesEntityExist(vorschauPed) then DeletePed(vorschauPed) end local modell = LadeModell(gewuenschtesModell) if not modell then return end vorschauPed = CreatePed(4, modell, VORSCHAU_POS.x, VORSCHAU_POS.y, VORSCHAU_POS.z, 0.0, false, false) aktuellesModell = gewuenschtesModell FreezeEntityPosition(vorschauPed, true) SetEntityInvincible(vorschauPed, true) SetBlockingOfNonTemporaryEvents(vorschauPed, true) SetModelAsNoLongerNeeded(modell) -- Vorherige Drehung und Ansicht wiederherstellen aktuelleDrehung = drehung SetEntityHeading(vorschauPed, aktuelleDrehung) SetzeKameraAuf(modus, false) end if vorschauPed and DoesEntityExist(vorschauPed) then AetherAussehen.Anwenden(vorschauPed, aussehen) end end --- Wechselt zwischen Gesichts- und Koerperansicht --- @param modus string 'gesicht' | 'koerper' function Vorschau.SetzeModus(modus) SetzeKameraAuf(modus, true) end --- Dreht den Vorschau-Ped um einen Winkel --- @param grad number Drehung in Grad (positiv = nach rechts) function Vorschau.Drehen(grad) if not vorschauPed or not DoesEntityExist(vorschauPed) then return end aktuelleDrehung = (aktuelleDrehung + (grad or 0.0)) % 360.0 SetEntityHeading(vorschauPed, aktuelleDrehung) end --- Beendet die Vorschau und raeumt Ped und Kamera auf function Vorschau.Beenden() if vorschauKamera then RenderScriptCams(false, false, 0, true, true) DestroyCam(vorschauKamera, false) vorschauKamera = nil end if vorschauPed and DoesEntityExist(vorschauPed) then DeletePed(vorschauPed) end vorschauPed = nil aktuellesModell = nil aktuelleDrehung = 0.0 end --- Ist gerade eine Vorschau aktiv? --- @return boolean function Vorschau.IstAktiv() return vorschauPed ~= nil end