Teleporting a player to a different vector if collision

I’m currently spending time working with LUA again, and I ran into something I wish to accomplish but I’m not to sure where to start. I’m hoping some can point me in the right direction.

At the moment I have a script that teleports members of a team to random vectors in a table. That works fine, but I don’t want multiple players to teleport to the same vector. Is there a way I can make it so that if two(or more) players end up teleporting to the same vector one of them will be teleported to another vector instead? How would I go about doing this (with collision detection maybe?)

This is part of my script I’m currently working on. (Feel free to point out any errors, I’m here to learn!)


function round.Start()
    pos = { Vector(712,-705,127), Vector(703,-139,127), Vector(311,-309,127), Vector(327,-714,127) }
    round.Announce("A new round has started!")
    
    
    for k, v in pairs(player.GetAll()) do
    if v:Team() == TEAM_READY then
        v:SetPos(table.Random(pos))
            print("TELEPORTED")
        else
            print("Other team wasn't teleported.")
        end
    end
end


Thanks for your time!

what i’m thinking of is assigning the vector to a player and checking if a player has been teleported there before, if there’s no more spots for a vector, you could add another one like oldvector+Vector(0,0,20) or something of the sort

You could remove the vector from the table you’re picking a random from, or mark the vectors as used in the function, which it then should also check before picking.

[Lua]
function nz.Enemies.Functions.CheckIfSuitable(pos)
local Ents = ents.FindInBox( pos + Vector( -16, -16, 0 ), pos + Vector( 16, 16, 64 ) )
local Blockers = 0
if Ents == nil then return true end
for k, v in pairs( Ents ) do
if ( IsValid( v ) and (v:GetClass() == “player” ) ) then
Blockers = Blockers + 1
end
end
if Blockers == 0 then return true end
return false end
[/Lua]

That’s the function I use to check if a player can spawn at a certain vector. So before you set the the spawn of a player run it through your version of this function, if the function returns true then set their position if false then find a new position and check that

Sorry about formatting posting from mobile; here it is with proper format

I currently revised my code attempting to use your snippet but I seem to be failing. I’m getting a GMOD error of


[ERROR] /gamemode/init.lua:34: bad argument #1 to '__add' (Vector expected, got table)
  1. __add - [C]:-1


For some reason it doesn’t want to read my POS table as a vector. Any suggestions? Here is my current revision




pos = { Vector(712,-705,127), Vector(703,-139,127), Vector(311,-309,127), Vector(327,-714,127) }

function CheckIfSuitable() 	
	local Ents = ents.FindInBox(pos + Vector( -16, -16, 0 ),pos + Vector( 16, 16, 64 ) )
	local Blockers = 0
		if Ents == nil then
			return true
		end
		for k, v in pairs( Ents ) do 
		if ( IsValid( v ) and (v:GetClass() == "player" ) ) then
			Blockers = Blockers + 1		
		end	
	end		
		if Blockers == 0 then
			return true	
	end		
		return false
end

function round.Start()
	round.Announce("A new round has started!")
	
	for k, v in pairs(player.GetAll()) do
	if v:Team() == TEAM_READY && CheckIfSuitable() then
		v:SetPos(table.Random(pos))
			print("TELEPORTED")
		else
			print("Other team wasn't teleported.")
		end
	end
end


Thanks for the suggestion, I’ve been toying around with this method attempting to get it work. Is there an easy to mark the vector as used, instead of using table.remove/table.add?

After assigned a player to a vector is there a way I can unassign them after a certain amount of time to reset it?

[lua]
local positions = { Vector(712,-705,127), Vector(703,-139,127), Vector(311,-309,127), Vector(327,-714,127) }

function CheckIfSuitable( pos )
local Ents = ents.FindInBox(pos + Vector( -16, -16, 0 ),pos + Vector( 16, 16, 64 ) )
local Blockers = 0

if Ents == nil then
	return true
end

for k, v in pairs( Ents ) do 
	if ( IsValid( v ) and (v:GetClass() == "player" ) ) then
		Blockers = Blockers + 1		
	end	
end		
	
if Blockers == 0 then
	return true	
end		
	
return false

end

function round.Start()
round.Announce(“A new round has started!”)

for k, v in pairs(player.GetAll()) do
	if v:Team() == TEAM_READY then
		local pos = table.Random(positions)
		if CheckIfSuitable(pos) then
			v:SetPos(pos)
			print("TELEPORTED")
		else
			print("Spawn was blocked!")
		end
	else
		print("Other team wasn't teleported.")
	end
end

end
[/lua]

Here try this. Your problem was you weren’t actually using the function. You need to feed the position into the function.


ply.UsedPos = pos

to reset:


ply.UsedPos = nil

Thank you for elaborating! Good to know.

Brilliant! I can see where I was making my errors now. Thank you for the fixed revision.

My last question I didn’t think I was going to have to ask, but it seems I’ve created an infinite loop in my script which is causing it to error out. To continue on with it, how would you go about checking a new position if it returns false. I attempted to have it go through another check function when it returns false, but thats creating the infinite loop. Suggestions?

The way you probably want to do it is; loop through your positions table (for k,v in pairs) and check each value (v) in the CheckIfSuitable function, if it returns true the set their position there and break from the loop, if you need some more guidance just ask

For future reference, you could easily mark a vector as used by making each entry in your vector table another table, which then contains both the vector and a bool whether it’s used. Although in your case, I’d use a separate table of remaining vectors which we can safely add and remove from:
[lua]pos = {
Vector(1,1,1),
Vector(2,2,2)
}

function SpawnAtRandomPos()
local pos2 = table.Copy(pos)

 for k,v in pairs(player.GetAll()) do
 	 if v:Team() == TEAM_READY then
 	 	 local ranpos = math.random(1, #pos2)
 	 	 v:SetPos(pos2[ranpos])
 	 	 table.remove(pos2, ranpos)
 	 end
 end

end[/lua]
There might be a better way, but this method avoids looping potentially back and forth between already used vectors since we keep picking random.

Thank you for all the help! I have got this working the way I wanted it to. I kind of prefer zet0r’s method due to the simplicity and not having to use looping, but both ways work fine!

I learned a quite a bit from this thread so once again, thank you for your time and support!