I am unable to wrap my head around sine and cosine

i want to figure out sine and cosine so that i can make camera bobbing and things like that. however: trying to get it right is just a lot more difficult than i anticipated. i’d like to make a basic figure 8 on the y-axis so i can warm up to using sin & cos. i’ve been messing around with desmos but it isn’t clicking for me.

one of the tutorials i watched suggested multiplying the cframe for all of the axes i want to move and setting axes i want to ignore to 0. but that makes it move very far and in an arch.

part.CFrame *= CFrame.new(x, y, 0)

can someone please explain what sin and cos do and how i can use them properly?

-- sine wave formula: math.sin(tick() * frequency) / displacement (?) <-- am i doing this right

local frequency = 2
local amplitude = 5
local part = workspace:FindFirstChild("mover")
local startTime = tick()

game:GetService("RunService").Heartbeat:Connect(function()
	local timeElapsed = tick() - startTime
	local x = math.sin(timeElapsed * frequency) * amplitude
	local y = math.cos(timeElapsed * frequency) * amplitude * math.sin(timeElapsed * frequency)
	part.CFrame *= CFrame.new(x, y, 0)
end)

You can add decimals to offset the wave forward, making a phase shift, like this:

local x = math.sin(timeElapsed * frequency + 0.13) * amplitude

or multiply the y axis a little:

local y = math.cos(timeElapsed * frequency * 1.25) * amplitude -- 1.25 or 1.5

sin is a wave that goes up and down
cos is the same thing but shifted to the left/right slightly

if you want to make a figure 8 then you can use either sin or cos (doesnt matter) to make the up/down movement, and the other one to make the horizontal movement

if the speed of the horizontal movement is faster than the speed of the vertical movement (by multiplying whats inside) then you can make a figure 8

now it’s moving in a circle instead of a figure 8

part.CFrame *= CFrame.new(math.cos(tick() * frequency) / amplitude, math.sin(tick() * frequency) / amplitude, 0)

Offset the axis with a phase shift, look at my comment, I gave you 2 ways.

that did not fix it, it still moved in an oversized arch

try this:

local frequency = 2
local amplitude = 5
local part = workspace:FindFirstChild("mover")
local startTime = tick()

game:GetService("RunService").Heartbeat:Connect(function()
    local timeElapsed = tick() - startTime
    local x = math.sin(timeElapsed * frequency) * amplitude
    local y = math.cos(timeElapsed * frequency) * amplitude * math.sin(timeElapsed * frequency)
    
    part.CFrame = CFrame.new(x, y, 0)
end)

or

local frequency = 2
local amplitude = 5
local part = workspace:FindFirstChild("mover")
local startPos = part.Position
local startTime = tick()

game:GetService("RunService").Heartbeat:Connect(function()
    local timeElapsed = tick() - startTime
    local x = math.sin(timeElapsed * frequency) * amplitude
    local y = math.cos(timeElapsed * frequency) * amplitude * math.sin(timeElapsed * frequency)
    
    part.CFrame = CFrame.new(
        startPos.X + x,
        startPos.Y + y,
        startPos.Z
    )
end)

You can also try to lower the decimal on the phase shift, for a less exaggerated wave.

one of them has to be faster

local horizontalFrequency = frequency * 2
local verticalFrequency = frequency

part.CFrame *= CFrame.new(math.cos(tick() * horizontalFrequency) / amplitude, math.sin(tick() * verticalFrequency) / amplitude, 0)