I've been programming for a long time now, and one question that has plagued me is this. I've been able to find workarounds, but no longer.
I'm creating a terrain generator, and the idea behind it is this: Put nearby terrain parts into a table Put possible terrain locations into a table
If a nearby terrain part has the same location as a possible terrain location, remove it from the table.
Create terrain
Seems simple, right? Ideally one would assume this would work:
for _, nearGridTable in pairs(nearbyGrid) do for index, nearPositions in pairs(possibilities) do if nearGridTable == nearPositions then print("same") table.remove(possibilities, index) print("removed") end end end
The issue I run into however is, my print's never run. That has lead me to believe that the nearGridTable is never equaling nearPositions.
On further analysis, there are duplicate values in both table, this for loop is just not getting them properly.
I've had a few ideas on how one might go about fixing it:
Idea 1:
Check the values before I put it into the table
This wouldn't work, as it would be inefficient for my use case.
Idea 2:
use table.sort()
However, that doesn't sort my tables properly (I'm storing vector3 values). I could go about making my own sort function. I've never done this, and so essentially I come before everyone asking, what would you do to compare two tables?
Full code so you understand the context of what I'm working on:
-- Made by Conmmander -- -- terrainCore -- -- Last Edit: 9-2-2018, 2:55 PM -- -- Inititalization -- print("Intialization | "..script.Name) -- Game Services -- local workspaceService = game:GetService("Workspace") local playerService = game:GetService("Players") local lightingService = game:GetService("Lighting") local replicatedStorage = game:GetService("ReplicatedStorage") local serverStorage = game:GetService("ServerStorage") local starterGui = game:GetService("StarterGui") local starterPack = game:GetService("StarterPack") local chatService = game:GetService("Chat") -- Game Folders -- local terrainStorage = serverStorage:FindFirstChild("terrainStorage") local baseTerrain = terrainStorage:FindFirstChild("baseTerrain") local buildingTerrain = terrainStorage:FindFirstChild("buildingTerrain") -- Configuration -- local ignoreCordinates = {} local baseLimit = 100 local yCord = .5 local mingenerationRange = 12 local maxgenerationRange = 15 -- Variables -- local bases = 0 local initialSetup = false -- Functions -- function countTerrain() bases = 0 for _, defaultPart in pairs(workspaceService:GetChildren()) do if defaultPart.Name == "defaultGrid" then bases = bases + 1 end end end function generateTerrain(player) local nearbyGrid = {} local possibilities = {} if initialSetup == false then local position = CFrame.new(math.random(math.randomseed(1)), yCord, math.random(math.randomseed(1))) local clonedBase = baseTerrain.defaultGrid:Clone() clonedBase:SetPrimaryPartCFrame(position) clonedBase.Parent = workspaceService initialSetup = true end local debounce = false countTerrain() if bases < baseLimit then local Torso = player.Character.HumanoidRootPart local base = player.Character.RightFoot base.Touched:Connect(function(hitPart) wait(.1) if debounce == false then debounce = true if hitPart.Parent.Name == "defaultGrid" then if (hitPart.Parent.centerPart.Position-Torso.Position).Magnitude >= mingenerationRange and (hitPart.Parent.centerPart.Position-Torso.Position).Magnitude < maxgenerationRange then wait(.1) local debounce2 = false if debounce2 == false then debounce2 = true table.insert(possibilities, hitPart.Parent.centerPart.Position - Vector3.new(0, 0, 30)) table.insert(possibilities, hitPart.Parent.centerPart.Position + Vector3.new(0, 0, 30)) table.insert(possibilities, hitPart.Parent.centerPart.Position - Vector3.new(30, 0, 0)) table.insert(possibilities, hitPart.Parent.centerPart.Position + Vector3.new(30, 0, 0)) print("Insert") for _, leftPart in pairs(hitPart.Parent.left:GetTouchingParts()) do print("Called") if leftPart.Parent.Name == "defaultGrid" then table.insert(nearbyGrid, leftPart.Parent.centerPart.Position) print("Insertleft") end end for _, rightPart in pairs(hitPart.Parent.right:GetTouchingParts()) do print("Called") if rightPart.Parent.Name == "defaultGrid" then table.insert(nearbyGrid, rightPart.Parent.centerPart.Position) print("Insertright") end end for _, nearGridTable in pairs(nearbyGrid) do for index, nearPositions in pairs(possibilities) do if nearGridTable == nearPositions then print("same") table.remove(possibilities, index) print("removed") end end end for _, position in pairs(possibilities) do local clonedBase = baseTerrain.defaultGrid:Clone() clonedBase:SetPrimaryPartCFrame(CFrame.new(position)) clonedBase.Parent = workspaceService end end debounce2 = false end end end wait(.2) debounce = false end) end end -- Code -- playerService.PlayerAdded:Connect(function(addedPlayer) addedPlayer.CharacterAdded:Connect(function(addedCharacter) generateTerrain(addedPlayer) end) end) -- Loop -- while true do wait(5) for _, players in pairs(playerService:GetPlayers()) do generateTerrain(players) end end
EDIT:
Some nice person I spoke with yesterday sent me this as a method of sorting tables, but how would I use it? (I'm not very familiar with sorting tables).
local function unordered_tostring_equals(array_1, array_2) -- making count_diffs[unknown] return 0 instead of nil -- I usually I have have a function for this: count_diffs = DefaultedTable(0) local count_diffs = setmetatable({}, {__index = function() return 0 end}) -- adds 1's counts for _, v in ipairs(array_2) do local str = tostring(v) count_diffs[str] = count_diffs[str] + 1 end -- subtracts 2's counts for _, v in ipairs(array_1) do local str = tostring(v) count_diffs[str] = count_diffs[str] - 1 end -- if the same tostrings has a different count, it's a different table for _, count in pairs(count_diffs) do if count ~= 0 then return false end end return true end