I do apologies if the title seems confusing; I’m about to explain the issue. The issue is that the Object (Banana) is being Tagged on the same Tagged Handlers (Trees). How to make a single Banana get Tagged on a random Tree each time you play the game?
Server Script:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local EventsFolder = ReplicatedStorage:WaitForChild("EVENTS")
local CollectRequest_Event = EventsFolder:WaitForChild("CollectRequest")
local Collect_Event = EventsFolder:WaitForChild("Collect")
local bananas = CollectionService:GetTagged("Banana")
local bananaTrees = CollectionService:GetTagged("BananaTree")
local BANANA_CONFIG = {
MAX_BANANAS = 5,
MIN_BANANAS = 0,
BANANA_DISTANCE = 1,
}
-- Shuffle function to randomize table order
local function shuffle(t)
for i = #t, 2, -1 do
local j = math.random(1, i)
t[i], t[j] = t[j], t[i]
end
end
local function TagBananas()
-- Clear all existing Banana Tags to prevent duplicates on same BananaTree
for _, banana in CollectionService:GetTagged("Banana") do
CollectionService:RemoveTag(banana, "Banana")
end
if #bananaTrees == 0 then return end
-- Shuffle bananaTrees to randomize the tree selection order
shuffle(bananaTrees)
local possibleBananas = {}
-- Step 1: Collect one candidate Banana from each BananaTree, along with its position
for _, bananaTree in bananaTrees do
local treeBananas = {}
for _, descendant in bananaTree:GetDescendants() do
if descendant:IsA("BasePart") and descendant.Name == "Banana" then
table.insert(treeBananas, descendant)
end
end
if #treeBananas > 0 then
local chosenBanana = treeBananas[1]
table.insert(possibleBananas, {
Banana = chosenBanana,
Position = chosenBanana.Position
})
end
end
if #possibleBananas == 0 then
warn("No available Bananas to Tag.")
return
end
-- Step 2: Shuffle candidates to randomize selection order
shuffle(possibleBananas)
local taggedBananaPositions = {}
local numToTag = math.clamp(BANANA_CONFIG.MAX_BANANAS, BANANA_CONFIG.MIN_BANANAS, #possibleBananas)
local taggedCount = 0
local function AreBananasTooClose(pos1, pos2)
return (pos1 - pos2).Magnitude < BANANA_CONFIG.BANANA_DISTANCE
end
-- Step 3: Tag Bananas ensuring minimum distance spacing
for _, entry in possibleBananas do
local currentPos = entry.Position
local isTooClose = false
for _, taggedPos in taggedBananaPositions do
if AreBananasTooClose(taggedPos, currentPos) then
isTooClose = true
print("Skipping Banana at", entry.Banana:GetFullName(), "due to proximity")
break
end
end
if not isTooClose then
CollectionService:AddTag(entry.Banana, "Banana")
table.insert(taggedBananaPositions, currentPos)
taggedCount += 1
print("Tagged Banana:", entry.Banana:GetFullName())
end
if taggedCount >= numToTag then
break
end
end
-- Fallback: guarantee at least one Banana is Tagged
if taggedCount == 0 and #possibleBananas > 0 then
local fallback = possibleBananas[1]
CollectionService:AddTag(fallback.Banana, "Banana")
taggedCount = 1
print("Fallback tagged Banana:", fallback.Banana:GetFullName())
end
if taggedCount < numToTag then
warn("Only Tagged", taggedCount, "Banana; spacing rule blocked the other Bananas.")
end
end
CollectRequest_Event.OnServerEvent:Connect(function(player, bananas)
if bananas and CollectionService:HasTag(bananas, "Banana") then
local sound = bananas:FindFirstChild("Grab")
if not sound then
sound = Instance.new("Sound")
sound.Name = "Grab"
sound.SoundId = "rbxassetid://444895479"
sound.Volume = 0.5
sound.RollOffMode = Enum.RollOffMode.Linear
sound.RollOffMaxDistance = 10
sound.RollOffMinDistance = 5
sound.PlayOnRemove = true
sound.Parent = bananas:IsA("BasePart") and bananas or bananas:FindFirstChildWhichIsA("BasePart") or bananas
end
if bananas and bananas.Parent then
sound:Play()
bananas:Destroy()
end
task.delay(0.1, function()
local remaining = #CollectionService:GetTagged("Banana")
if remaining == 0 then
for _, plr in ipairs(Players:GetPlayers()) do
Collect_Event:FireClient(plr, "Victory")
end
for _, plr in ipairs(Players:GetPlayers()) do
plr:Kick("All bananas have been collected!")
end
else
Collect_Event:FireClient(player, remaining)
end
end)
end
end)
TagBananas()
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local EventsFolder = ReplicatedStorage:WaitForChild("EVENTS")
local CollectRequest_Event = EventsFolder:WaitForChild("CollectRequest")
local Collect_Event = EventsFolder:WaitForChild("Collect")
local bananas = CollectionService:GetTagged("Banana")
local bananaTrees = CollectionService:GetTagged("BananaTree")
local BANANA_CONFIG = {
MAX_BANANAS = 2,
MIN_BANANAS = 0,
}
local function shuffle(tbl)
local n = #tbl
for i = n, 2, -1 do
local j = math.random(1, i)
tbl[i], tbl[j] = tbl[j], tbl[i]
end
return tbl
end
local function clamp(val, lower, upper)
return math.max(lower, math.min(upper, val))
end
local function TagBananas()
-- Clear existing "Banana" tags
for _, banana in pairs(CollectionService:GetTagged("Banana")) do
CollectionService:RemoveTag(banana, "Banana")
end
local bananaTrees = CollectionService:GetTagged("BananaTree")
if #bananaTrees == 0 then
warn("No BananaTrees found.")
return
end
shuffle(bananaTrees)
local taggedCount = 0
local maxToTag = clamp(BANANA_CONFIG.MAX_BANANAS, 0, #bananaTrees)
for i = 1, maxToTag do
local tree = bananaTrees[i]
local treeBananas = {}
for _, descendant in pairs(tree:GetDescendants()) do
if descendant:IsA("BasePart") and descendant.Name == "Banana" then
table.insert(treeBananas, descendant)
end
end
if #treeBananas > 0 then
local chosenBanana = treeBananas[math.random(1, #treeBananas)]
CollectionService:AddTag(chosenBanana, "Banana")
taggedCount = taggedCount + 1
print("Tagged Banana:", chosenBanana:GetFullName(), "from BananaTree:", tree:GetFullName())
else
warn("No Bananas found in BananaTree:", tree:GetFullName())
end
end
if taggedCount == 0 then
warn("No Bananas were tagged!")
end
end
CollectRequest_Event.OnServerEvent:Connect(function(player, bananas)
if bananas and CollectionService:HasTag(bananas, "Banana") then
local sound = bananas:FindFirstChild("Grab")
if not sound then
sound = Instance.new("Sound")
sound.Name = "Grab"
sound.SoundId = "rbxassetid://444895479"
sound.Volume = 0.5
sound.RollOffMode = Enum.RollOffMode.Linear
sound.RollOffMaxDistance = 10
sound.RollOffMinDistance = 5
sound.PlayOnRemove = true
sound.Parent = bananas:IsA("BasePart") and bananas or bananas:FindFirstChildWhichIsA("BasePart") or bananas
end
if bananas and bananas.Parent then
sound:Play()
bananas:Destroy()
end
task.delay(0.1, function()
local remaining = #CollectionService:GetTagged("Banana")
if remaining == 0 then
for _, player in ipairs(Players:GetPlayers()) do
Collect_Event:FireClient(player, "Victory")
player:Kick("All bananas have been collected!")
end
else
Collect_Event:FireClient(player, remaining)
end
end)
end
end)
TagBananas()
Current Map Template: (will expand when issue is fixed)
For some reason the shuffle() doesn’t tag the Bananas from a random BananaTree in random order but rather "first-to-last) order, how to fix?
local function shuffle(tbl)
local n = #tbl
for i = n, 2, -1 do
local j = math.random(1, i) -- I think the issue occurs here
tbl[i], tbl[j] = tbl[j], tbl[i]
end
return tbl
end
I fixed the issue, I didn’t Tag every BananaTree D:<
Fixed Server Script:
--// SERVICES
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
--// EVENTS
local EventsFolder = ReplicatedStorage.EVENTS
local CollectRequest_Event = EventsFolder.CollectRequest
local Collect_Event = EventsFolder.Collect
--// BANANA CONFIGURATION
local BANANA_CONFIG = {
MAX_BANANAS = 4,
MIN_BANANAS = 0,
}
--// RANDOM SHUFFLE SET
local function shuffle(t)
local n = #t
for i = n, 2, -1 do
local j = math.random(1, i)
t[i], t[j] = t[j], t[i]
end
return t
end
--// CLAMPING SET
local function clamp(v, lower, upper)
return math.max(lower, math.min(upper, v))
end
--// MAIN FUNCTION
local function TagBananas()
-- Clear existing "Banana" tags
for _, banana in CollectionService:GetTagged("Banana") do
CollectionService:RemoveTag(banana, "Banana")
end
local bananaTrees = CollectionService:GetTagged("BananaTree")
if #bananaTrees == 0 then
warn("No BananaTrees found.")
return
end
local candidateBananas = {}
for _, bananaTree in bananaTrees do
local bananasInTree = {}
for _, descendant in bananaTree:GetDescendants() do
if descendant:IsA("BasePart") and descendant.Name == "Banana" then
table.insert(bananasInTree, descendant)
end
end
if #bananasInTree > 0 then
local taggedBananas = bananasInTree[math.random(1, #bananasInTree)]
table.insert(candidateBananas, taggedBananas)
else
warn("BananaTree has no bananas:", bananaTree:GetFullName())
end
end
if #candidateBananas == 0 then
warn("No Bananas found in BananaTrees.")
return
end
shuffle(candidateBananas)
local maxToTag = clamp(BANANA_CONFIG.MAX_BANANAS, 0, #candidateBananas)
for i = 1, maxToTag do
local banana = candidateBananas[i]
CollectionService:AddTag(banana, "Banana")
end
if maxToTag == 0 then
warn("No Bananas were tagged!")
else
print("==== All Tagged Bananas ====")
for _, b in CollectionService:GetTagged("Banana") do
print(b:GetFullName())
end
end
end
--// COLLECT REQUEST SERVER
CollectRequest_Event.OnServerEvent:Connect(function(player, bananas)
if bananas and CollectionService:HasTag(bananas, "Banana") then
local sound = bananas:FindFirstChild("Grab")
if not sound then
sound = Instance.new("Sound")
sound.Name = "Grab"
sound.SoundId = "rbxassetid://444895479"
sound.Volume = 0.5
sound.RollOffMode = Enum.RollOffMode.Linear
sound.RollOffMaxDistance = 10
sound.RollOffMinDistance = 5
sound.PlayOnRemove = true
sound.Parent = bananas:IsA("BasePart") and bananas or bananas:FindFirstChildWhichIsA("BasePart") or bananas
end
if bananas and bananas.Parent then
sound:Play()
bananas:Destroy()
end
task.delay(0.1, function()
local remaining = #CollectionService:GetTagged("Banana")
if remaining == 0 then
for _, player in Players:GetPlayers() do
Collect_Event:FireClient(player, "Victory") -- String message to indicate victory
player:Kick("All bananas have been collected!")
end
else
Collect_Event:FireClient(player, remaining)
end
end)
end
end)
TagBananas()