It’s the little blue boxes that follow the player as they move around. Its supposed to show you where you are on the server
The problem with my script is that it keeps making the ghost look very choppy. I’ve tried to Tween the parts of the ghost to the position of the players character and I’ve also tried to set its cframe to the cframe of the character.
local tweenService = game:GetService("TweenService")
local runserver = game:GetService("RunService")
local Ghosts = {
}
runserver.Heartbeat:Connect(function(plr)
for num1 , GhostTab in pairs(Ghosts) do
for num2 , GhostPart in pairs(GhostTab.Ghost:GetChildren()) do
local part = GhostTab.Char:FindFirstChild(GhostPart.Name)
GhostPart.CFrame = part.CFrame
end
end
end)
game.Players.PlayerAdded:Connect(function(plr)
local ghost = nil
plr.CharacterAdded:Connect(function(char)
ghost = game.ReplicatedStorage.Copy.Debug.GhostPvpChar:Clone()
ghost.Parent = game.Workspace
local gtab = {
["Ghost"] = ghost;
["Player"] = plr;
["Char"] = char
}
table.insert(Ghosts,gtab)
end)
end)
I recommend using ipairs in GetChildren() and use square brackets instead of :FindFirstChild(). I don’t know if anything changes but I guess it’s worth a try.
I don’t really see any change in performance nor does it make it look smoother. Thanks for trying to help! also what’s the difference between square brackets and :FindFirstChild()? from what I can see they do the same thing.
Why is this being handled on the server, I don’t really see the point in implementing a system like this other than visual effect… It would be better to handle this on the client, that’s me assuming you don’t require other players to see other player boxes…
Right, can I ask you was this how you implemented the tweening?
local tweenService = game:GetService("TweenService")
local tweeninfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
local runserver = game:GetService("RunService")
local Ghosts = {
}
runserver.Heartbeat:Connect(function(plr)
for num1 , GhostTab in pairs(Ghosts) do
for num2 , GhostPart in pairs(GhostTab.Ghost:GetChildren()) do
local part = GhostTab.Char:FindFirstChild(GhostPart.Name)
local goal = {CFrame = part.CFrame}
local tweeninstance = tweenservice:Create(GhostPart,tweeninfo,goal)
tweeninstance:Play()
end
end
end)
game.Players.PlayerAdded:Connect(function(plr)
local ghost = nil
plr.CharacterAdded:Connect(function(char)
ghost = game.ReplicatedStorage.Copy.Debug.GhostPvpChar:Clone()
ghost.Parent = game.Workspace
local gtab = {
["Ghost"] = ghost;
["Player"] = plr;
["Char"] = char
}
table.insert(Ghosts,gtab)
end)
end)
Sorry, if this is a little too much but can I see a small clip of you tweening?
I’m just making sure because tweening is probably the smoothest transition in roblox your going to get…
Hmmm, strange… This is really because this function here
We gonna have to rewrite this to be more efficient since your having to iterate through every single players Ghost which is very inefficient the way you have logically layed this out give me a second
Instead of having this layed out like this wouldn’t it be best if we took a properly welded rig add the selection boxes, tween ghosts HRP to the plrs HRP then we just take the players animation track via
local animtracks = player.Character.Humanoid:GetPlayingAnimationTracks()
and play it to the ghosts humanoid, this will be less computationally heavy as opposed to what your currently doing
how could I do this without setting up multiple for loops inside of each other just to check if the animation track is already playing
so far I’ve gotten this
runserver.Heartbeat:Connect(function()
for num1 , GhostTab in pairs(Ghosts) do
local CharacterTracks = GhostTab.Char.Humanoid:GetPlayingAnimationTracks()
local GhostTracks = GhostTab.Ghost.AniControl:GetplayingAnimationTracks()
for i , CharTrack in pairs(CharacterTracks) do
local animation = CharTrack.Animation
for i , GhostTrack in pairs(GhostTracks) do
-- check if Tracks are similar and play if one isn't playing
end
end
local goal = {["CFrame"] = GhostTab.Char.HumanoidRootPart.CFrame}
local tweeninstance = tweenService:Create(GhostTab.Ghost.HumanoidRootPart,TweenInfo.new(.1),goal)
tweeninstance:Play()
end
end)
Animation track is a table that contains the loaded and recently played animation.
In this case you wouldn’t need to get the ghosts animation track, since all we going to need do is get the players recent animation, in this case would be (example)
local plrtrack = plr.Character.Humanoid.Animator:GetPlayingAnimationTracks()
local recentanimation = plrtrack[1]
-- Now all you would need to do is play #recentanimation to ghosts character by loading it into the humanoid via its animator object
EDIT: recentanimation is an instance of the animation playing…
But the track would be playing every tick which causes lag and doesn’t make the ghost move also how would I stop the animations after the player stopped using them for example the walking animation
Oh, sorry for the late reply I was doing something else
Here is something I just whipped up together, sorry again
local tweenService = game:GetService("TweenService")
local tweeninfo = TweenInfo.new(.5, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, 0, false, 0)
local runserver = game:GetService("RunService")
local Ghosts = {}
runserver.Heartbeat:Connect(function(plr)
for plrName, info in pairs(Ghosts) do
local ghosthrp = info["Ghost"].HumanoidRootPart
local goal = {}
goal.CFrame = info["Char"].HumanoidRootPart.CFrame
local tweeninstance = tweenService:Create(ghosthrp,tweeninfo,goal)
tweeninstance:Play()
end
end)
game.Players.PlayerAdded:Connect(function(plr)
local ghost = nil
plr.CharacterAdded:Connect(function(char)
ghost = game.ReplicatedStorage.Copy.Debug.GhostPvpChar:Clone()
ghost.Parent = game.Workspace
Ghosts[plr.Name] = {
["Ghost"] = ghost;
["Player"] = plr;
["Char"] = char
}
char.Humanoid.AnimationPlayed:Connect(function(recentanimation)
for i, track in pairs (ghost.Humanoid:GetPlayingAnimationTracks()) do
track:Stop()
end
local recentanimation = recentanimation.Animation
local hum = ghost.Humanoid
local anim = hum:LoadAnimation(recentanimation)
anim:Play()
end)
end)
end)
If that still is laggy then we can use BodyPosition and BodyGyro which can eliminate the use of tweening entirely
EDIT:
Here is that as well since I already did it might as well complete it here it is fully working
local runserver = game:GetService("RunService")
local Ghosts = {}
runserver.Heartbeat:Connect(function(plr)
for plrName, info in pairs(Ghosts) do
if info["Char"]:FindFirstChild("HumanoidRootPart",false) then
info["GhostBodyTrack"][1].Position = info["Char"].HumanoidRootPart.Position
info["GhostBodyTrack"][2].CFrame = info["Char"].HumanoidRootPart.CFrame
end
end
end)
game.Players.PlayerAdded:Connect(function(plr)
local ghost = nil
plr.CharacterAdded:Connect(function(char)
ghost = game.ReplicatedStorage.Copy.Debug.GhostPvpChar:Clone()
ghost.Parent = game.Workspace
local bodyposition = Instance.new("BodyPosition",ghost.HumanoidRootPart); bodyposition.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
local bodygyro = Instance.new("BodyGyro",ghost.HumanoidRootPart); bodygyro.MaxTorque = Vector3.new(10000,10000,10000)
Ghosts[plr.Name] = {
["Ghost"] = ghost;
["Player"] = plr;
["Char"] = char;
["GhostBodyTrack"] = {bodyposition,bodygyro}
}
char.Humanoid.AnimationPlayed:Connect(function(recentanimation)
for i, track in pairs (ghost.Humanoid:GetPlayingAnimationTracks()) do
track:Stop()
end
local recentanimation = recentanimation.Animation
local hum = ghost.Humanoid
local anim = hum:LoadAnimation(recentanimation)
anim:Play()
end)
end)
end)