TRIGGER | Module for making triggers

TRIGGER | A module for making part-based triggers.

What is a trigger?
An area where if touched it fires a function.

I made this module because I was bored, so it’s nothing serious “for now”

The module is in very early stage at the moment and there are quite a few bugs,
so there will probably be a lot of updates on it.

Model: TRIGGER - Roblox

Sources:
Main Module
Type - ‘ModuleScript’
Pastebin

local TRIGGER = {}
local triggers = {}

local chars = {
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3",
"4", "5", "6", "7", "8", "9",
}

local function generate_id()
local random = math.random
local template = "xxxxxxx-xxxx-xxxx-yxxxx"
return string.gsub(template, "[xy]", function(c)
	local v = (c == 'x') and random(0, 0xf) or random(8, 0xb)
	return string.format("%x", v)
end)
end

--[[
params {
	properties: 'table'
	_repeat:    'bool' -> true: touched event fires infinitely at the rate of the given cooldown ; false: touched 
event fires once
	callback:   'function' -> gets called when the trigger object gets touched
	part:       Instance of class 'BasePart' -> the part to turn into a trigger object
}

TRIGGER:new()        -> Creates trigger object from scratch with given properties
*NOTICE* When using TRIGGER:new() you need to parent the part to workspace yourself.

trigger:hook()       -> Hooks the trigger to the part
trigger:unhook()     -> Unhooks the trigger from the part
trigger:initialize() -> Initializes the trigger *fires when the trigger object gets called*
trigger:destroy()    -> Destroys the part along with the trigger object
trigger:reset()      -> Resets the trigger and leaves it unhooked

<---------------------------->

Example with part:
local TRIGGER = require(PATH_TO_MODULE)

local trigger = TRIGGER(PATH_TO_BASEPART, false, function()
	print("triggered")
end)

<---------------------------->

Example without part:
local TRIGGER = require(PATH_TO_MODULE)
local properties = {
	Name = "New Trigger";
	Position = Vector3.new(0, 10, 0);
	Anchored = true;
	CanCollide = false;
	Size = Vector3.new(10, 10, 10);
	Parent = workspace;
}

TRIGGER:new(properties, false, function()
	print("new trigger")
end)

<---------------------------->
]]

function TRIGGER:new(properties, _repeat, callback)
local trigger_part = Instance.new("Part")
for property,value in pairs(properties) do
	trigger_part[property] = value
end
self(trigger_part, _repeat, callback)
end

function TRIGGER:getTriggers()
return triggers
end

setmetatable(TRIGGER, {
__call = function(self, part, _repeat, callback)
	callback = callback or function() end
	
	local trigger = {
		part = part;
		_repeat = _repeat;
		triggered = {};
		cooldowns = {};
		cooldown = 2;
		state = "unhooked";
		connection = nil;
		id = generate_id();
		
		hook = function(self)
			self.state = "hooked"
			if not self.connection then
				self.connection = part.Touched:Connect(function(hit)
					pcall(function()
						local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
						if self._repeat then
							while table.find(self.part:GetTouchingParts(), hit) do
								if os.time() - self.cooldowns[player] >= self.cooldown then
									self.cooldowns[player] = os.time()
									callback(player)
								end
								wait()
							end
						else
							if not self.triggered[player] then
								self.triggered[player] = true
								for i,v in pairs(self.triggered) do print(i,v) end
								callback(player)
							end
						end
					end)
				end)
			end
		end;
		
		unhook = function(self)
			self.state = "unhooked";
			self.connection:Disconnect()
			self.connection = nil
		end;
		
		initialize = function(self)
			table.insert(triggers, self)
			for _,player in pairs(game:GetService("Players"):GetPlayers()) do
				self.cooldowns[player] = os.time()
			end
			game:GetService("Players").PlayerAdded:Connect(function(player)
				self.cooldowns[player] = os.time()
			end)
			self:hook()
		end;
		
		reset = function(self)
			if self.state == "hooked" then self.connection:Disconnect() end
			self.connection = nil
			self.state = "unhooked"
			self.triggered = {}
		end;
		
		destroy = function(self)
			local i = table.find(triggers, self)
			table.remove(triggers, i)
			self.part:Destroy()
		end;
	}
	
	trigger:initialize()
	
	return trigger
end
});

return TRIGGER
  • DATE OF LATEST UPDATE
    2/10/2020
8 Likes

You definitely shouldn’t use this over Zone+.
From 1 quick look I can tell it’s far better than my module.

1 Like

Sorry, but what exactly is the point of this?

What is wrong with creating a part and listening to the .Touched event manually - is there any particular benefit to your approach?

1 Like

At the moment it’s very bare boned.
The original idea was to basically make a “new Instance object” with a ton of features, which i’m still aiming for.
It can definitely be useful if I add enough features.

The only 2 benefits at the moment are that when the player is inside the area and repeat property is set to true, it will infinitely loop at the rate of a given cooldown until the player walks outside the area.

But when you use a .Touched event it only fires when the player is moving, which is definitely not ideal in most cases.

And you can hook/unhook the trigger whenever you want.

Frankly, I don’t exactly think it’s anything more than a hobby project and I think this kind of stuff could still be interesting to mess with and provide feedback on. new modules doesn’t exactly have to be more useful than already available plugins and modules. The OP stated that this module isn’t a serious project and so I can only infer it’s a hobbyist creation*.

Again, Still fairly cool to see this kind of stuff being created even if it’s not useful for now. GJ Empy.