• Teleporting a player to a different vector if collision
    10 replies, posted
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!) [CODE]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 [/CODE] 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 [url]https://github.com/Alig96/nzombies/blob/master/nzombies3/gamemode/enemies/sv_spawner.lua#L3[/url]
[QUOTE=Alig96;48322105][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 [url]https://github.com/Alig96/nzombies/blob/master/nzombies3/gamemode/enemies/sv_spawner.lua#L3[/url][/QUOTE] I currently revised my code attempting to use your snippet but I seem to be failing. I'm getting a GMOD error of [code][ERROR] /gamemode/init.lua:34: bad argument #1 to '__add' (Vector expected, got table) 1. __add - [C]:-1 [/code] For some reason it doesn't want to read my POS table as a vector. Any suggestions? Here is my current revision [code] 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 [/code] [QUOTE=Zet0r;48322075]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.[/QUOTE] 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? [QUOTE=tyguy;48320278]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[/QUOTE] 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.
[QUOTE=cold020;48326002]I currently revised my code attempting to use your snippet but I seem to be failing. I'm getting a GMOD error of [code][ERROR] /gamemode/init.lua:34: bad argument #1 to '__add' (Vector expected, got table) 1. __add - [C]:-1 [/code] For some reason it doesn't want to read my POS table as a vector. Any suggestions? Here is my current revision [code] 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 [/code] 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?[/QUOTE] [code]ply.UsedPos = pos[/code] to reset: [code]ply.UsedPos = nil[/code]
[QUOTE=tyguy;48326651][code]ply.UsedPos = pos[/code] to reset: [code]ply.UsedPos = nil[/code][/QUOTE] Thank you for elaborating! Good to know. [QUOTE=Alig96;48326536][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.[/QUOTE] 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.
[QUOTE=Alig96;48331287]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[/QUOTE] [QUOTE=Zet0r;48336192]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.[/QUOTE] 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!
Sorry, you need to Log In to post a reply to this thread.