How do I check if something exists already in its position?

Hey there, I’m trying to make a coin-placement system but there is a slight problem, sometimes the coins decide to spawn on top of each other and it makes for some really weird spawning. Can I get some help please?

Here is the function that shows the code:

coinEvent.OnServerEvent:Connect(function(player: Player, coinId: string, ChosenLS)
	if not currentCoins[coinId] then return end
	
	local coinInfo = currentCoins[coinId]
	local coinType: string = coinInfo.Name
	local leaderstats = player:WaitForChild("leaderstats") :: leaderstatsDataType

	if player:GetAttribute("DoubleTokens") then
		leaderstats[ChosenLS].Value += coinInfo.Amount * 2
	else
		leaderstats[ChosenLS].Value += coinInfo.Amount
	end

	local respawnTimer: number = 5
	
	if coinInfo.Timer then
		respawnTimer = coinInfo.Timer
	end

	local previousPosition: Vector3 = coinInfo.Position
	
	currentCoins[coinId] = nil
	
	for i, plr in plrs:GetPlayers() do
		if plr == player then continue end
		coinEvent:FireClient(plr, "DestroyCoin", {Id = coinId})
	end
	
	task.delay(respawnTimer, function()
		new(previousPosition, coinType)
	end)
end)

I would have something like this. Basically when you are checking a new position you would loop through all current coins and check how close they are to the given position. If even one is close enough it’ll return false.

local Distance = 1 --> Studs

--@@ Checks if the magnitude of 2 positions, if they are below the distance variable then it's not a valid position
local function IsValid(target: Vector3, position: Vector3): boolean
  return (target - position).Magnitude > Distance 
end 

--@@ This just loops through all coins. Should return true if you can place.
local function ValidatePosition(target: Vector3): boolean
   for _, coin in currentCoins do
     if not IsValid(target, coin.Position) then
         return false
     end
   end

   return true
end

--> Use ValidatePosition function and send in the new position you want to check.
1 Like

Alright, I’ve just applied what you have told me and I managed to understand it! Sort of checking if any are overlapping etc or are really bunched up. Would this code seem correct to do?

(My game takes some time to load so I just wanted to double check)

--!strict

local Coin = {}

--// Services

local debris = game:GetService("Debris")
local ts = game:GetService("TweenService")
local market = game:GetService("MarketplaceService")
local plrs = game:GetService("Players")
local servstorg = game:GetService("ServerStorage")
local rs = game:GetService("ReplicatedStorage")
local httpserv = game:GetService("HttpService")

--// Other Variables

local Tokens = workspace:WaitForChild("DefaultService"):WaitForChild("Tokens")
local coinsFolder = rs.Assets.Coins

local remotes = rs.Assets.Remotes
local coinEvent = remotes.CoinEvent

type leaderstatsDataType = typeof(servstorg.leaderstats)
type coinDataType = {typeof(coinsFolder.Token)}

local onCoinTaken, new
local currentCoins = {}

local OutDist = 0.5

--// Main Code

new = function(position: Vector3, coinType: string, specificPlayer: Player?, specificId: string?)
	local desiredCoin = coinsFolder:FindFirstChild(coinType)
	if not desiredCoin then
		error("Coin ".. tostring(coinType) .. " not found!")
	end
	local newCoin = {
		CoinInstance = desiredCoin,
		Position = position,
		Id = if specificId then specificId else httpserv:GenerateGUID()
	}
	currentCoins[newCoin.Id] = {
		Name = coinType,
		Timer = desiredCoin.Timer.Value,
		Amount = desiredCoin.Amount.Value,
		Position = position
	}
	if specificPlayer then
		coinEvent:FireClient(specificPlayer, "CreateCoin", newCoin)
	else
		coinEvent:FireAllClients("CreateCoin", newCoin)
	end
end

plrs.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Wait()
	for i, v in currentCoins do
		new(v.Position, v.Name, player, i)
	end
end)

local function IsValid(target: Vector3, position: Vector3): boolean
	return (target - position).Magnitude > OutDist 
end

local function ValidatePosition(target: Vector3): boolean
	for _, coin in currentCoins do
		if not IsValid(target, coin.Position) then
			return false
		end
	end
	return true
end

coinEvent.OnServerEvent:Connect(function(player: Player, coinId: string, ChosenLS)
	if not currentCoins[coinId] then return end
	
	local coinInfo = currentCoins[coinId]
	local coinType: string = coinInfo.Name
	local leaderstats = player:WaitForChild("leaderstats") :: leaderstatsDataType

	if player:GetAttribute("DoubleTokens") then
		leaderstats[ChosenLS].Value += coinInfo.Amount * 2
	else
		leaderstats[ChosenLS].Value += coinInfo.Amount
	end

	local respawnTimer: number = 5
	
	if coinInfo.Timer then
		respawnTimer = coinInfo.Timer
	end

	local previousPosition: Vector3 = coinInfo.Position
	
	if ValidatePosition(previousPosition) == true then
		currentCoins[coinId] = nil

		for i, plr in plrs:GetPlayers() do
			if plr == player then continue end
			coinEvent:FireClient(plr, "DestroyCoin", {Id = coinId})
		end

		task.delay(respawnTimer, function()
			new(previousPosition, coinType)
		end)
	end
end)

Coin.new = new

return Coin

Yep that seems like it would work

There seems to be no errors / no issues. Probably because there is only 1 coin spawn-part as of now. But once I start adding more and issues possibly occuring, I may instead Message you instead of bumping this post. Thank you for your help!

Ah I see the issue in that case. So making a slight adjustment to the ValidateCoin function.

--@@ This just loops through all coins. Should return true if you can place.
local function ValidatePosition(target: Vector3, coinId: string): boolean
   for id, coin in currentCoins do
     if id == coinId then
         continue
     end

     if not IsValid(target, coin.Position) then
         return false
     end
   end

   return true
end

Then you would just pass the coin id through the function too. The reason this is happening is because it’s all checking it’s own position.

Edit: I completely misread the reply, I thought you meant only one part was spawning. In any case this should fix the issue.

1 Like

Ah, thank you for your support. I nearly forgot about that!

1 Like

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