Hey, so I’m trying to teleport a player to another player, but only if they do not surpass the maximum range, if they do, I want to teleport basically to the max range but in the direction where the opposing player is looking to.
Here is my current math-thingy, it’s quite broken though, any ideas?
Looking at your code you seem to have the math wrong. Also, you should use PVInstance:PivotTo instead of Part.Position when repositioning the player.
Also, math.max returns the larger of the two numbers passed instead of restricting a value to a range. Instead you should use math.clamp. The first parameter is the value you want to restrict, the second the minimum value allowed, and the third the maximum value allowed. Then if the first value is less than the second it returns the second value and if it’s larger than the third value it returns the third value. If the first value is in-between the min and max values then it returns the first value.
So to do this I would do something like this instead:
local player = teleportPlayer -- the player we want to teleport
local target = targetPlayer -- the player we want to teleport to
local maxDistance = 200 -- the maximum distance from the Target the player can be
-- The function we use to teleport the players’ character to the targets’ character
local function teleport(playerCharacter, targetCharacter)
local distance = (playerCharacter:GetPivot().Position - targetCharacter:GetPivot().Position).Magnitude -- the distance the player is from the target
distance -= math.clamp(distance, 2, maxDistance) -- will be 0 if we are within the max distance. If we are less than 2 studs away it will default to two. Otherwise it will be the distance of how much further we are out of range.
targetCharacter:PivotTo(targetCharacter: GetPivot() + targetCharacter:GetPivot().LookVector * distance) -- teleports the player distance studs in front of the target player.
end
-- teleport the player to the target player
teleport(player.Character, target.Character)
Edit: One thing I should mention! PVInstance | Roblox Creator Documentation will teleport the player to the new position regardless of whether or not something is at that location. This means they could get trapped inside a wall, fall through terrain, or something. If this behavior is undesired then you should use Model | Roblox Creator Documentation. It will teleport the player on top of whatever obstruction is in the way.
Thank you, sadly, this doesn’t work for me, it teleports to very weird places. Here is my code.
--Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local ServerStorage = game:GetService("ServerStorage")
--Folders
local Modules = ServerScriptService:WaitForChild("Modules")
local Remotes = ReplicatedStorage:WaitForChild("Remotes")
--Remotes
local TeleportRemote = Remotes:WaitForChild("RequestTeleport")
--Modules
local Utils = require(Modules:WaitForChild("Utils"))
local CharacterAbilities = require(Modules:WaitForChild("CharacterAbilities"))
--On server event
TeleportRemote.OnServerEvent:Connect(function(plr, mouse)
--Get player data
local Data = Utils.GetData(plr)
if not Data then return plr:Kick(Utils.Error("No data.")) end
--Check player fighter
local PlayerFighter = Data.Character.Value
if PlayerFighter ~= "None" then
--If player has a character selected, we get that characters teleport range
local CharTPRange = CharacterAbilities[PlayerFighter].TPRange
--Next, we declare some variables regarding Player's character
local PlayerChar = plr.Character
local PlayerRoot = PlayerChar.HumanoidRootPart
local PlayerHead = PlayerChar.Head
--Now, let's check if the player is currently locked onto somebody.
local LockedValue = Data.lockedOnto.Value
--If the player is locked, let's teleport to the locked on player.
if LockedValue ~= "None" then
--Let's get some info about the locked on player.
local TargetPlayer = Players:FindFirstChild(LockedValue)
local TargetChar = TargetPlayer.Character
local TargetRoot = TargetChar.HumanoidRootPart
local TargetHead = TargetChar.Head
--Let's see if the location of the 2nd player does not exceed the maximum allowed Teleport Range.
local MagnitudeLock = (PlayerHead.Position - TargetHead.Position).Magnitude
if MagnitudeLock <= CharTPRange then
--If everything is alright, we can proceed with the teleport. First, let's set the offset of the player.
local OFFSET = 4
--Before we completely teleport, let's check if the player has sufficient mana to teleport.
local Mana = Data.Mana.Value
local ManaCost = CharacterAbilities[PlayerFighter].TPManaCost
if Mana >= ManaCost then
--Let's deduct the mana.
local ManaEquation = Mana - ManaCost
Data.Mana.Value = ManaEquation
--Now we teleport!
PlayerRoot.CFrame = TargetRoot.CFrame * CFrame.new(0, 0, -OFFSET)
end
-- If the Teleport Range is not sufficient, we teleport to the max allowed range.
elseif MagnitudeLock > CharTPRange then
local distance = (PlayerChar:GetPivot().Position - TargetChar:GetPivot().Position).Magnitude -- the distance the player is from the target
distance -= math.clamp(distance, 2, CharTPRange) -- will be 0 if we are within the max distance. If we are less than 2 studs away it will default to two. Otherwise it will be the distance of how much further we are out of range.
TargetChar:PivotTo(TargetChar:GetPivot() + TargetChar:GetPivot().LookVector * distance)
end
end
end
end)
Raycast, you could create a ray and teleport the player to the ray’s hitting location (but also make them teleport a bit above to prevent ground phasing).
And any idea why this doesnt work?
local distance = (PlayerChar:GetPivot().Position - TargetChar:GetPivot().Position).Magnitude – the distance the player is from the target
distance -= math.clamp(distance, 2, CharTPRange) -- will be 0 if we are within the max distance. If we are less than 2 studs away it will default to two. Otherwise it will be the distance of how much further we are out of range.
TargetChar:PivotTo(TargetChar:GetPivot() + TargetChar:GetPivot().LookVector * distance)
Why don’t you just use Magnitude like you first did, use an if statement with < and =, then proceed to create the ray to teleport to the limiting blocks?
Or, since it’s a teleport to target character, have it simply be a magnitude check.
Sorry about that. I tested my code and found a few issues, so here’s the working version:
local player = teleportPlayer -- the player we want to teleport
local target = targetPlayer -- the player we want to teleport to
local maxDistance = 200 -- the maximum distance from the Target the player can be
-- The function we use to teleport the players’ character to the targets’ character
local function teleport(playerCharacter, targetCharacter, offset)
offset = offset or 4
local tarFrame = targetCharacter:GetPivot() -- the CFrame of the targetCharacter
local distance = (playerCharacter:GetPivot().Position - tarFrame.Position).Magnitude -- the distance the player is from the target
if distance >= (maxDistance + offset) then
distance -= math.clamp(distance, offset, maxDistance)
else
distance += offset - math.clamp(distance, offset, maxDistance)
end
playerCharacter:PivotTo(CFrame.lookAt((tarFrame + tarFrame.LookVector * distance).Position, tarFrame.Position)) -- teleports the player distance studs in front of the target player.
end
-- teleport the player to the target player
teleport(player.Character, target.Character)
Here’s what it might look like in your code:
--Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local ServerStorage = game:GetService("ServerStorage")
--Folders
local Modules = ServerScriptService:WaitForChild("Modules")
local Remotes = ReplicatedStorage:WaitForChild("Remotes")
--Remotes
local TeleportRemote = Remotes:WaitForChild("RequestTeleport")
--Modules
local Utils = require(Modules:WaitForChild("Utils"))
local CharacterAbilities = require(Modules:WaitForChild("CharacterAbilities"))
-- The function we use to teleport the players’ character to the targets’ character
local function teleportToTarget(playerCharacter, targetCharacter, offset)
offset = offset or 4
local tarFrame = targetCharacter:GetPivot() -- the CFrame of the targetCharacter
local distance = (playerCharacter:GetPivot().Position - tarFrame.Position).Magnitude -- the distance the player is from the target
if distance >= (maxDistance + offset) then
distance -= math.clamp(distance, offset, maxDistance)
else
distance += offset - math.clamp(distance, offset, maxDistance)
end
playerCharacter:PivotTo(CFrame.lookAt((tarFrame + tarFrame.LookVector * distance).Position, tarFrame.Position)) -- teleports the player distance studs in front of the target player.
end
--On server event
TeleportRemote.OnServerEvent:Connect(function(plr, mouse)
--Get player data
local Data = Utils.GetData(plr)
if not Data then return plr:Kick(Utils.Error("No data.")) end
--Check player fighter
local PlayerFighter = Data.Character.Value
if PlayerFighter ~= "None" then
--If player has a character selected, we get that characters teleport range
local CharTPRange = CharacterAbilities[PlayerFighter].TPRange
--Next, we declare some variables regarding Player's character
local PlayerChar = plr.Character
local PlayerRoot = PlayerChar.HumanoidRootPart
local PlayerHead = PlayerChar.Head
--Now, let's check if the player is currently locked onto somebody.
local LockedValue = Data.lockedOnto.Value
--If the player is locked, let's teleport to the locked on player.
if LockedValue ~= "None" then
--Let's get some info about the locked on player.
local TargetPlayer = Players:FindFirstChild(LockedValue)
local TargetChar = TargetPlayer.Character
--Before we completely teleport, let's check if the player has sufficient mana to teleport.
local ManaCost = CharacterAbilities[PlayerFighter].TPManaCost
if Data.Mana.Value >= ManaCost then
Data.Mana.Value -= ManaCost --Let's deduct the mana.
teleportToTarget(PlayerChar, TargetChar, 4) -- teleport with offset of 4
end
end
end
end)
Thank you so much, however this still does not seem to work for me, I get this error:
ServerScriptService.Player.TeleportHandler:25 Attempt to perform an arithmetic (add) on an Instance and number.
Here is my code:
--Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local ServerStorage = game:GetService("ServerStorage")
--Folders
local Modules = ServerScriptService:WaitForChild("Modules")
local Remotes = ReplicatedStorage:WaitForChild("Remotes")
--Remotes
local TeleportRemote = Remotes:WaitForChild("RequestTeleport")
--Modules
local Utils = require(Modules:WaitForChild("Utils"))
local CharacterAbilities = require(Modules:WaitForChild("CharacterAbilities"))
-- The function we use to teleport the players’ character to the targets’ character
local function teleportToTarget(playerCharacter, targetCharacter, offset, maxDistance)
offset = offset or 4
local tarFrame = targetCharacter:GetPivot() -- the CFrame of the targetCharacter
local distance = (playerCharacter:GetPivot().Position - tarFrame.Position).Magnitude -- the distance the player is from the target
if distance >= (playerCharacter + offset) then
distance -= math.clamp(distance, offset, maxDistance)
else
distance += offset - math.clamp(distance, offset, maxDistance)
end
playerCharacter:PivotTo(CFrame.lookAt((tarFrame + tarFrame.LookVector * distance).Position, tarFrame.Position)) -- teleports the player distance studs in front of the target player.
end
--On server event
TeleportRemote.OnServerEvent:Connect(function(plr, mouse)
--Get player data
local Data = Utils.GetData(plr)
if not Data then return plr:Kick(Utils.Error("No data.")) end
--Check player fighter
local PlayerFighter = Data.Character.Value
if PlayerFighter ~= "None" then
--If player has a character selected, we get that characters teleport range
local CharTPRange = CharacterAbilities[PlayerFighter].TPRange
--Next, we declare some variables regarding Player's character
local PlayerChar = plr.Character
local PlayerRoot = PlayerChar.HumanoidRootPart
local PlayerHead = PlayerChar.Head
--Now, let's check if the player is currently locked onto somebody.
local LockedValue = Data.lockedOnto.Value
--If the player is locked, let's teleport to the locked on player.
if LockedValue ~= "None" then
--Let's get some info about the locked on player.
local TargetPlayer = Players:FindFirstChild(LockedValue)
local TargetChar = TargetPlayer.Character
--Before we completely teleport, let's check if the player has sufficient mana to teleport.
local ManaCost = CharacterAbilities[PlayerFighter].TPManaCost
if Data.Mana.Value >= ManaCost then
Data.Mana.Value -= ManaCost --Let's deduct the mana.
teleportToTarget(PlayerChar, TargetChar, 4, CharTPRange) -- teleport with offset of 4
end
end
end
end)
Looks likes you accidentally changed the code when adding the maxDistance parameter to the teleportToTarget function. You replaced the original maxDistance variable with the playerCharacter variable, so it’s trying to add the playerCharacter instance and the offset variable together. Just replace
Thank you, it actually did teleport me this time but sadly it teleported me under the map, any ideas?
--Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local ServerStorage = game:GetService("ServerStorage")
--Folders
local Modules = ServerScriptService:WaitForChild("Modules")
local Remotes = ReplicatedStorage:WaitForChild("Remotes")
--Remotes
local TeleportRemote = Remotes:WaitForChild("RequestTeleport")
--Modules
local Utils = require(Modules:WaitForChild("Utils"))
local CharacterAbilities = require(Modules:WaitForChild("CharacterAbilities"))
-- The function we use to teleport the players’ character to the targets’ character
local function teleportToTarget(playerCharacter, targetCharacter, offset, maxDistance)
offset = offset or 4
local tarFrame = targetCharacter:GetPivot() -- the CFrame of the targetCharacter
local distance = (playerCharacter:GetPivot().Position - tarFrame.Position).Magnitude -- the distance the player is from the target
if distance >= (maxDistance + offset) then
distance -= math.clamp(distance, offset, maxDistance)
else
distance += offset - math.clamp(distance, offset, maxDistance)
end
playerCharacter:PivotTo(CFrame.lookAt((tarFrame + tarFrame.LookVector * distance).Position, tarFrame.Position)) -- teleports the player distance studs in front of the target player.
end
--On server event
TeleportRemote.OnServerEvent:Connect(function(plr, mouse)
--Get player data
local Data = Utils.GetData(plr)
if not Data then return plr:Kick(Utils.Error("No data.")) end
--Check player fighter
local PlayerFighter = Data.Character.Value
if PlayerFighter ~= "None" then
--If player has a character selected, we get that characters teleport range
local CharTPRange = CharacterAbilities[PlayerFighter].TPRange
--Next, we declare some variables regarding Player's character
local PlayerChar = plr.Character
local PlayerRoot = PlayerChar.HumanoidRootPart
local PlayerHead = PlayerChar.Head
--Now, let's check if the player is currently locked onto somebody.
local LockedValue = Data.lockedOnto.Value
--If the player is locked, let's teleport to the locked on player.
if LockedValue ~= "None" then
--Let's get some info about the locked on player.
local TargetPlayer = Players:FindFirstChild(LockedValue)
local TargetChar = TargetPlayer.Character
--Before we completely teleport, let's check if the player has sufficient mana to teleport.
local ManaCost = CharacterAbilities[PlayerFighter].TPManaCost
if Data.Mana.Value >= ManaCost then
Data.Mana.Value -= ManaCost --Let's deduct the mana.
teleportToTarget(PlayerChar, TargetChar, 4, CharTPRange) -- teleport with offset of 4
end
end
end
end)
Or, if you wanted to, you could create some invisible bricks that collectively contain the map and then check to see if the teleport location is within one of them.
Here’s a function to check if a position is within a part:
local function isPosInPart(position, part) -- returns true if the position is in the part and false if it isn’t
position = part:PointToObjectSpace(position)
return (math.abs(position.X) <= part.Size.X and math.abs(position.Y) <= part.Size.Y and math.abs(position.Z) <= part.Size.Z)
end
Then you could loop through the invisible bricks to check and see if the teleport location is within one of them.
I think this is exactly what you want, paste it into a LocalScript inside of StarterCharacterScripts
local localPlayer = game:GetService('Players').LocalPlayer
local mouse = localPlayer:GetMouse()
local character = localPlayer.Character
local maxRange = 25
mouse.Button1Down:Connect(function()
local otherCharacterCFrame = CFrame.new(Vector3.new(0,3,0))
local otherCharacterPosition = otherCharacterCFrame.Position
local direction = (otherCharacterPosition-character.PrimaryPart.Position)
local newPosition = (direction.Magnitude <= maxRange and otherCharacterPosition) or otherCharacterCFrame.Position+otherCharacterCFrame.LookVector*maxRange
character:SetPrimaryPartCFrame(CFrame.new(newPosition))
end)
Thank you, however it is not, since I need to make it ServerSided, due to the fact that I am making a cooldown and that I am deducting Mana from the player, both of which are ServerSided.
Having it local was just to show you how its done and so you can test it easily, not to make it work with your system. The calculations would still work on the server