I am making a ‘color grab’ type game, and I am needing to floodfill a grid to find an enclosed area. Such as…
I am the pink area, and I mark off a section of unclaimed grid (light pink line) and once that line re-connects back to the area I own, I need a way to detect the enclosed area, so I can fill it in, as claimed by me.
If I floodfill on every neighbor of each point on the line (ignoring other player colors) , I assume I will get results of valid, meaning I only encountered my own territory (color) or I encountered the line. Or invalid meaning I hit an edge.
This method seems to work, but is very laggy with large maps, of 15,000 squares.
So I thought of using actors, and google gave me an example of some script to use to divide the task up into quadrants, however, I am lost as to how the different sections will understand they are connected to the whole.
Here is the script from the AI
Main Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local GridModule = require(ReplicatedStorage.GridModule)
local Grid = GridModule.new(100, 100) -- Example 100x100 grid
-- Create actors for different sections of the grid
local Actors = {}
for i = 1, 4 do -- Example: 4 actors for 4 quadrants
local actor = Instance.new("Actor")
actor.Name = "FloodActor_" .. i
actor.Parent = workspace.ActorsFolder
table.insert(Actors, actor)
-- A script inside each actor will contain the flood fill logic
local actorScript = Instance.new("Script")
actorScript.Source = ReplicatedStorage.FloodFillActorScript:GetSource()
actorScript.Parent = actor
end
function initiateFloodFill(x, y, newColor)
-- Determine which actor to start the fill on
local startActor = Actors[Grid:getActorIndexForPoint(x, y)]
startActor:SendMessage("StartFill", {
x = x,
y = y,
newColor = newColor
})
end
initiateFloodFill(50, 50, Color3.new(0, 1, 0))
Actor Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local GridModule = require(ReplicatedStorage.GridModule)
local Actor = script.Parent
local Grid = GridModule.new(100, 100) -- A new, local copy of the grid data
local function parallelFloodFill(startPos, newColor)
task.desynchronize()
-- Non-recursive, queue-based flood fill logic
local queue = {startPos}
while #queue > 0 do
local pos = table.remove(queue, 1)
local x, y = pos.x, pos.y
-- Check boundaries and color conditions
if Grid:isValid(x, y) and Grid:isSameColor(x, y) then
-- Safely update local data in parallel
Grid:setColor(x, y, newColor)
-- Check neighbors
for _, neighbor in ipairs(Grid:getNeighbors(x, y)) do
-- If neighbor is in a different actor's territory, message that actor
if not Actor:isMyTerritory(neighbor) then
local otherActor = Actor:getActorForPoint(neighbor)
otherActor:SendMessage("ContinueFill", {
x = neighbor.x,
y = neighbor.y,
newColor = newColor
})
else
table.insert(queue, neighbor)
end
end
end
end
task.synchronize()
-- At this point, the main thread can safely modify `DataModel` objects
-- to reflect the changes made in parallel.
end
Actor:BindToMessage("StartFill", function(message)
parallelFloodFill(message.startPos, message.newColor)
end)
There is a section in the script where it says…
" – At this point, the main thread can safely modify DataModel objects
– to reflect the changes made in parallel."
So I assume this is where I would put something to modify a global data set to reflect the actor’s changes.
However, what would happen if…
In this image, Actor1 shaded in green and Actor2 shaded in yellow, will both scan their respective areas of the map, but how will they know the area (with a double Red Arrow) is connected, so that Actor2 doesnt disregard this space, thinking it is not enclosed. And the same for Actor 1, without the edges touching the space I own, how would it understand where the boundaries are?
Maybe I don’t really get ‘actors’ or how to use them, or maybe there is a simpler way to go about this.
This has had me stumped for about a week now, so any help or advice is greatly appreciated.




