Some reasoning behind this module
I faced a problem while making an upcoming VR game: I needed to have certain movements be smoothened without snapping. We couldn’t just use a tween, that would be buggy. Instead, we decided wave movement would be the best option. More specifically, sine wave oscillations.
Essentially, this module allows you to create an instance that automatically creates two types of sine-based movements:
- Sine Ease-Out
- Sine Ease-In-Out
What are wave based movements?
Wave based movements are used for creating smooth, often human-like, movements in many situations. Instead of snapping to a position, we can interpolate between a selected start, and a designated, often dynamic, target.
Let’s take a look at the result of both types of movement:
Sine Ease-Out
This type of movement is smooth. It starts out linear, and gradually slows down towards the end. Let’s look at a visualization:
This can be used for example, a car braking. We could have the car reach a destination at a given speed, and then slow down towards the end.
Sine Ease-In-Out
This is the other type of movement covered so far. It starts out by gradually speeding up into a linear movement, and then slows towards the end. Here’s another visualization:
As you can see, this is perfect for human-like movement, just like I needed. It’s not too linear, nor too inaccurate like typical lerping.
Now that we know the difference between the too, and what they can do, let’s take a look at the module!
Module API:
Oscillatory.new()
Creates a new Oscillatory instance.
Oscillatory:SetSpeed(speed)
Change “speed” to any number. This calculates the total length, in seconds, through 1/speed
Oscillatory:SetDuration(duration)
Change duration to any amount of time in seconds. This sets the total length, in seconds.
Oscillatory:GetAlpha()
Returns the current alpha for interpolation. Equivalent to Oscillatory.Alpha
Oscillatory:Start()
Starts the timing process. This also resets the elapsed time. Make sure to run this before interpolating, otherwise you will be stuck on weird numbers.
Oscillatory:Update()
Calculates everything needed upon being called. Use this before retrieving the wave X and alpha.
Properties
class.Types: Array
- The types of waves supported. Select this before running the start function.
class.Duration
- The duration set
class.Elapsed
- Total time elapsed since the start function was called
class.Alpha
- Current calculated alpha for interpolation
class.Value
- Current wave x position
class.LastUpdate
- Used for calculating elapsed time
class.Type
- Set this using class.Types
before running the start function
class.IsFinished
- Has the oscillation completed?
Example Usage:
local a = workspace.a -- Part
local b = workspace.b -- Part
local start = a.Position -- Starting position
local speed = 0.25 -- Our speed
-- Set up the oscillatory instance
local oscillatory = require(workspace.Oscillatory).new()
oscillatory.Type = oscillatory.Types.Sine_Ease_In_Out
oscillatory:SetSpeed(speed)
oscillatory:Start()
game:GetService("RunService").Heartbeat:Connect(function()
oscillatory:Update() -- Update the instance
local alpha = oscillatory:GetAlpha() -- Get our current alpha
local new = start:Lerp(b.Position,alpha) -- Calculate the current position
a.Position = new -- Set the position
end)
MODULE DOWNLOAD:
Oscillatory_v1.0.0.rbxm (1.5 KB)
or
SOURCE CODE
local class = {}
class.__index = class
class.Types = {
["Sine_Ease_Out"] = 0,
["Sine_Ease_In_Out"] = 1,
}
class.Duration = 0
class.Elapsed = 0
class.Alpha = 0
class.Value = 0
class.LastUpdate = 0
class.Type = class.Types.Sine_Ease_Out
class.IsFinished = false
local sin = math.sin
local cos = math.cos
local pi = math.pi
local piHalf = pi/2
--[[
Creates a new Oscillatory instance.
]]
function class.new()
local self = {}
setmetatable(self,class)
return self
end
--[[
Sets the duration as a speed.
]]
function class:SetSpeed(speed: number)
self.Duration = 1/speed
end
--[[
Sets the duration in seconds.
]]
function class:SetDuration(duration: number)
self.Duration = duration
end
--[[
Gets the current interpolated alpha.
(equivalent to Oscillatory.Alpha)
This can be used to calculate the new value with interpolation.
]]
function class:GetAlpha()
return self.Alpha
end
--[[
Starts the elapsed time.
Can be used to reset the time.
]]
function class:Start()
self.Elapsed = 0
self.LastUpdate = tick()
end
--[[
MAKE SURE YOU HAVE RAN THE START FUNCTION!
Automatically gets the delta time.
]]
function getAlpha(type: number, progress)
if type == class.Types.Sine_Ease_Out then
return sin(progress * piHalf)
elseif type == class.Types.Sine_Ease_In_Out then
return 0.5 * (1 - cos(progress * pi))
end
end
function class:Update()
local t = tick()
self.Elapsed += (t - self.LastUpdate)
self.LastUpdate = t
local progress = math.clamp(self.Elapsed/self.Duration,0,1)
self.IsFinished = progress >= 1
local alpha = getAlpha(self.Type,progress)
self.Value = progress
self.Alpha = alpha
end
return class
Feel free to request other types of waves to be added!
If you're interested in this new VR FPS game....
Consider joining our Discord to find out more!
ATHENA
How useful would you rate this?
- 5 - Very useful
- 4 - Useful
- 3 - Somewhat useful
- 2 - Barely useful
- 1 - Not useful at all
0 voters