nide Posted August 25 Share Posted August 25 Hi! I've been messing around with a custom vehicle chase camera script I made for my own private server. It has a toggleable chase camera and can detect whether you're in a vehicle or not and disable/enable itself accordingly, and commands to adjust the behavior of the camera, like camera distance from the vehicle, camera height and camera FOV management, which currently is giving me the most gripe. For whatever reason i just can't manage to make the FOV aspect of the script work, as it for some reason only affects me when I exit the car, but when i enter it, the FOV resets even without enabling the custom camera. If you guys could take a look at my code it'd be greatly appreciated. I'd also like to mention that this code was created with the help of claudeAI, and I'm not an expert at scripting whatsoever, I just wanted to make something for my own use, and not trying to "sell it off" as my actual own hard work and effort. It just makes it easier when testing some race maps I created without having to use my mouse for moving the vanilla camera around. -- client.lua - Fixed Camera with Working FOV local chaseCamEnabled = false local camX, camY, camZ local camRotation = 0 local originalFOV = nil -- Camera settings local baseDist = 7.5 local height = 3 local smooth = 0.3 local turnSmooth = 0.05 local fov = 70 -- FOV update timer to ensure it stays applied local fovTimer = nil -- Function to force FOV application function applyFOV() if chaseCamEnabled then setCameraFieldOfView("player", fov) end end -- Update camera every frame function updateChaseCam() if not chaseCamEnabled then return end local veh = getPedOccupiedVehicle(localPlayer) if not veh then disableChaseCam() return end local x, y, z = getElementPosition(veh) local _, _, rz = getElementRotation(veh) -- Smoothly interpolate camera rotation instead of instant following local targetRotation = rz -- Handle rotation wrap-around (e.g., from 350° to 10°) local rotDiff = targetRotation - camRotation if rotDiff > 180 then rotDiff = rotDiff - 360 elseif rotDiff < -180 then rotDiff = rotDiff + 360 end -- Smooth the rotation camRotation = camRotation + rotDiff * turnSmooth -- Keep rotation in 0-360 range if camRotation >= 360 then camRotation = camRotation - 360 elseif camRotation < 0 then camRotation = camRotation + 360 end -- Use the smoothed rotation for camera position local rad = math.rad(camRotation) local targetX = x + math.sin(rad) * baseDist local targetY = y - math.cos(rad) * baseDist local targetZ = z + height -- Initialize camera position and rotation first time if not camX then camX, camY, camZ = targetX, targetY, targetZ camRotation = rz end -- Smooth position interpolation camX = camX + (targetX - camX) * smooth camY = camY + (targetY - camY) * smooth camZ = camZ + (targetZ - camZ) * smooth -- Apply camera matrix setCameraMatrix(camX, camY, camZ, x, y, z + 0.3) end -- Enable chase cam function enableChaseCam() if chaseCamEnabled then return end local veh = getPedOccupiedVehicle(localPlayer) if not veh then outputChatBox("You must be in a vehicle!", 255, 0, 0) return end chaseCamEnabled = true camX, camY, camZ = nil, nil, nil -- Store original FOV originalFOV = getCameraFieldOfView("player") outputChatBox("Original FOV: " .. originalFOV, 255, 255, 0) -- Start the camera update loop addEventHandler("onClientRender", root, updateChaseCam) -- Create a timer to constantly apply FOV (this is the key fix) if fovTimer then killTimer(fovTimer) end fovTimer = setTimer(applyFOV, 50, 0) -- Apply FOV every 50ms -- Apply initial FOV setTimer(function() setCameraFieldOfView("player", fov) outputChatBox("Chase camera enabled (FOV: " .. fov .. ")", 0, 255, 0) end, 100, 1) -- Slight delay to ensure camera matrix is set first end -- Disable chase cam function disableChaseCam() if not chaseCamEnabled then return end chaseCamEnabled = false camX, camY, camZ = nil, nil, nil camRotation = 0 -- Stop the update loop removeEventHandler("onClientRender", root, updateChaseCam) -- Stop FOV timer if fovTimer then killTimer(fovTimer) fovTimer = nil end -- Restore normal camera setCameraTarget(localPlayer) -- Restore original FOV with a small delay if originalFOV then setTimer(function() setCameraFieldOfView("player", originalFOV) outputChatBox("FOV restored to: " .. originalFOV, 255, 255, 0) end, 100, 1) end outputChatBox("Chase camera disabled", 255, 0, 0) end -- Toggle chase cam with C bindKey("c", "down", function() outputChatBox("C key pressed", 255, 255, 255) if chaseCamEnabled then disableChaseCam() else if isPedInVehicle(localPlayer) then enableChaseCam() else outputChatBox("You must be in a vehicle to use chase camera!", 255, 0, 0) end end end) -- Auto disable on exit vehicle addEventHandler("onClientPlayerVehicleExit", localPlayer, function() if chaseCamEnabled then disableChaseCam() end end) -- FOV command with better handling addCommandHandler("setfov", function(cmd, newFOV) local fovValue = tonumber(newFOV) if not fovValue then outputChatBox("Usage: /setfov [30-180]", 255, 255, 0) outputChatBox("Current FOV variable: " .. fov, 255, 255, 0) local currentFOV = getCameraFieldOfView("player") outputChatBox("Current camera FOV: " .. currentFOV, 255, 255, 0) return end if fovValue < 30 or fovValue > 180 then outputChatBox("FOV must be between 30 and 180", 255, 0, 0) return end fov = fovValue outputChatBox("FOV variable set to: " .. fov, 0, 255, 0) -- If chase cam is active, apply the new FOV if chaseCamEnabled then -- Apply multiple times to ensure it sticks setCameraFieldOfView("player", fov) setTimer(function() setCameraFieldOfView("player", fov) local actualFOV = getCameraFieldOfView("player") outputChatBox("New FOV applied: " .. actualFOV, 255, 255, 0) end, 100, 1) end end) -- Camera distance command addCommandHandler("camdist", function(cmd, newDist) local distValue = tonumber(newDist) if not distValue then outputChatBox("Usage: /camdist [1-50]", 255, 255, 0) outputChatBox("Current distance: " .. baseDist, 255, 255, 0) return end if distValue < 1 or distValue > 50 then outputChatBox("Distance must be between 1 and 50", 255, 0, 0) return end baseDist = distValue outputChatBox("Camera distance set to: " .. baseDist, 0, 255, 0) end) -- Camera height command addCommandHandler("camheight", function(cmd, newHeight) local heightValue = tonumber(newHeight) if not heightValue then outputChatBox("Usage: /camheight [-10 to 20]", 255, 255, 0) outputChatBox("Current height: " .. height, 255, 255, 0) return end if heightValue < -10 or heightValue > 20 then outputChatBox("Height must be between -10 and 20", 255, 0, 0) return end height = heightValue outputChatBox("Camera height set to: " .. height, 0, 255, 0) end) -- Test commands addCommandHandler("testcam", function() outputChatBox("=== Camera Debug Info ===", 255, 255, 0) outputChatBox("Chase cam enabled: " .. tostring(chaseCamEnabled), 255, 255, 0) outputChatBox("In vehicle: " .. tostring(isPedInVehicle(localPlayer)), 255, 255, 0) outputChatBox("FOV variable: " .. fov, 255, 255, 0) outputChatBox("Camera FOV: " .. getCameraFieldOfView("player"), 255, 255, 0) outputChatBox("Distance: " .. baseDist .. ", Height: " .. height, 255, 255, 0) if camX then outputChatBox("Camera pos: " .. string.format("%.2f, %.2f, %.2f", camX, camY, camZ), 255, 255, 0) end if fovTimer then outputChatBox("FOV timer active: YES", 0, 255, 0) else outputChatBox("FOV timer active: NO", 255, 0, 0) end end) -- Camera smoothness commands addCommandHandler("camsmooth", function(cmd, type, value) local val = tonumber(value) if not type or not val then outputChatBox("Usage: /camsmooth [pos/turn] [value]", 255, 255, 0) outputChatBox("pos = position smoothing (0.1-1.0)", 255, 255, 0) outputChatBox("turn = turn smoothing (0.01-0.5)", 255, 255, 0) outputChatBox("Current: pos=" .. smooth .. ", turn=" .. turnSmooth, 255, 255, 0) return end if type == "pos" or type == "position" then smooth = math.max(0.1, math.min(1.0, val)) outputChatBox("Position smoothing set to: " .. smooth, 0, 255, 0) elseif type == "turn" or type == "rotation" then turnSmooth = math.max(0.01, math.min(0.5, val)) outputChatBox("Turn smoothing set to: " .. turnSmooth, 0, 255, 0) outputChatBox("(Lower = smoother turns, Higher = more responsive)", 255, 255, 0) else outputChatBox("Unknown type. Use 'pos' or 'turn'", 255, 0, 0) end end) -- Preset smoothing commands addCommandHandler("smoothcinematic", function() smooth = 0.1 turnSmooth = 0.03 outputChatBox("Cinematic smoothing applied", 0, 255, 0) outputChatBox("Position: " .. smooth .. ", Turn: " .. turnSmooth, 255, 255, 0) end) addCommandHandler("smoothnormal", function() smooth = 0.3 turnSmooth = 0.08 outputChatBox("Normal smoothing applied", 0, 255, 0) outputChatBox("Position: " .. smooth .. ", Turn: " .. turnSmooth, 255, 255, 0) end) addCommandHandler("smoothresponsive", function() smooth = 1.0 turnSmooth = 0.2 outputChatBox("Responsive smoothing applied", 0, 255, 0) outputChatBox("Position: " .. smooth .. ", Turn: " .. turnSmooth, 255, 255, 0) end) -- FOV presets addCommandHandler("fovwide", function() fov = 90 if chaseCamEnabled then setCameraFieldOfView("player", fov) setTimer(function() setCameraFieldOfView("player", fov) end, 100, 1) end outputChatBox("Wide FOV set: " .. fov, 0, 255, 0) end) addCommandHandler("fovnormal", function() fov = 70 if chaseCamEnabled then setCameraFieldOfView("player", fov) setTimer(function() setCameraFieldOfView("player", fov) end, 100, 1) end outputChatBox("Normal FOV set: " .. fov, 0, 255, 0) end) addCommandHandler("fovnarrow", function() fov = 50 if chaseCamEnabled then setCameraFieldOfView("player", fov) setTimer(function() setCameraFieldOfView("player", fov) end, 100, 1) end outputChatBox("Narrow FOV set: " .. fov, 0, 255, 0) end) -- Resource start notification addEventHandler("onClientResourceStart", resourceRoot, function() outputChatBox("=== Enhanced Smooth Chase Camera ===", 0, 255, 0) outputChatBox("Controls: C = Toggle camera", 255, 255, 0) outputChatBox("Camera: /camdist [1-50], /camheight [-10 to 20]", 255, 255, 0) outputChatBox("FOV: /setfov [30-180], /fovwide, /fovnormal, /fovnarrow", 255, 255, 0) outputChatBox("Smoothing: /camsmooth [pos/turn] [value]", 255, 255, 0) outputChatBox("Presets: /smoothcinematic, /smoothnormal, /smoothresponsive", 255, 255, 0) outputChatBox("Debug: /testcam", 255, 255, 0) outputDebugString("[Enhanced Chase Camera] Resource loaded") end) -- Resource stop notification addEventHandler("onClientResourceStop", resourceRoot, function() if chaseCamEnabled then disableChaseCam() end outputChatBox("Enhanced Chase Camera unloaded", 255, 100, 100) end) Link to comment
iNawaF Posted August 26 Share Posted August 26 The core issue is that MTA automatically resets the FOV when entering a vehicle. In your code, the custom FOV is only applied when the chase camera is enabled, so it gets reset upon vehicle entry. To fix this, apply the FOV continuously or bind it to the onClientPlayerVehicleEnter event to ensure it stays consistent while driving Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now