Spawn order algorithm

I am making a game where you build an army of clones and they spawn in a specific formation around the player.
How would I go about creating an algorithm to create the formation so I do not have to type hundreds of values manually.

This is it spawning just three in order I would like this to continue infinitely in the pattern shown in image below

local ClonePosition = {Vector3.new(-4,0,0),Vector3.new(-4,0,-4),Vector3.new(0,0,-4)}

https://gyazo.com/d40336b7c5de05ddcc408a8fe8a3e906

You’d definitely want to use matrices to achieve this. For example:

Let’s say I wanted a Diamond formation around the player

--[[
DIAMOND FORMATION
0 0 0 1 0 0 0
0 0 1 0 1 0 0
0 1 0 2 0 1 0
0 0 1 0 1 0 0
0 0 0 1 0 0 0

0 - EMPTY
1 - GUARD
2 - PLAYER
--]]

Great, now what? Well, let’s make it into a table.

local diamondPattern = {
     {0, 0, 0, 1, 0, 0, 0},
     {0, 0, 1, 0, 1, 0, 0},
     {0, 1, 0, 2, 0, 1, 0},
     {0, 0, 1, 0, 1, 0, 0},
     {0, 0, 0, 1, 0, 0, 0},
}

Now the rest is easy. We just loop through each value of the table, and start from an origin position of however many studs away from the player is.

Let’s define those values:

local Players = game:GetService("Players")
local playerToGuard = Players:FindFirstChild("thePlayerName")
local characterToGuard = playerToGuard.Character or playerToGuard.CharacterAdded:Wait()

local formationHeight = #diamondPattern
local formationWidth = diamondPattern[1] -- We are using 1 because any other relative value would produce the same width

-- Getting the distance away from the character
local distanceHeight, distanceWidth = formationHeight / 2, formationWidth / 2

local cloneSize -- You do this part, since I am not sure what clone model you are using
local startCFrame = characterToGuard.CFrame * CFrame.new(-(distanceHeight * cloneSize), 0, -(distanceWidth * cloneSize))

Now for our for loops

for i, row in pairs(diamondPattern) do
     for j, designation in pairs(row) do
          if designation == 1 then
               -- Spawn at startCFrame * CFrame.new(-((i - 1) * cloneSize), 0, (j - 1) * cloneSize)
          elseif designation == 2 then
               -- That is the player!
          end
     end
end

Let me know if this helped.

I realized I misunderstood your request. So for that, we can manipulate the existing code into the following:

Our new Pattern will be:

local tornadoPattern = {
     {20, 21, 22, 23, 24},
     {19, 6 , 7 , 8 , 9 },
     {18, 5 , 0 , 1 , 10},
     {17, 4 , 3 , 2 , 11},
     {16, 15, 14, 13, 12},
} -- Nifty tornado shape

Then what we would want to do is modify our for loops to account for if we have that amount of clones:

local cloneAmount -- Set your clone amount

for i, row in pairs(diamondPattern) do
     for j, designation in pairs(row) do
          if designation ~= 0 and designation <= cloneAmount then
               -- Spawn at startCFrame * CFrame.new(-((i - 1) * cloneSize), 0, (j - 1) * cloneSize)
          end
     end
end

Let me know if this makes sense.

Thank you so much. I will try this right now

1 Like

Looks like spawning in a spiral like formation
This is a similar post with a solution

Here is my really quick, rough, untested pseudo-code:

-- First figure out how many layers you need based on amount of clones
func GetRequiredLayers(numClones)
	local neededLayers = 0
	local totalSlots = 0
	while wait() do
		if (totalSlots >= numClones) then
			return neededLayers
		end
		neededLayers += 1
		totalSlots += 5 + ((neededLayers - 1) * 2)
	end
end

-- Create the matrix from required layers
func CreateMatrix(layers)
	local matrix = {}
	if (layers == 0) then
		return matrix
	end
	for currentLayer = 1, layers do
		local layerSlots = {}
		local requiredSlots = 5 + ((currentLayer - 1) * 2)
		for i = 1, layerSlots do
			table.insert(layerSlots, true)
		end
		table.insert(matrix, layerSlots)
	end
	return matrix
end

-- Populate the matrix (assume first slot index in each layer is middle, left)
local matrix = CreateMatrix(GetRequiredLayers(20))

You’ll probably have to figure out for each layer how many slots each side has to determine how to actually construct it.

This is just an idea, no idea if it would work in practice.
No doubt there is probably some more efficient approach.
If you find it useful then great.

-- position: initial position
-- n:  number of elements
-- distance: element spacing
function generator(position: Vector3, n: number, distance: number)
    local p = {position.X, position.Z}
    local inc = 1
    local sign = 1
    while true do
        for i = 1, 2 do
            for _ = 1, inc do
                p[i] += sign*distance
                makeClone(Vector3.new(p[1], position.Y, p[2]))  -- Vector3.new(p[1], position.Y, p[2]) is the position where the clone is spawned
                n -= 1
                if n <= 0 then return end
            end
        end
        inc += 1
        sign = -sign
    end
end

generator(Vector3.new(0,5,0), 26, 4)
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.