Hi folks!
New member that is thrilled to be able to engage with the community finally. My first post will expose how new I am and how much I have to learn. At the risk of having my Roblox Dev card revoked, here goes:
In my game you earn points for jumping, and can earn higher points if you jump over certain terrain. I have parts over challenging terrain called Terrain Multipliers. I plan to have many of these multiplier parts sprinkled around the map. My system works fine if I define each part with a unique name, then have a unique touched event trigger a function to change the multiplier. I’m sure this is far from optimal. I’m trying to find the correct solution, where I simply have the function to change the multiplier only defined once, and it is called any time you touch one of the many different multipliers on the map.
TL;DR: I am trying to set player.TerrainMultiplier.Value to 2 when the player touches any of three different parts on the map: TerrMult2x001, TerrMult2x002 or TerrMult2x003, all without writing out the function three times.
local TerrainX2 = game.Workspace.TerrainMultipliers.TerrMult2x001
local TerrainX2 = game.Workspace.TerrainMultipliers.TerrMult2x002
local TerrainX2 = game.Workspace.TerrainMultipliers.TerrMult2x003
--------------------------------------------------
db = false
TerrainX2.Touched:Connect(function(hit)
print("Player Touched Terrain X2 Part")
if hit.Parent:FindFirstChild("Humanoid") then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if db == false then
db = true
player.TerrainMultiplier.Value = 2
wait(1)
db = false
end
end
end)
Thanks much.
3 Likes
Something I quickly wrote up. This would do the trick, and it’s a little more compact than your current one. Put all the things from your function (provided in the OP) in your part.Touched() event in the loop.
local Parts = {game.Workspace.Part1, game.Workspace.Part2}
for _, part in pairs(Parts) do
part.Touched:Connect(function()
print(part.Name)
end)
end
2 Likes
If there are a lot of parts you want to connect this function to, you could go to the specific folder / model where all those parts are and loop through them all with GetChildren()
for i, part in pairs(game.Workspace.terrainPartsFolder:GetChildren()) do
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
--do something with the terrainMultiplier.Value
end
end
end
2 Likes
Thank you so much. I’m floored how folks are so willing and able to help here. I think this is my solution. @Polyheximal - Your code worked perfectly, and drastically cut down my huge script with the same function pasted over and over.
It turns out I’ll likely have well over 100 of these multipliers, so the folder/GetChildren solution should work. A silly question that I’ll test on my own, but will this work if the parts in terrainPartsFolder have the same name, or do they need to be unique?
Thank you both so much.
2 Likes
I’m pretty sure it will work if they have the same name, regardless. In @speeddecoolste’s code, it iterates through the objects in the folder’s children (in this case, the multiplier parts) and then checks if that part was touched. It doesn’t check for the name, but if you wanted to add checks for part names for certain things (e.g. certain multipliers with names like MultiplierX2 gives x2 and MultiplierX5 gives x5) would need to be named differently to each other to differentiate the multiplier value. However, if that isn’t the case, then they can all be the same name.
3 Likes
SUCCESS! Thank you both so much. Yes, the looping through folder with GetChildren works perfectly with same-name parts, which is great because now I can just duplicate and sprinkle the parts around the map easily. I simply made separate folders for the X2 and X3 and X4…and so on…multipliers and it works flawlessly.
3 Likes
If you do prefer to use one script with 1 loop instead of having multiple scripts you could make 1 big folder with multiple folders inside of it, and loop through them all with GetDescendants().
for i, part in pairs(game.Workspace.allTerrainPartsFolders:GetDescendants()) do
if part:IsA("Folder") == false then
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
if part.Name == "X2Part" then
--give the player X2
elseif part.Name == "X3Part" then
--give the player X3
elseif part.Name == "X4Part" then --etc...
end
end
end
end
end
1 Like
Hmm, Interesting, that is probably what I should do. I’m currently working with three different multiplier levels, so I still ended up repeating the function three times in the same script. It seems to be working well, but is probably still longer (less efficient?) than it needs to be. Still certainly much better than my first pass where I had the function pasted for each individual part in the workspace.
db = false
for i, part in pairs(game.Workspace.TerrainMults2x:GetChildren()) do
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if db == false then
db = true
player.TerrainMultiplier.Value = 2
wait(.5)
db = false
end
end
end
end)
end
------------------------------------
db = false
for i, part in pairs(game.Workspace.TerrainMults3x:GetChildren()) do
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if db == false then
db = true
player.TerrainMultiplier.Value = 3
wait(.5)
db = false
end
end
end
end)
end
------------------------------------
db = false
for i, part in pairs(game.Workspace.TerrainMults4x:GetChildren()) do
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if db == false then
db = true
player.TerrainMultiplier.Value = 4
wait(.5)
db = false
end
end
end
end)
end
If you use GetDescendants() it doesn’t really matter how many mulitplier levels you have, as long as the names are the same from each seperate multiplier, you should be able to give them all seperate boosts
this is how the folder structure would look like
for i, part in pairs(game.Workspace.allTerrainMults:GetDescendants()) do
if part:IsA("Part") then --we check if its a part, and not a folder.
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
if part.Name == "TerrMult2x002" then
--give boost
elseif part.Name == "TerrMult2x003" then
--give boost
elseif part.Name == "TerrMult2x004" then --etc...
--give boost
end
end
end
end)
end
end
The reason why I am using folders inside one bigger folder is to make it easier to read. You could also place all parts inside one folder without subfolders and use :GetChildren() instead of :GetDescendants and without checking if its a part
1 Like
Thank you for taking the time to illustrate and update the code. Very educational for me. And yes, this works 100% perfectly. I now have good multipliers. I still may use your nested IF statement to further simplify.
1 Like