I’m making an obby game that includes wall jumps like in FE2, launch pads, etc. Also I have in the lobby a training room whose door tweens opened nicely. I also have it so the lobby changes to winter theme automatically during the winter season.
The wall jumps, launch pads, and training room door work perfectly fine if I’m playing alone. But, when I tested with 3 other people none of them worked. I tested again with just me and my alt and all the features worked perfectly fine.
The lobby also immediately changed to winter theme when I was playing alone or with an alt, but with 3+ people it took once maybe 10 seconds to change, then once it took approximately a minute.
Only possible problem I can think of is that I am utilizing coroutines with an infinite loop in it (which does slow all scripts down), but I’m not sure of an alternative to coroutines…
I tried task.spawn, but it just isn’t my solution.
My problem is I need something that doesn’t yield my script, and at the same time I need to be able to cancel the function at my leisure.
Here’s the part where coroutines are being used:
(coroutines aren’t being created here, just being run and/or stopped)
-- existingeffects is a list of dictionaries; the d.Function is obviously the function I'm trying to execute.
while wait() do
for a,b in pairs(folder:GetChildren()) do
for i,v in pairs(b:GetChildren()) do
if (v:IsA("BasePart") or v:IsA("UnionOperation") or v:IsA("MeshPart")) and v:FindFirstChildOfClass("AlignPosition") then
if (v:FindFirstChildOfClass("AlignPosition").Attachment0.WorldPosition - v:FindFirstChildOfClass("AlignPosition").Attachment1.WorldPosition).Magnitude > 50 then
v.Position = v:FindFirstChildOfClass("AlignPosition").Attachment1.WorldPosition
end
end
end
end
for c,d in pairs(existingEffects) do
if d.Player and game.Players:FindFirstChild(d.Player.Name) then
playerIsAtSpawn = checkIfPlayerIsInBounds(d.Player, spawnArea)
playerIsInVIPLounge = checkIfPlayerIsInBounds(d.Player, workspace.LobbyStuff.VIPArea)
if playerIsAtSpawn == true and d.Running == true and d.RC == true then
forceStopEffect(d,c)
if d.Player == game.Players.LocalPlayer and game.Players.LocalPlayer:FindFirstChild("PlayerGui") then
loadUIStatement("Your effect has been disabled while you are at spawn.")
end
continue
elseif playerIsInVIPLounge == true and d.Running == true and d.RC == true then
forceStopEffect(d,c)
if d.Player == game.Players.LocalPlayer and game.Players.LocalPlayer:FindFirstChild("PlayerGui") then
loadUIStatement("Your effect has been disabled while you are in the VIP lounge.")
end
continue
elseif userSettings:GetAttribute("HideEffects") == 3 and table.find(_G.Contestants, d.Player) and workspace.CurrentMap:FindFirstChildOfClass("Folder") then
forceStopEffect(d,c)
continue
end
if d.Running == true and d.RC ~= true then
if playerIsAtSpawn == false and playerIsInVIPLounge == false then
if effectsAreToggled == true then
coroutine.resume(d.Function)
d.RC = true
end
end
elseif d.Running == false and d.RC == true then
coroutine.close(d.Function);
d.RC = false
table.remove(existingEffects, c)
end
else
if d.Running == true and d.RC == true then
coroutine.close(d.Function)
end
table.remove(existingEffects, c)
end
end
end
Hopefully you can see now why task.spawn isn’t working out for me. I did use task.cancel when I tried out task.spawn, but because of task.spawn yielding, task.cancel serves useless.
The whole point of task.spawn is that it runs in a new thread, therefore not yielding. I’m assuming you were using it incorrectly.
I fixed a couple of things with your script:
You should be using task.wait instead of wait
pairs/ipairs should be removed and replaced with generalized iteration as it runs faster
You had checks for v:IsA("MeshPart") and v:IsA("UnionOperation") but then had v:IsA("BasePart")
The first two checks are useless, because MeshParts and UnionOperations are BaseParts
You should save the results of :FindFirstChild so you don’t waste performance
Code:
-- existingeffects is a list of dictionaries; the d.Function is obviously the function I'm trying to execute.
while task.wait() do
for a, b in folder:GetChildren() do
for i, v in b:GetChildren() do
if v:IsA("MeshPart") then
local AlignPosition = v:FindFirstChildOfClass("AlignPosition")
if AlignPosition and (AlignPosition.Attachment0.WorldPosition - AlignPosition.Attachment1.WorldPosition).Magnitude > 50 then
v.Position = AlignPosition.Attachment1.WorldPosition
end
end
end
end
for c,d in existingEffects do
if d.Player and game.Players:FindFirstChild(d.Player.Name) then
playerIsAtSpawn = checkIfPlayerIsInBounds(d.Player, spawnArea)
playerIsInVIPLounge = checkIfPlayerIsInBounds(d.Player, workspace.LobbyStuff.VIPArea)
if playerIsAtSpawn == true and d.Running == true and d.RC == true then
forceStopEffect(d,c)
if d.Player == game.Players.LocalPlayer and game.Players.LocalPlayer:FindFirstChild("PlayerGui") then
loadUIStatement("Your effect has been disabled while you are at spawn.")
end
continue
elseif playerIsInVIPLounge == true and d.Running == true and d.RC == true then
forceStopEffect(d,c)
if d.Player == game.Players.LocalPlayer and game.Players.LocalPlayer:FindFirstChild("PlayerGui") then
loadUIStatement("Your effect has been disabled while you are in the VIP lounge.")
end
continue
elseif userSettings:GetAttribute("HideEffects") == 3 and table.find(_G.Contestants, d.Player) and workspace.CurrentMap:FindFirstChildOfClass("Folder") then
forceStopEffect(d,c)
continue
end
if d.Running == true and d.RC ~= true then
if playerIsAtSpawn == false and playerIsInVIPLounge == false then
if effectsAreToggled == true then
coroutine.resume(d.Function)
d.RC = true
end
end
elseif d.Running == false and d.RC == true then
coroutine.close(d.Function);
d.RC = false
table.remove(existingEffects, c)
end
else
if d.Running == true and d.RC == true then
coroutine.close(d.Function)
end
table.remove(existingEffects, c)
end
end
end
Thanks for pointing those errors out. I did find myself doing something wrong with the task.spawn: corrected my issue and it is no longer yielding. Won’t be able to mark this as a solution until I can test this out with other people…
Thanks for that list. Regarding the stuff like wall jumps and launch pads, I am only using one loop which simply checks if the player hits the wall (since touched events are not ideal), but that shouldn’t exactly be a big problem, should it?
Okay I finally got around to testing this out with 3+ people. Switching to using task instead of coroutines appears to have solved one issue, but it has yet to solve the others.
The wall jumps and launchpads I’ve discovered will work randomly, but the chances are rather low (when there are 3+ people, works fine if there are two or lower); however, if I reset my character they work fine (the scripts are located under StarterCharacterScripts). Since the script just uses a for loop and :GetDescendants() to find wall jumps and launch pads in the map, I think it is safe to assume this is a loading issue? However, I did put a wait(3) once a map is added into the workspace and that really didn’t fix the issue.
The lobby also continues to take up to seconds to switch when there are multiple people.
Here’s how the script detects wall jumps and launch pads; the actual code for the wall jumps and launch pads works fine, it’s just that it won’t detect anything when the map is first added. I have to reset my character to get it to work (the script is a local script located under StarterCharacterScripts).
I had put a wait(3) in front in case maybe the map is slow to load in, but it didn’t seem to work at all. The same issue occurs with kill bricks that I have in my game too.
local map = workspace.CurrentMap:FindFirstChildOfClass("Folder")
repeat wait() map = workspace.CurrentMap:FindFirstChildOfClass("Folder") until map
local activeWallJumps = {}
wait(3)
for _,model in pairs(map:GetDescendants()) do
if model:IsA("Model") then
if string.lower(model.Name) == "launchpad" and model:FindFirstChild("Destination") and model:FindFirstChild("Pad") then
-- Launchpads
local pad, destination = model:WaitForChild("Pad"), model:WaitForChild("Destination")
local debounce
pad.Touched:connect(function(hit)
-- And here goes a bunch of code for the launchpads.
end)
end
elseif model:IsA("BasePart") then
if string.lower(model.Name) == "walljump" then
-- WallJumps
table.insert(activeWallJumps, model) -- A while loop handles whether a player is on a walljump or not using this activeWallJumps table.
end
end
end
The features actually do rely on the client; I’ve hid the code though. Would it be just as feasible to put the launchpads and wall jumps in a table in the server and send the table over to the client?
The launch pads use LinearVelocity to launch players from a launch pad to a specific destination in a semi-elliptical pattern, which needs to be accurate for an obstacle course game. I’ve already tried scripting it on the server prior to this post and found it didn’t work because the character’s position on the server and on the client can be different, causing the path to be inaccurate…
As for the wall jumps, they don’t rely on touched events since touched events don’t always fire so it relies on a while loop instead (which, for the same reason above, scripting it on the server wouldn’t be very ideal). And I’m also using UserInputService to detect when a player wants to jump off the wall.