FiveM-Kamerasystem: Eigene Kameras, Überwachung und Filmszenen
Lerne FiveM-Kameraskripte: Freecam, Überwachung für die Polizei, Filmszenen und eigene Kameraoberflächen mit Code und passenden Ressourcen.
Agency Scripts
Gründer und leitender Entwickler bei Agency Scripts
Warum individuelle Kamerasysteme wichtig sind
Die Standardkamera von GTA V eignet sich gut für das allgemeine Gameplay, aber Roleplay-Server und benutzerdefinierte Spielmodi benötigen oft spezielle Kamerafunktionen. Bei der Charaktererstellung sind Orbitalkameras erforderlich, mit denen Spieler ihren Charakter drehen können. Zwischensequenzen benötigen geskriptete Kamerafahrten mit flüssigen Übergängen. CCTV-Systeme erfordern fest installierte Überwachungskameras. Objektvorschauen benötigen Kamerafahrten. Ein flexibles Kamerasystem, das all diese Anwendungsfälle abdeckt, wird die Präsentationsqualität deines Servers deutlich verbessern. Dieses Tutorial behandelt die FiveM-Kamera-API ausführlich und enthält praxisnahe Beispiele, die du sofort verwenden kannst.
Kamera-Grundlagen
FiveM-Kameras verwenden die nativen CreateCam und CreateCamWithParams Funktionen. Eine Kamera ist eine Entity mit Position, Rotation und Sichtfeld. Du kannst mehrere Kameras erstellen und zwischen ihnen wechseln oder fließend von einer Kameraposition zur nächsten überblenden. Wichtig ist, dass die normale Gameplay-Kamera deaktiviert wird, wenn über eine Skriptkamera gerendert wird. Daher musst du den Wechsel zurück sorgfältig handhaben.
-- client/camera_core.lua
local CameraSystem = {
activeCam = nil,
isActive = false,
}
function CameraSystem.Create(coords, rot, fov)
local cam = CreateCamWithParams(
'DEFAULT_SCRIPTED_CAMERA',
coords.x, coords.y, coords.z,
rot.x, rot.y, rot.z,
fov or 60.0,
false, 0
)
return cam
end
function CameraSystem.Activate(cam, transitionTime)
transitionTime = transitionTime or 1000
SetCamActive(cam, true)
RenderScriptCams(true, true, transitionTime, true, false)
CameraSystem.activeCam = cam
CameraSystem.isActive = true
end
function CameraSystem.Deactivate(transitionTime)
transitionTime = transitionTime or 1000
RenderScriptCams(false, true, transitionTime, true, false)
if CameraSystem.activeCam then
SetCamActive(CameraSystem.activeCam, false)
DestroyCam(CameraSystem.activeCam, false)
CameraSystem.activeCam = nil
end
CameraSystem.isActive = false
end
-- Clean up on resource stop
AddEventHandler('onResourceStop', function(resourceName)
if GetCurrentResourceName() ~= resourceName then return end
if CameraSystem.isActive then
CameraSystem.Deactivate(0)
end
end)
Orbitalkamera für die Charaktererstellung
Eine Orbitalkamera kreist um einen Mittelpunkt und ermöglicht es dem Spieler, die Ansicht durch Ziehen mit der Maus zu drehen. Sie ist die Standardkamera für die Charaktererstellung, Kleidungsgeschäfte und Friseursalons. Die Kamera hält einen festen Abstand zum Ziel und wandelt Mausbewegungen in eine Drehung um den Mittelpunkt um.
-- client/orbit_camera.lua
local OrbitCam = {
active = false,
cam = nil,
target = nil,
distance = 2.0,
angleH = 0.0,
angleV = 20.0,
minV = -30.0,
maxV = 60.0,
sensitivity = 0.3,
fov = 45.0,
}
function OrbitCam.Start(targetEntity, distance, height)
OrbitCam.target = targetEntity
OrbitCam.distance = distance or 2.0
OrbitCam.angleH = GetEntityHeading(targetEntity) + 180.0
OrbitCam.angleV = 20.0
local targetCoords = GetEntityCoords(targetEntity)
local camPos = OrbitCam.CalculatePosition(targetCoords)
OrbitCam.cam = CreateCamWithParams(
'DEFAULT_SCRIPTED_CAMERA',
camPos.x, camPos.y, camPos.z,
0.0, 0.0, 0.0,
OrbitCam.fov, false, 0
)
PointCamAtCoord(OrbitCam.cam, targetCoords.x, targetCoords.y, targetCoords.z + 0.5)
SetCamActive(OrbitCam.cam, true)
RenderScriptCams(true, true, 800, true, false)
OrbitCam.active = true
OrbitCam.UpdateLoop()
end
function OrbitCam.CalculatePosition(center)
local hRad = math.rad(OrbitCam.angleH)
local vRad = math.rad(OrbitCam.angleV)
local x = center.x + OrbitCam.distance * math.cos(vRad) * math.sin(hRad)
local y = center.y + OrbitCam.distance * math.cos(vRad) * math.cos(hRad)
local z = center.z + 0.5 + OrbitCam.distance * math.sin(vRad)
return vector3(x, y, z)
end
function OrbitCam.UpdateLoop()
CreateThread(function()
while OrbitCam.active do
DisableAllControlActions(0)
EnableControlAction(0, 1, true) -- Mouse X
EnableControlAction(0, 2, true) -- Mouse Y
EnableControlAction(0, 241, true) -- Scroll Up
EnableControlAction(0, 242, true) -- Scroll Down
-- Mouse rotation
local mouseX = GetDisabledControlNormal(0, 1) * OrbitCam.sensitivity * 8.0
local mouseY = GetDisabledControlNormal(0, 2) * OrbitCam.sensitivity * 8.0
OrbitCam.angleH = OrbitCam.angleH - mouseX
OrbitCam.angleV = math.max(OrbitCam.minV,
math.min(OrbitCam.maxV, OrbitCam.angleV + mouseY))
-- Scroll zoom
if IsDisabledControlPressed(0, 241) then
OrbitCam.distance = math.max(0.5, OrbitCam.distance - 0.1)
elseif IsDisabledControlPressed(0, 242) then
OrbitCam.distance = math.min(5.0, OrbitCam.distance + 0.1)
end
local targetCoords = GetEntityCoords(OrbitCam.target)
local camPos = OrbitCam.CalculatePosition(targetCoords)
SetCamCoord(OrbitCam.cam, camPos.x, camPos.y, camPos.z)
PointCamAtCoord(OrbitCam.cam, targetCoords.x, targetCoords.y, targetCoords.z + 0.5)
Wait(0)
end
end)
end
function OrbitCam.Stop()
OrbitCam.active = false
RenderScriptCams(false, true, 800, true, false)
if OrbitCam.cam then
SetCamActive(OrbitCam.cam, false)
DestroyCam(OrbitCam.cam, false)
OrbitCam.cam = nil
end
end
Kamerainterpolation und Übergänge
Fließende Kamerabewegungen zwischen zwei Positionen sorgen für filmische Effekte in Zwischensequenzen, Objekttouren und Ladebildschirmen. FiveM stellt SetCamActiveWithInterp bereit, das die Interpolation nativ ausführt. Du kannst aber auch benutzerdefinierte Easing-Funktionen erstellen, um den Verlauf des Übergangs genauer zu steuern.
-- client/camera_transition.lua
local function TransitionCamera(fromPos, fromRot, toPos, toRot, duration, fov)
fov = fov or 50.0
local camFrom = CreateCamWithParams('DEFAULT_SCRIPTED_CAMERA',
fromPos.x, fromPos.y, fromPos.z,
fromRot.x, fromRot.y, fromRot.z,
fov, false, 0)
local camTo = CreateCamWithParams('DEFAULT_SCRIPTED_CAMERA',
toPos.x, toPos.y, toPos.z,
toRot.x, toRot.y, toRot.z,
fov, false, 0)
SetCamActive(camFrom, true)
RenderScriptCams(true, false, 0, true, false)
-- Interpolate from first camera to second
SetCamActiveWithInterp(camTo, camFrom, duration, 1, 1)
Wait(duration)
-- Clean up the first camera
DestroyCam(camFrom, false)
return camTo
end
-- Usage: Flythrough preview of a property
local function PropertyPreview(waypoints, duration)
local perSegment = duration / (#waypoints - 1)
local currentCam = nil
for i = 1, #waypoints - 1 do
local wp = waypoints[i]
local nextWp = waypoints[i + 1]
currentCam = TransitionCamera(
wp.pos, wp.rot,
nextWp.pos, nextWp.rot,
perSegment, wp.fov or 60.0
)
end
-- Return to gameplay camera
Wait(500)
RenderScriptCams(false, true, 1000, true, false)
if currentCam then DestroyCam(currentCam, false) end
end
CCTV-Überwachungskamerasystem
Ein CCTV-System verwendet fest installierte Kameras an verschiedenen Orten auf der Karte, zwischen denen Spieler wechseln können. Jede Kamera hat eine vordefinierte Position und Rotation. Das System wendet einen Post-Processing-Effekt an, der Aufnahmen von Überwachungskameras simuliert. Diese Funktion wird häufig in Polizeistationen und Geschäftsräumen eingesetzt.
-- client/cctv.lua
local CCTV = {
cameras = {},
currentIndex = 0,
activeCam = nil,
active = false,
}
function CCTV.AddCamera(name, coords, rot, fov)
table.insert(CCTV.cameras, {
name = name,
coords = coords,
rot = rot,
fov = fov or 60.0,
})
end
function CCTV.Start(startIndex)
CCTV.currentIndex = startIndex or 1
CCTV.active = true
CCTV.SwitchTo(CCTV.currentIndex)
CreateThread(function()
while CCTV.active do
-- Apply security camera filter
SetTimecycleModifier('CAMERA_secuirity')
SetTimecycleModifierStrength(1.0)
DisableAllControlActions(0)
EnableControlAction(0, 174, true) -- Left Arrow
EnableControlAction(0, 175, true) -- Right Arrow
EnableControlAction(0, 202, true) -- Escape
-- Cycle cameras
if IsDisabledControlJustPressed(0, 175) then
local next = CCTV.currentIndex + 1
if next > #CCTV.cameras then next = 1 end
CCTV.SwitchTo(next)
elseif IsDisabledControlJustPressed(0, 174) then
local prev = CCTV.currentIndex - 1
if prev < 1 then prev = #CCTV.cameras end
CCTV.SwitchTo(prev)
elseif IsDisabledControlJustPressed(0, 202) then
CCTV.Stop()
end
Wait(0)
end
end)
end
function CCTV.SwitchTo(index)
local data = CCTV.cameras[index]
if not data then return end
local newCam = CreateCamWithParams('DEFAULT_SCRIPTED_CAMERA',
data.coords.x, data.coords.y, data.coords.z,
data.rot.x, data.rot.y, data.rot.z,
data.fov, false, 0)
if CCTV.activeCam then
SetCamActiveWithInterp(newCam, CCTV.activeCam, 500, 1, 1)
Wait(500)
DestroyCam(CCTV.activeCam, false)
else
SetCamActive(newCam, true)
RenderScriptCams(true, true, 500, true, false)
end
CCTV.activeCam = newCam
CCTV.currentIndex = index
end
function CCTV.Stop()
CCTV.active = false
ClearTimecycleModifier()
RenderScriptCams(false, true, 800, true, false)
if CCTV.activeCam then
DestroyCam(CCTV.activeCam, false)
CCTV.activeCam = nil
end
end
Bewährte Methoden für Kamerasysteme
- Zerstöre Kameras immer, wenn du sie nicht mehr benötigst. Nicht zerstörte Kameras führen zu Speicherlecks. Verfolge jedes Kamera-Handle und bereinige es in
onResourceStop. - Deaktiviere Steuerungseingaben während Kamerasequenzen. Spieler sollten sich nicht bewegen, schießen oder interagieren können, solange eine Skriptkamera aktiv ist, sofern dies nicht ausdrücklich erlaubt ist.
- Verwende passende FOV-Werte. Beim normalen Gameplay liegt das Sichtfeld bei 50-60 FOV. Für einen Teleobjektiv-Look werden in filmischen Einstellungen 30-40 FOV verwendet. Weitwinkelaufnahmen zur Einführung nutzen 70-90 FOV.
- Blende während Kamerasequenzen das HUD aus. Verwende
DisplayHud(false)undDisplayRadar(false), um Gameplay-Elemente während filmischer Kamerafahrten auszublenden. - Teste Übergänge bei unterschiedlichen Bildraten. Kamerainterpolation kann bei 30fps anders aussehen als bei 144fps. Teste auf leistungsschwacher Hardware, um ein flüssiges Verhalten sicherzustellen.