Camera system that rotates based on velocity direction

Hi, currently am having an issue writing a camera system that works off of a car’s AssemblyLinearVelocity. Basically what I need is the direction of that velocity of wherever the car is moving to and rotating the camera accordingly to face that direction.

I am also having an issue that when I orbit around the car with the right stick, I have the camera tilted by -5 degrees on the x axis. When it orbits to 180 degrees, that angle becomes 5 degrees.

Here is my code now:

    local pivot_origin = car.DriveSeat.CFrame * CFrame.new(Vector3.new(-1.5))
	local ang = CFrame.Angles(-math.rad(6), script.angX.Value, 0)
	cam.CFrame = pivot_origin*ang*CFrame.new(0,3.5,17.75)

My main question is getting the direction and applying it to the camera’s CFrame accordingly without messing up the orbital system I have now.

Bumping this due to inactivity, to clarify, I’m trying to rotate the camera based on a unit vector provided from the AssemblyLinearVelocity, and I do not know how to translate that normal into a rotation across the y axis so that the camera will offset the rotation based on the velocity.

I dont undestand exactly what those values ure using means nor how do you want the cam to behave, but i can try giving you this idea

You can get a CFRame rotated to the velocity vector like this, which you can do with your current CFrame result

local CurrentCFrame = pivot_origin*ang*CFrame.new(0,3.5,17.75)

local rotatedToVelocity = CFrame.new(CurrentCFrame.Position, CurrentCFrame.Position + Car.AssemblyLinearVelocity)

Make sure you check if that AssemblyLinearVelocity is not zero or this CFrame will return with some “nan” values. In case of “nan” values you can change the direction to a pattern one. If you try to set something to a CFrame with “nan” values you can get a lot of network related bugs.

to know if a value is nan:

local function isnan(arg: any): boolean
	return not rawequal(arg, arg)
end 

You can just check if the velocity is Vector3.new(0,0,0) though.
Then you can also use CFrame:Lerp() to change the camera’s direction according to the speed.Magnitude with something like

Camera.CFrame = CurrentCFrame:Lerp(rotatedToVelocity, Car.AssemblyLinearVelocity.Magnitude / MaxSpeed)

This helps a little bit, if this video will help make it clearer to what i am trying to achieve:

The camera points in the direction the car is heading while keeping the car on the center of the screen. This is basically the effect I am heading for. I thought using velocity would be the best way (and probably is), but let me know. Thank you for the assistance

Well, i have some theories for that:

that first one could work out good, ill see if i can implement

this implementation doesnt work as intended
https://gyazo.com/177f01fe193df0058c072959e6490552

it seems to look towards a certain point and not at all towards the front of the car

How is this wrong? How do you think it should behave?

Its hard to tell what is different in your video sinse your car is not going high speed.

Looks like the offset position of your camera is fixed by the world’s orientation, shouldnt it be fixed over the car’s orientation? So when you turn, the camera goes to the back of your car, turning with it

yeah it should, but it doesnt do that, is it basing off the world space and not the pivoting origin as declared in the script? ill paste my function so far:

RunService:BindToRenderStep("CamTest", Enum.RenderPriority.Camera.Value + 1, function(deltaTime)
	local pivot_origin = car.DriveSeat.CFrame.Position + Vector3.new(1.5)
	local offset = Vector3.new(0,3.5,17.75)
	local ang = CFrame.Angles(-math.rad(6), script.angX.Value, 0)
	local assemVelocity = car.DriveSeat.AssemblyLinearVelocity

	local newCF = CFrame.new(pivot_origin)*ang*CFrame.new(offset)
	local rotatedToVelocity = CFrame.new(Vector3.new(newCF.Position.X+offset.X, newCF.Position.Y+offset.Y, math.clamp(newCF.Position.Z, pivot_origin.Z+offset.Z, pivot_origin.Z+offset.Z)), newCF.Position+assemVelocity)
	cam.CFrame = newCF:Lerp(rotatedToVelocity, math.clamp(math.abs(assemVelocity.Magnitude/125), 0.1, 1))
end)

it should act as it should in the youtube video posted above, that is the effect i am going for. it seems to just be pointing to position in the world and not snapping back to the car

shouldnt it have 3 args? :face_with_raised_eyebrow:

Here, instead of

*CFrame.new(offset)

try

+ car.DriveSeat.CFrame.LookVector * -offset.Z + Vector3.new(0, offset.Y, 0)

it seems like the lerping could be the root issue, as I dont need it to be based around speed. it needs to keep the car on the screen. nothing seems to be making it so this happens, the camera always seems to just look off into the distance and nothing changes it
https://gyazo.com/942d5ad8a1332200a4c8259b09fb71e6

it should keep the car on the screen however that is not the case

I was testing something alike with the humanoid, here is the script (on starter character):

local cam = workspace.CurrentCamera
cam.CameraType = Enum.CameraType.Scriptable

local car = script.Parent:WaitForChild("HumanoidRootPart")
local zero = Vector3.new()

game:GetService("RunService"):BindToRenderStep("CamTest", Enum.RenderPriority.Camera.Value + 1, function(deltaTime)
	local carCF = car.CFrame
	local offset = Vector3.new(0,3.5, 0) + carCF.LookVector * -10
	local ang = CFrame.Angles(-math.rad(6), 0, 0)
	local vel = car.AssemblyLinearVelocity ~= zero and car.AssemblyLinearVelocity or Vector3.new(0,0,-1)
	
	local camCF = CFrame.new(carCF.Position + offset, carCF.Position + offset + carCF.LookVector) * ang
	local rotatedToVelocity = CFrame.new(camCF.Position, carCF.Position + vel/10) -- speed max is 40 here, then vel/10 is max 4.
	cam.CFrame = camCF:Lerp(rotatedToVelocity, vel.Magnitude/40, 0.1, 1) -- i forgot to clamp, no need to math.abs though, magnitude is already absolute
end)


local hum = script.Parent:WaitForChild("Humanoid")

hum.WalkSpeed = 0

game:GetService("UserInputService").InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.W then
		while game:GetService("UserInputService"):IsKeyDown(Enum.KeyCode.W) do
			task.wait()
			hum.WalkSpeed = math.min(hum.WalkSpeed + 1, 40)
		end
		hum.WalkSpeed = 0
	end
end)

Note: besides that -math.rad(6) makes cam face more downwards, that orientation is still higher then rotatedToVelocity’s orientation (that is from “offset” to “root position + velocity”), so the camera faces more down instead of up when it gains speed.

1 Like

I would say this is the solution, I would also attempt to Tween this and add some sort of panning feature so it’s less snappy but this is essentially what he wants and this is why I love the dev forum!

Use one Tween for moving away and one when input ends, that just does the same but in a negative.

This will serve well as a base that I can build off of. Thank you so much for the help!
I do wonder if I can make that rotation orbit around the car instead of the camera itself being rotated, If i could do something like this:

cam.CFrame = originCF*lerprotation

I used this to make the orbiting camera, and then translated it back to the offset before adding in your code. I was wondering if i could replicate that with your code as well

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.