La caméra par défaut de Roblox manque cruellement de souplesse dans les jeux d'action, provoquant des saccades brutales au contact des murs.
En exploitant CameraType.Scriptable et RenderStepped, on peut concevoir une caméra sur mesure combinant inertie par ressorts et détection volumétrique des parois via Spherecast.
1. Faiblesses du système de caméra natif
Pourquoi les jeux compétitifs nécessitent une caméra personnalisée :
- Saccades au mur : Téléportation brusque lors de collisions dans les espaces exigus.
- Absence d'inertie : Mouvements robotiques sans sensation de poids naturel.
- Obstruction visuelle : Le personnage masque le réticule en vue centrée.
- Contrôle Scriptable : Liberté absolue de calcul sur la matrice CFrame.
2. Physique de ressort et amortissement critique
Inertie fluide sans oscillations indésirables :
- Amortissement critique : Ratio fixé à 1.0 pour une stabilisation instantanée.
- Simulation de masse : Dynamique naturelle lors des accélérations et sauts.
- Orientation dissociée : Visée immédiate à la souris pendant que la position suit avec souplesse.
- Indépendance temporelle : Intégration stricte avec delta-temps (dt).
--!strict
local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local CameraController = {}
local camera = Workspace.CurrentCamera
local player = Players.LocalPlayer
local yaw, pitch = 0, 0
local targetDistance, currentDistance = 12, 12
local springPos, springVel = Vector3.zero, Vector3.zero
local SPHERE_RADIUS = 0.6
local RAY_PARAMS = RaycastParams.new()
RAY_PARAMS.FilterType = RaycastFilterType.Exclude
function CameraController.Init()
camera.CameraType = Enum.CameraType.Scriptable
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
RunService.RenderStepped:Connect(CameraController.Update)
end
function CameraController.Update(dt: number)
local char = player.Character
if not char or not char:FindFirstChild("Head") then return end
local head = char.Head :: BasePart
RAY_PARAMS.FilterDescendantsInstances = { char }
local focus = CFrame.new(head.Position) * CFrame.Angles(0, yaw, 0) * CFrame.Angles(pitch, 0, 0)
local force = (Vector3.new(2.2, 1.0, 0) - springPos) * 140 - (springVel * 22)
springVel += force * dt
springPos += springVel * dt
local targetPos = (focus * CFrame.new(springPos)).Position - (focus.LookVector * targetDistance)
local hit = Workspace:Spherecast(head.Position, SPHERE_RADIUS, targetPos - head.Position, RAY_PARAMS)
local adjDist = targetDistance
if hit and hit.Instance and hit.Instance.CanCollide then
adjDist = math.max(1.5, (hit.Position - head.Position).Magnitude - SPHERE_RADIUS)
end
currentDistance += (adjDist - currentDistance) * math.min(1, dt * 25)
camera.CFrame = focus * CFrame.new(springPos) * CFrame.new(0, 0, currentDistance)
end
return CameraController
3. Détection d'obstacles par Spherecast volumétrique
Empêcher la caméra de passer à travers les murs solides :
- Analyse volumique : Le Spherecast balaie une sphère 3D autour de la caméra.
- Marge de recul : Maintien d'un espace de sécurité avec les parois.
- Retour progressif : Agrandissement en douceur après un passage étroit.
- Efficacité sur les angles : Prise en compte parfaite des arêtes vives.
4. Changement d'épaule et visée précise (ADS)
Adapter l'angle de vue selon la situation tactique :
- Bascule d'épaule : Alternance droite-gauche pour regarder derrière les angles.
- Zoom de visée : Réduction du champ de vision (FOV) lors du tir.
- Correction de parallaxe : Alignement des tirs avec le centre de l'écran.
- Inertie de sprint : Recul dynamique lors des pointes de vitesse.
5. Ergonomie mobile et contrôles tactiles
Prise en main optimisée pour les écrans tactiles et manettes :
- Pincement pour zoomer : Réglage fluide de la distance de caméra.
- Zone droite dédiée : Rotation de la vue séparée du joystick virtuel.
- Réponse exponentielle : Précision accrue sur les sticks analogiques.
- Calcul 100% local : Aucune transmission réseau superflue.
Frequently Asked Questions
Pourquoi préférer le Spherecast au Raycast simple ?
Le Spherecast prend en compte le volume physique de la caméra, empêchant la lentille d'entrer dans les textures de mur.
Comment éliminer les tremblements près des obstacles ?
En lissant les variations de distance par interpolation asymptotique.
Le calcul par image ralentit-il les smartphones ?
L'exécution prend moins de 0.05 ms par image, préservant une fluidité à 60 FPS.