Making a bobbing function time dependant

I want to make something bob up and down based on the current tick() time. Here is my current code:

function FindPosition(DistanceFrom0)
	local XCoord = DistanceFrom0 * WorldGuiHandler.Settings.XSpread
	local YCoord = (DistanceFrom0 == 0 and 0 or 2) 
	local ZCoord =  DistanceFrom0 == 0 and WorldGuiHandler.Settings.ZCentre or WorldGuiHandler.Settings.ZOutside
	
	if WorldGuiHandler.Settings.YBobbingEnabled then -- STUFF RELATED TO QUESTION
		local BobDistance = 1
		
		local TimeRemainder = tick() % 4  --(tick() + (DistanceFrom0 / 2)) % 4
		local TimeOffset = TimeRemainder
	
		YCoord = YCoord + (TimeOffset * BobDistance)
	end
	
	return Center.Position + Vector3.new(XCoord,YCoord,ZCoord)
end

The issue is when tick % 4 = 3.9 for example, the function puts it very high up, but then it becomes 0, and moves it down to the start instantly, with no some ease from top to bottom, just bottom to top.

Without getting conditionals involved and just sticking to maths (mostly because I want to learn), what is the best way to achieve this?

Thanks

Here is one way you could do it:

local TimeOffset = (TimeRemainder < 2 and TimeRemainder or 4 - TimeRemainder)

This type of behavior will act as an absolute value, being linear with a positive slope for the first half and linear with a negative slope for the second half. You may want to look into something like a sine curve though.

For a sine curve, you would want the domain to be from -pi/2 to 3pi/2 radians, and the range from 0 to 1 instead of -1 to 1. Here is the idea of what to do:

local SineXPoint = (-math.pi/2) + ((TimeRemainder/4) * (math.pi * 2))
local TimeOffset = (0.5 * math.sin(SineXPoint)) + 0.5

Be aware I haven’t tested any of these to make sure they have the correct value.

3 Likes

The most conventional way of making position a sinusoidal function of time is just this:

local pos = math.sin( w * tick())

Where w is frequency in radians per second (engineering convention uses lowercase omega). Conversion from cycles per second requires a 2π ( w = 2 * math.pi * freqInHz). This position swings -1 to 1 of course, not 0 to 1 like TheNexusAvenger’s example.

If you need things bobbing at the same rate, but at different points in the cycle, you can add a phase shift term like so:

local pos = math.sin( w * tick() + phase)

Phase can have any value, of course, but naturally you don’t need values outside of the range 0 to 2π ( or -π to π if you prefer that). If the large value of tick() bothers you, or makes debugging prints less clear, you can use time(), or tick()-tickAtGameStart, or even time()%(2*math.pi) if you want a value always in the range 0 to 2π.

5 Likes