Movement with Camera

Attempting to make a Camera-bob with a motion similar to this;
been unsuccessful so far,
So far I’ve attempted While loops and For i = 's to no prevail.

Was wondering if Tweening would be a better solution, and if so how would I go about it for this movement.


Seems like you need to implement a sine or cosine loop CFrame rotation to the camera’s CoordinateFrame.

Something like this might work. (I’m not compiling this/running it at all so there might be errors)

local RUN = game:GetService"RunService"
local player = game:GetService"Players".LocalPlayer
local camera = workspace.CurrentCamera

local startPart = workspace.CameraPart -- something you place to keep it facing forward

RUN:BindToRenderStep("CameraEffect", Enum.RenderPriority.Last.Value, function()
    camera.CFrame = startPart.CFrame * CFrame.Angles(math.rad(math.sin(tick())), math.rad(math.sin(tick())), math.rad(math.sin(tick())))

SOMETHING like this, I’m not really sure if it’ll get you what you want.


For camera movement, you will want to use RunService:BindToRenderStep()

This will allow your code to run as every frame is rendered, and will stop any jittering and tearing on the screen. Don’t go overboard with this though, as it yields the actual frame rendering and can easily reduce the framerate if you do too much processing.

In terms of the actual bobbing motion, it depends on what you want exactly, but I’d experiment with just some basic time-based stuff, and just define the movement using sines with different periods and amplitudes. To get a really intricately controlled effect you could create some keyframes or even use some sort of physical object that you bind the camera to, but it all depends on the details of what you are aiming for.

And yes this is exactly what I mean, although I would have the priority before the camera renders (Camera’s RenderPriority is 200, so use <200), rather than last, and mess with those different sines to get a more exact effect.

1 Like

The RenderPriority value of the camera is 200. Any number > 200 will run above the Camera.

1 Like

You’ll definitely want to use sine or cosine, as these produce waves over time.
Here’s a quick code sample I wrote up, it probably won’t work out of the box since I haven’t tested it but it should work somewhat.

local headbob =
local dt = 0
local moving = true --use something to set whether the character is moving or not
--I assume this should only run when the character is walking or running but this will
--only implement walking

    dt = dt + s
    if not moving then dt = 0 end
    headbob = headbob:lerp(CFrame.Angles(0.5 * math.sin(dt * 2), 2 * math.cos(dt * 0.6), 0), 0.7)
    --you may want to change the 0.7 value, but this essentially makes it so when dt ends it smoothly
    --transitions to to end the animation
    --camera.CFrame = --etc, however you want to set it

When you use math.sin or math.cos;
(for example lets say a * math.sin(dt * b))
dt is the total time elapsed
a is the amplitude or the exremity of the wave, smaller values make it smaller, while bigger make it bigger
b is the speed or the wave, or how quickly is goes from positive to negative.

Actually, here’s a graph to show what I mean:

The black wave represents y = 5 * sin(x * 2) or 5 * math.sin(dt * 2)
The red wave represents y = 0.5 * sin(x * 0.75) or 0.5 * math.sin(dt * 0.75)

You’ll notice that this wave is very large in size (very high on y axis), this is because of the 5 which says how big it will be.
You’ll also notice that its pretty tight wave, this is because of the 2 which says its going to oscillate (go up and down) 2 times as fast as normal (if you wanted it to be in hertz, or cycles per second you would do dt*2*pi*2 as the sin and cos functions are trigonometric functions and have to do with circles, so by doing that it will complete 2 full cycles per second.

The second wave is much smaller because of the amplitude is much smaller (0.5) and is also much more stretched out (0.75).

I hope this helps.


You might want to layer on some noise as well. Using something strictly like sin or cos is fine, but it can look a bit unnatural. Adding some noise will make it feel more “real”


I’ll correct that in the original post, thanks for catching that. I’d usually use the Enum so I don’t remember the values lol.

Although just to clarify, lower numbers run first, so <200 would run before the camera, and >200 would run afterwards.

1 Like