Help with Block Signaling System

  1. What do you want to achieve? Create a block signaling system with positional signals similar to that of many American railroads.

image
(Similar to this, except with even more aspects then just green, double yellow, yellow, and red… about 7.)

  1. Background: What I’ve got so far
    robloxapp-20240319-2049497.wmv (317.9 KB)

The above video shows all of the different signal aspects in order from Clear (Green) to full Stop (Red)

robloxapp-20240319-2052593.wmv (130.0 KB)

This next video shows a signal switching from STOP to STOP AND PROCEED, after a train leaves the corresponding signal block.

image

This above image is an example of one of my signal block groups within the explorer.

  1. What is the issue? Include screenshots / videos if possible!

My script only seems to work for changing a signal aspect from STOP to STOP AND PROCEED, while it should be able to do SLOW APPROACH and APPROACH as well. (and more in the future)

local signals = script.Parent

--[[ ASPECT GUIDE
0 = stop
1 = stopandproceed
2 = slowapproach
3 = approach
4 = approachslow
5 = mediumclear
6 = approachmedium
7 = clear
]]

--[[ TYPE GUIDE
doublepos = double level position light signal
]]

for i, v in pairs(signals.Gates:GetChildren()) do
	if v.Name == "gate" then
		v.Touched:Connect(function(hit)
			for a, b in pairs(signals:GetDescendants()) do
				if b.Name == "entry" then
					if hit.Name == "front" and v == b.Value then
						print("train has entered signal block")
						b.Parent.occupied.Value = true
						b.Parent.occupant.Value = hit.Parent.Parent.Parent
						local aspect = b.Parent.aspect
						changeAspect(aspect)
					end
				elseif b.Name == "exit" then
					if hit.Name == "back" and v == b.Value then
						wait(0.2)
						print("train has exitted signal block")
						b.Parent.occupied.Value = false
						b.Parent.occupant.Value = nil
						local aspect = b.Parent.aspect
						changeAspect(aspect)
					end
				end
			end
		end)
	end
end

local off = Color3.fromRGB(27, 42, 53)
local on = Color3.fromRGB(255, 255, 0)

function clear(signal)
	signal.top.center.Color = on
	signal.top.top.Color = on
	signal.top.topright.Color = off
	signal.top.right.Color = off
	signal.top.bottom.Color = on
	signal.top.bottomleft.Color = off
	signal.top.left.Color = off

	signal.bottom.center.Color = off
	signal.bottom.topleft.Color = off
	signal.bottom.top.Color = off
	signal.bottom.topright.Color = off
	signal.bottom.bottomright.Color = off
	signal.bottom.bottom.Color = off
	signal.bottom.bottomleft.Color = off

	signal.simple.ui.text.BackgroundColor3 = Color3.new(0, 1, 0)
	signal.simple.ui.text.Text = "CLEAR"
end

function approachmedium(signal)
	signal.top.center.Color = on
	signal.top.top.Color = off
	signal.top.topright.Color = on
	signal.top.right.Color = off
	signal.top.bottom.Color = off
	signal.top.bottomleft.Color = on
	signal.top.left.Color = off

	signal.bottom.center.Color = on
	signal.bottom.topleft.Color = off
	signal.bottom.top.Color = on
	signal.bottom.topright.Color = off
	signal.bottom.bottomright.Color = off
	signal.bottom.bottom.Color = on
	signal.bottom.bottomleft.Color = off

	signal.simple.ui.text.BackgroundColor3 = Color3.new(1, 1, 0)
	signal.simple.ui.text.Text = "APPROACH MEDIUM"
end

function mediumclear(signal)
	signal.top.center.Color = on
	signal.top.top.Color = off
	signal.top.topright.Color = off
	signal.top.right.Color = on
	signal.top.bottom.Color = off
	signal.top.bottomleft.Color = off
	signal.top.left.Color = on

	signal.bottom.center.Color = on
	signal.bottom.topleft.Color = off
	signal.bottom.top.Color = on
	signal.bottom.topright.Color = off
	signal.bottom.bottomright.Color = off
	signal.bottom.bottom.Color = on
	signal.bottom.bottomleft.Color = off

	signal.simple.ui.text.BackgroundColor3 = Color3.new(1, 1, 0)
	signal.simple.ui.text.Text = "MEDIUM CLEAR"
end

function approachslow(signal)
	print("slow approach slow function started")
	signal.top.center.Color = on
	signal.top.top.Color = off
	signal.top.topright.Color = on
	signal.top.right.Color = off
	signal.top.bottom.Color = off
	signal.top.bottomleft.Color = on
	signal.top.left.Color = off

	signal.bottom.center.Color = on
	signal.bottom.topleft.Color = off
	signal.bottom.top.Color = off
	signal.bottom.topright.Color = on
	signal.bottom.bottomright.Color = off
	signal.bottom.bottom.Color = off
	signal.bottom.bottomleft.Color = on

	signal.simple.ui.text.BackgroundColor3 = Color3.new(1, 1, 0)
	signal.simple.ui.text.Text = "APPROACH SLOW"
end

function approach(signal)
	print("approach function started")
	signal.top.center.Color = on
	signal.top.top.Color = off
	signal.top.topright.Color = on
	signal.top.right.Color = off
	signal.top.bottom.Color = off
	signal.top.bottomleft.Color = on
	signal.top.left.Color = off

	signal.bottom.center.Color = off
	signal.bottom.topleft.Color = off
	signal.bottom.top.Color = off
	signal.bottom.topright.Color = off
	signal.bottom.bottomright.Color = off
	signal.bottom.bottom.Color = off
	signal.bottom.bottomleft.Color = off

	signal.simple.ui.text.BackgroundColor3 = Color3.new(1, 1, 0)
	signal.simple.ui.text.Text = "APPROACH"
end

function slowapproach(signal)
	print("slow approach function started")
	signal.top.center.Color = on
	signal.top.top.Color = off
	signal.top.topright.Color = off
	signal.top.right.Color = on
	signal.top.bottom.Color = off
	signal.top.bottomleft.Color = off
	signal.top.left.Color = on

	signal.bottom.center.Color = on
	signal.bottom.topleft.Color = off
	signal.bottom.top.Color = off
	signal.bottom.topright.Color = on
	signal.bottom.bottomright.Color = off
	signal.bottom.bottom.Color = off
	signal.bottom.bottomleft.Color = on

	signal.simple.ui.text.BackgroundColor3 = Color3.new(1, 0.5, 0)
	signal.simple.ui.text.Text = "SLOW APPROACH"
end

function stopandproceed(signal)
	print("stop and proceed function started")
	signal.top.center.Color = on
	signal.top.top.Color = off
	signal.top.topright.Color = off
	signal.top.right.Color = on
	signal.top.bottom.Color = off
	signal.top.bottomleft.Color = off
	signal.top.left.Color = on

	signal.bottom.center.Color = on
	signal.bottom.topleft.Color = off
	signal.bottom.top.Color = off
	signal.bottom.topright.Color = off
	signal.bottom.bottomright.Color = off
	signal.bottom.bottom.Color = off
	signal.bottom.bottomleft.Color = off

	signal.simple.ui.text.BackgroundColor3 = Color3.new(1, 0, 0)
	signal.simple.ui.text.Text = "STOP & PROCEED"
end

function stop(signal)
	print("stop function started")
	signal.top.center.Color = on
	signal.top.top.Color = off
	signal.top.topright.Color = off
	signal.top.right.Color = on
	signal.top.bottom.Color = off
	signal.top.bottomleft.Color = off
	signal.top.left.Color = on

	signal.bottom.center.Color = off
	signal.bottom.topleft.Color = off
	signal.bottom.top.Color = off
	signal.bottom.topright.Color = off
	signal.bottom.bottomright.Color = off
	signal.bottom.bottom.Color = off
	signal.bottom.bottomleft.Color = off

	signal.simple.ui.text.BackgroundColor3 = Color3.new(1, 0, 0)
	signal.simple.ui.text.Text = "STOP"
end

function changeAspect(aspect)
	local block = aspect.Parent
	local signal = block.Signal
	print(signal)
	if block.occupied.Value == true then
		stop(signal)
	elseif block.occupied.Value == false then
		print("block no longer occupied")
		if block.next.Value.occupied.Value == true then
			print("next block is occupied")
			stopandproceed(signal)
		elseif block.next.Value.next.Value.occupied.Value == true then
			print("two blocks ahead occupied")
			slowapproach(signal)
		elseif block.next.Value.next.Value.next.Value.occupied.Value == true then
			print("three blocks ahead occupied")
			approach()
		end
	end
end
  1. What solutions have you tried so far? I’ve done everything in my control and have searched the DevForum for solutions.

This is extremely important to my game, and I was wondering if anyone would have any insights for me to fix this issue.

3 Likes

KIND OF solved. Still looking for improvements. I was able to modify the last block of code to repeat forever, but I’m scared this will create lots of lag once there are many signals within my game.

function changeAspect(aspect)
	local block = aspect.Parent
	local signal = block.Signal
	print(signal)
	repeat wait(1) --added
		if block.occupied.Value == true then
			stop(signal)
		elseif block.occupied.Value == false then
			print("block no longer occupied")
			if block.next.Value.occupied.Value == true then
				print("next block is occupied")
				stopandproceed(signal)
			elseif block.next.Value.next.Value.occupied.Value == true then
				print("two blocks ahead occupied")
				slowapproach(signal)
			elseif block.next.Value.next.Value.next.Value.occupied.Value == true then
				print("three blocks ahead occupied")
				approach()
			end
		end
	until nil --added
end
2 Likes

I think a good rule of thumb to keep in mind is that any time you have to do the same thing to a bunch of similar instances, a good idea may be to use CollectionService in combination with a signal-based approaching utilizing BindableEvents (for example, firing an event when a train approaches a block instead of busy waiting every second for a train to approach) instead of listening in a loop.

2 Likes

Could you lead me to some areas where I could learn about these and how to use them in conjunction? Thanks

3 Likes

CollectionService and BindableEvents.

A gross simplification - CollectionService allows you to tag certain objects and use those tags to manipulate their data instead of indexing for them. BindableEvents allow you to define arbitrary events that other Scripts can listen to (cross-script communication, as long as the listener has a reference to the event), exactly like built-in ROBLOX events such as Touched.

For example, you could use a BindableEvent to signal when a train reaches a certain point (there are multiple ways to implement this, and I will leave it as an exercise for you). Instead of continuously scanning and wasting processing power, you can execute your logic once in the listener script this event fires, since you know a train is in a certain area.

4 Likes