Using math for camera movement

I’m trying to make a script that makes the camera follow this figure-8 shape as shown in the photo, but I can’t seem to do it reasonably well.


I’ve sort-of hacked together a solution using tick() and a sine-wave function (shown below), but it doesn’t follow the shape very well at all and is more of a general camera-bobbing. I know a fair portion about these trigonometric functions, but I sometimes get confused about how they can translate into camera movement in a ROBLOX game. Thanks.

My current one that barely achieves the goal at all:

RenderStepped:Connect(function()
	local Main = math.rad(math.sin(tick() * math.clamp(HumanoidRootPart.Velocity.Magnitude, 0, 10)));

	Camera.CFrame = (Camera.CFrame * (CFrame.Angles(Main * 0.08, 0, Main * 0.24)));
end);
1 Like

One way that might work is using Bezier Curves, to get the effect that the camera is moving in the way you mentioned

Thanks, but how can I even begin to apply this? Based on this wiki page, I can’t fathom a way to create a figure-8 shape and have the camera follow it based on the curve.

I would suggest using Lissajous curves or sin waves for this. Here’s a good source to read up on:

I saw this in another thread for the same problem, and again, I’m not sure how I can make these equations and whatnot rotate the camera in the correct way…
Like, what variables to plug in, what I’m supposed to do with the output of the function, etc

Using some basic sin waves:

x = xOffset * math.sin(speed * tick());
y = yOffset * math.sin(speed * tick());

Essentially we are graphing the camera offset in a two-dimensional graph and then applying that offset to the camera based on where the cameraSubject is.

Ex: camera.CFrame = cameraSubject.CFrame * CFrame.new(Vector3.new(x,y,0))

I’m not as familiar with lissajous curves but I believe it would basically be:

math.sin((tick()*a) + b) * c

with variables:
a = frequency
b = offset
c = intensity/amplitude

3 Likes

Worked very smoothly, thanks! Also helps clear up a bit of the confusion I had with relating graph functions with in-game stuff.

I don’t mean to bump up this topic, but can you clear up the part of the “xOffset” and “yOffset”? Do you mean that as in the humanoid’s CameraOffset?

xOffset and yOffset are the amplitudes of offset that you want to apply to the camera. So, for this equation:
x = xOffset * math.sin(speed * tick());
We know that math.sin is going to return a number between 0 and 1, when it returns 0, the camera offset will be 0, when it returns 1, the camera offset will be equal to xOffset, any number in between will be a lerp between 0 and xOffset. If you want the camera to offset by a large factor on the x-axis, make xOffset large. If you want the offset to be small, make xOffset small.

1 Like

So, something like this?

local runService = game:GetService("RunService")
local camera = workspace.CurrentCamera

local speed = 1

local xOffset = Vector3.new(10,0,0)
local yOffset = Vector3.new(0,10,0)

local function step()
	local x = xOffset * math.sin(speed * tick());
	local y = yOffset * math.sin(speed * tick());
	
	camera.CFrame = camera.CFrame * CFrame.new(x, y, 0)
end

runService.RenderStepped:Connect(step)

Close, but x and y need to be numbers. As you can see the code constructs a new CFrame using x and y, so they can’t be Vector3s.

local runService = game:GetService("RunService")
local camera = workspace.CurrentCamera

local speed = 1

local xOffset = 10
local yOffset = 10

local function step()
	local x = xOffset * math.sin(speed * tick());
	local y = yOffset * math.sin(speed * tick());
	
	camera.CFrame = camera.CFrame * CFrame.new(x, y, 0)
end

runService.RenderStepped:Connect(step)
1 Like