RblxTimer — Timer Library by Mubinet

RblxTimer, Timer Library


Introducing RblxTimer

:grey_question: What is RblxTimer?

  • RblxTimer is a simple, small library, with full support for type-checking (Luau) designed by @Mubinets.

‎ ‎


‎❔ Why should I use RblxTimer?

  • Full Support For Typechecking! :white_check_mark:
  • Designed with OOP in mind! :brain:
  • Easy To Use! :+1:
  • Listen for Events for Certain Actions (OnStarted, OnStopped, etc) :zap:
  • Your bugs are my bugs! It will be maintained by me, for long time!

‎ ‎


:grey_question:How To Use RblxTimer!

  • Get the source code directly!
  • Create new ‎ ModuleScript ‎ script in ReplicatedStorage or place of your choice
  • Paste the source code in the ModuleScript script.
  • Require the module and use!

‎ ‎


:grey_question: How To Actually Use RblxTimer?

  • Once you have required the module. You can start by creating a new timer. Here is the example:
local RblxTimer = require(...)

local timer : RblxTimer.Timer = RblxTimer.createTimer(60, 5) -- 60 Seconds with 5 Seconds interval
timer:start() -- Immediately starts the Timer object!

-- This function will run immediately for FIRST TIME and then ONCE every 5 seconds! (Interval)
timer.onElapsed:Connect(function(timerState : RblxTimer.TimerState)
  ‎ print("The clock is ticking...")
end

timer.onFinished:Connect(function(timerState : RblxTimer.TimerState)
 ‎ print("Round is starting!")

 ‎ . . . -- The rest code.
end

Source Code
--	Author  :  Mubinet (@mubinets | 5220307661)
--	Date    :  5/12/2024
--	Version :  1.0.1a

--!strict

------------ [[ ROBLOX SERVICES ]] ------------
local RunService = game:GetService("RunService")

------------ [[ USER MODULE ]] ------------
local RblxTimer = {} :: RblxTimer

------------ [[ USER TYPES ]] ------------
export type TimerStatus = "Pending" | "Running" | "Complete" | "Stopped" | "Paused"

--[[
    An object that provides information about the result of the Timer object.   
]]
export type TimerState = {
    --[[
        The value that is provided if the Timer object is either paused or stopped in time.
    ]]
	remainingTime   :  number?,

    --[[
        The status value describing the current state of the Timer object.
    ]]
	timerStatus : TimerStatus
}

--[[
    An object representing the time in the game.
]] 
export type Timer = {
    --[[
        The inital value in seconds in the construction of the Timer object.
    ]]
	initalTime             : number,

    --[[
        The event which fires on the completion of the timer, an TimerState object which provides information about the result will be given.
    ]]
	onFinished             : RBXScriptSignal<TimerState>,

    --[[
        The event which fires every interval of specified time. Defaults to 1 second internal if not specified
    ]]
	onElapsed              : RBXScriptSignal<TimerState>,

    --[[
        The event which fires when the Timer object has been stopped
    ]]
    onStopped              : RBXScriptSignal<TimerState>,

    
    --[[
        The event which fires when the Timer object has been paused
    ]]
    onPaused              : RBXScriptSignal<TimerState>,

    --[[
        The event which fires when the Timer object has been resumed
    ]]
    onResumed              : RBXScriptSignal<TimerState>,

    --[[
        The event which fires when the Timer object has started
    ]]
    onStarted              : RBXScriptSignal<TimerState>,

    --[[
        Returns the remaining time of the Timer object.
    ]]
	getRemainingTime       : (any) -> DateTime,

    --[[
        Stops the Timer object if not stopped already.
    ]]
	stop                   : (any) -> TimerState,

    --[[
        Resumes the Timer object if it has been paused. 
    ]]
	resume                 : (any) -> TimerState,

    --[[
        Pauses the Timer object if not paused already.
    ]]
	pause                  : (any) -> TimerState,

    --[[
        Starts the Timer object if not stopped already.
    ]]
	start                  : (any) -> TimerState,
}

--[[
    A user service for working with a timer object. 
]] 
export type RblxTimer = {
	createTimer  :   (number, number?)  ->  Timer
}

------------ [[ MAIN ]] ------------
--[[
    Creates a new object Timer with specified amount of time and optional interval in seconds.
]]
function RblxTimer.createTimer(seconds : number, interval: number?) : Timer

	-- Definitions
	local newTimerObject             = {}                            :: Timer
	local newElaspedBindableEvent    = Instance.new("BindableEvent") :: BindableEvent
	local newFinishedBindableEvent   = Instance.new("BindableEvent") :: BindableEvent
    local newStoppedBindableEvent    = Instance.new("BindableEvent") :: BindableEvent
    local newResumedBindableEvent    = Instance.new("BindableEvent") :: BindableEvent
    local newPausedBindableEvent     = Instance.new("BindableEvent") :: BindableEvent
    local newStartedBindableEvent    = Instance.new("BindableEvent") :: BindableEvent

	newTimerObject.onElapsed    = newElaspedBindableEvent.Event
	newTimerObject.onFinished   = newFinishedBindableEvent.Event
    newTimerObject.onStarted    = newStartedBindableEvent.Event
    newTimerObject.onPaused     = newPausedBindableEvent.Event
    newTimerObject.onStopped    = newStoppedBindableEvent.Event
    newTimerObject.onResumed    = newResumedBindableEvent.Event

	-- Object Private Constants
	local DEFAULT_INTERVAL = 1 :: number

	-- Object Private Properties
	local _initalTime        = seconds                            :: number
	local _currentTime       = seconds                            :: number
	local _timeElapsed       = 0                                  :: number
	local _interval          = interval or DEFAULT_INTERVAL       :: number
	local _currentTimerState = {}                                 :: TimerState
	local _isTicking         = false                              :: boolean

	-- Object Private Methods
	local function _tick()
        task.spawn(function()
            local heartbeatConnection : RBXScriptConnection do
                heartbeatConnection  = RunService.Heartbeat:Connect(function(deltatime : number)
                    if not (_isTicking) then return end
                    _currentTime -= deltatime
                    _timeElapsed += deltatime
        
                    if (_currentTime <= 0) then
                        _currentTimerState.remainingTime = nil
                        _currentTimerState.timerStatus   = "Complete"
                        _isTicking = false
        
                        newFinishedBindableEvent:Fire(_currentTimerState)
                        heartbeatConnection:Disconnect()
                    end
        
                    if (_timeElapsed >= _interval) then
                        _currentTimerState.remainingTime = math.round(_currentTime)
                        newElaspedBindableEvent:Fire(_currentTimerState)
    
                        _timeElapsed = 0
                    end
                end)
            end
        end)
	end

	local function _toggleTick(tickingToggle : boolean)
		if (_isTicking ~= tickingToggle) then
			_isTicking = tickingToggle

            if (tickingToggle == true) then
                _tick()
            end
		end
	end

	-- Object Private Properties Initalization
	_currentTimerState.remainingTime = _currentTime
	_currentTimerState.timerStatus   = "Pending"

	-- Object Initalization
	newTimerObject.initalTime = seconds

	-- Methods Definition
	newTimerObject.getRemainingTime = function() : DateTime
		return DateTime.fromUnixTimestamp(_currentTime)
	end

	newTimerObject.start = function() : TimerState
		if (_currentTimerState.timerStatus == "Pending") or (_currentTimerState.timerStatus == "Complete") or (_currentTimerState.timerStatus == "Stopped") then
			_toggleTick(true)

            _currentTime = _initalTime
			_currentTimerState.remainingTime = _initalTime

			_currentTimerState.timerStatus = "Running"
            newStartedBindableEvent:Fire(_currentTimerState)
            newElaspedBindableEvent:Fire(_currentTimerState)

			return _currentTimerState
		end

		return _currentTimerState
	end

	newTimerObject.resume = function() : TimerState
		if (_currentTimerState.timerStatus == "Paused") then
			_toggleTick(true)

			_currentTimerState.timerStatus = "Running"
            newResumedBindableEvent:Fire(_currentTimerState)

			return _currentTimerState
		end

		return _currentTimerState
	end

	newTimerObject.pause = function() : TimerState
		if (_currentTimerState.timerStatus == "Running") then
			_toggleTick(false)

			_currentTimerState.timerStatus = "Paused"
            newPausedBindableEvent:Fire(_currentTimerState)

			return _currentTimerState
		end

		return _currentTimerState
	end

	newTimerObject.stop = function() : TimerState
		if (_currentTimerState.timerStatus == "Running") or (_currentTimerState.timerStatus == "Paused") then
			_toggleTick(false)

			_currentTimerState.timerStatus = "Stopped"
            newStoppedBindableEvent:Fire(_currentTimerState)

			return _currentTimerState
		end

		return _currentTimerState
	end

	return newTimerObject
end

return RblxTimer
📜 Changelogs ( Latest: v.1.0.1 )

RblxTimer v1.0.1 Changelog


  • Adjusted the time mechanic to be more accurate. This now uses‎‎ ‎ Heartbeat‎‎ ‎ to run the time mechanic. This is done to ensure prefect timing.

NOTE: This does not affect your code that uses the module. The change is backend, and therefore only affects the performance.



If you have any questions or issues, please let me know! I will be HAPPY to fix any issue. :sparkling_heart:

/Mub

10 Likes

Here is the use case of RblxTimer! (Creating clock timer using it!)

2 Likes

splendid, i love this module, i started doing my minigames with it

1 Like

Awesome! :sparkling_heart:

If you found any issues or if you have any question, you can always ask me! If you think that the module has missing features, you can always suggest!

1 Like

RblxTimer v1.0.1 Release 5/12/2024

Please refer to the updated original post to view the latest changelog. Happy coding! :+1:

/Mub

2 Likes