You can write your topic however you want, but you need to answer these questions:
What do you want to achieve? Keep it simple and clear!
i want to change frame visibility according to the amount of tasks there are and change these frames textlabels to the tasks, so the tasks are like Task1, Task2. they should follow this order.
What is the issue? Include screenshots / videos if possible!
When I try t make single text change, like that:
if TasksNum == 1 then
for _,v in Frame.Frame.Tasks:GetChildren() do
if not v:IsA("UIListLayout") then
if v:IsA("Frame") then
v.Parent.Parent.Title.Text = Tasks.ObjName.Value
if v.Name ~= "Task"..TasksNum then
v.Visible = false
else
if Tasks.Tasks.Task1.Required.Value == true then
v.TaskName.Text = Tasks.Tasks.Task1.TaskName.Value.." [REQUIRED]"
else
v.TaskName.Text = Tasks.Tasks.Task1.TaskName.Value
end
v.TaskRequired.Text = Tasks.Tasks.Task1.TaskDesc.Value
end
end
end
end
it works fine, everything works as intended.
but when i try to do multiple, like this:
elseif TasksNum >= 2 then
for _,v in Frame.Frame.Tasks:GetChildren() do
if not v:IsA("UIListLayout") then
if v:IsA("Frame") then
v.Parent.Parent.Title.Text = Tasks.ObjName.Value
if v.Task.Value > TasksNum or v.Task.Value < 1 then
v.Visible = false
end
for i = 1, TasksNum do
--if i ~= TasksNum then
local N = "Task"
local tasko = N..i
print(tasko)
local Actual = Tasks.Tasks:FindFirstChild(tasko)
if Actual.Required.Value == true then
v.TaskName.Text = Actual.TaskName.Value.." [REQUIRED]"
else
v.TaskName.Text = Actual.TaskName.Value
end
v.TaskRequired.Text = Actual.TaskDesc.Value
--end
end
end
end
end
as you see, it just clones the task title and desc of second one and does it for 3 frames. so everything else is fine but labeling is not.
3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
tried everything other way to make it. it just didn’t work oo the code was messy so it was not good for player performance.
I am so confused of what you are trying to say. So like do you want to make labels and put the task name and desc in those labels so the players can see but your code doesn’t seem to work when you try it for multiple labels?
Why are you repeating the same thing again on the second code? Or are they both diffrent?
As long as I understand why don’t you make a for i, v in pairs(Tasks)(refering to the object value) then loop through the Tasks Frame and see if the name matches (since the task object values and the frames have the same name). If the names do match then apply the Name, description of the object value to the frames children where they belong?
Oh and it would’ve been nice if you commented on the code what they do or what are they for, something like that.
Why are you repeating the same thing again on the second code? Or are they both diffrent?
So first, I tried to make it on a single one, and it worked. When I manage to make this one work, I will remove that part. it just to reset if everything goes wrong.
As long as I understand why don’t you make a for i, v in pairs(Tasks)(refering to the object value) then loop through the Tasks Frame and see if the name matches (since the task object values and the frames have the same name) . If the names do match then apply the Name, description of the object value to the frames children where they belong?
Hmm I could try that. I will post back on how it goes.
Alrighty, it worked as inteded. tysm!
Also, any idea on how i could improove my code?
local event = game:GetService("ReplicatedStorage").Events:WaitForChild("Tasks")
local plr = game:GetService("Players").LocalPlayer
local deb = false
local frm = plr.PlayerGui:WaitForChild("ObjNew").Frame.Tasks
event.OnClientEvent:Connect(function(TasksNum,Tasks)
print(TasksNum,Tasks)
if deb then return end
deb = true
if TasksNum ~= 0 then
deb = true
local Frame = plr.PlayerGui.ObjNew
local Side = Tasks.Side.Value
if TasksNum == 1 then
for _,v in Frame.Frame.Tasks:GetChildren() do
if not v:IsA("UIListLayout") then
if v:IsA("Frame") then
v.Parent.Parent.Title.Text = Tasks.ObjName.Value
if v.Name ~= "Task"..TasksNum then
v.Visible = false
else
if Tasks.Tasks.Task1.Required.Value == true then
v.TaskName.Text = Tasks.Tasks.Task1.TaskName.Value.." [REQUIRED]"
else
v.TaskName.Text = Tasks.Tasks.Task1.TaskName.Value
end
v.TaskRequired.Text = Tasks.Tasks.Task1.TaskDesc.Value
end
end
end
end
elseif TasksNum >= 2 then
print(1)
frm.Parent.Title.Text = Tasks.ObjName.Value
print(frm.Parent.Title.Text)
for _,v in pairs(Tasks.Tasks:GetChildren()) do
print(2,v)
print(v.Value)
print(TasksNum)
for _,v2 in frm:GetChildren() do
if not v2:IsA("UIListLayout") then
local num = v2.Task.Value
if num > TasksNum or num < 1 then
print(3, v)
v2.Visible = false
continue
end
end
end
for i = 1, TasksNum do
print(i)
--if i ~= TasksNum then
local N = "Task"
local tasko = N..i
print(tasko)
local Actual = Tasks.Tasks:FindFirstChild(tasko)
print(Actual)
local propname = frm:FindFirstChild(tasko)
print(propname)
if Actual.Required.Value == true then
print(4)
propname.TaskName.Text = Actual.TaskName.Value.." [REQUIRED]"
else
print(45)
propname.TaskName.Text = Actual.TaskName.Value
end
print(5)
propname.TaskRequired.Text = Actual.TaskDesc.Value
--end
end
end
end
end
end)```
Before I try to improve it or optamize it, I am uncertain about some variables. like whats tasko or TasksNum, Side(Side Quest?). And I also don’t understand the what the code does sometimes, feels like it does something else. Also I have a question on why do you always manually do Task1.TaskName.Value When you have the for i, v in.
Also the names are just repeating inside the children which confuses on why are the children have the same name as the Parent. Try giving elements easy to know names. like if you stop doing the project and come back after a year, when u see it you may probs forgot what that element was for since there are multiple same names.
I’ll make a system where the labels will update when a/the remoteEvent is fired to update the quest Name & Description and send you the file, tell me if that’s what you are looking for.
Tasko is simply a frame name, combining i (number) and text:
“Task”…i
TasksNum is the number of tasks calculated before firing the remote.
Side is what side the frame will come out.
Also I have a question on why do you always manually do Task1.TaskName.Value When you have the for i, v in .
IDK, it was just weeks since last time I was editing it.
I’ll make a system where the labels will update when a/the remoteEvent is fired to update the quest Name & Description and send you the file, tell me if that’s what you are looking for.
Indeed you do, And Its good as well but You are saying you are only updating the UI and I don’t get why your code looks so complicated for me to understand, maybe its because I am still learning or Its just your code looks messy, I’ll just make something that updates the UI and compare with yours while seeing If thats what you are looking for and see how you could’ve done it If it was.
Sorry again for making you wait, When I opend the previous file I checked if the errors are not working or if they are still there and seems the file wasn’t updated so I had to do some changes again and update it.
But here’s the updated code which has no comments :
local plr = game.Players.LocalPlayer
local tasksUpdatedEvent = game:GetService("ReplicatedStorage"):WaitForChild("TasksUpdated")
local GUI = script.Parent
local tasksHolderFrame = GUI:WaitForChild("TasksFrame"):WaitForChild("TasksHolderFrame")
local debounce = false
------------------------------------------------// Update UI once tasks are changed
tasksUpdatedEvent.OnClientEvent:Connect(function(TotalTasks, Tasks)
if not TotalTasks or not Tasks then warn("Returning due to missing Argument(s)") return end
if typeof(TotalTasks) ~= "number" then TotalTasks = 0 warn("Oops, TotalTasks is not a number. Setting to Default 0") end
if debounce == true then return end
debounce = true
local side
---------------------------------------------------------------
for _, taskFrame in pairs(tasksHolderFrame:GetChildren()) do
if not taskFrame:IsA("Frame") or not taskFrame.Name:match("Task") then continue end
if Tasks:FindFirstChild(taskFrame.Name) == nil then taskFrame.Visible = false continue end
local foundTaskAsInstance = Tasks:FindFirstChild(taskFrame.Name)
if tonumber(string.match(taskFrame.Name, "%d+")) > TotalTasks or TotalTasks < 1 then taskFrame.Visible = false continue end
taskFrame.TaskName.Text = ((foundTaskAsInstance.Required.Value == true) and foundTaskAsInstance.TaskName.Value.." [REQUIRED]") or foundTaskAsInstance.TaskName.Value
taskFrame.TaskDesc.Text = foundTaskAsInstance.TaskDesc.Value
taskFrame:SetAttribute("Task", string.match(taskFrame.Name, "%d+"))
if taskFrame.Visible ~= true then taskFrame.Visible = true end
print(foundTaskAsInstance, "Task Attribute has been set to", taskFrame:GetAttribute("Task"))
end
---------------------------------------------------------------
debounce = false
end)
Turns out I could read your code better when i transfered it to Roblox Studio. I guess I still can’t get out of my comfort zone of viewing codes in a studio.
So Here’s the Game file (66.1 KB) where I tested stuffs. This place is the updated version of my orginal place. Which contains a version of the script with explained details.
Update me if your current problem is resolved using this method or not. Hope it helps !
Oh, ok. also im trying to make a module to make multiple tasks, but im stuck on the same thing again. it just changes everything to the 2nd task.
event.OnClientEvent:Connect(function(Tasks)
local TasksModule = require(Tasks)
if deb then return end
deb = true
local ActualTask
local function Get()
for name, value in pairs(TasksModule) do
if tonumber(name) and tonumber(name) == Progress then
ActualTask = value
return value
else
end
end
end
local GetTask = Get()
if Get() then
frm.Parent.Title.Text = ActualTask.ObjName
local Tasks = ActualTask.Tasks
local TasksNum = 0
for i, v in pairs(Tasks) do
TasksNum += 1
end
print(TasksNum)
for i,v in Tasks do
for i2,v2 in frm:GetChildren() do
if not v2:IsA("UIListLayout") then
for i3 = 1, TasksNum do
local N = "Task"
local tasko = N..i3
local propname = frm:FindFirstChild(tostring(tasko))
print(propname,tasko)
--print(tasko, v2.Name, i2)
local str = string.split(v2.Name, "Task")[2]
str = tonumber(str)
if str > TasksNum or str < 1 then
v2.Visible = false
continue
else
if v.Required then
propname.TaskName.Text = v.Title.." [REQUIRED]"
else
propname.TaskName.Text = v.Title
end
propname.TaskRequired.Text = v.Desc
end
end
end
end
end
end
end)
and here’s the module
local plr = game:GetService("Players").LocalPlayer
local module = {
Side = "Left"; -- Left or Right. Where the ui comes out when you talk to npc
["1"] = {
ObjName = "Mission No.1";
Tasks = {
Task1 = {
Required = true;
Title = "Kill 10 zombies";
Desc = "Find zombies around the map and kill them with your gun";
Task = "Kill"; -- Will be added later
KillWhat = "Zombie"
};
Task2 = {
Required = true;
Title = "Find Suspicious Vent";
Desc = "Locate a vent on a map. Pretty sus to me";
Task = "Touch";
TouchPart = workspace.PartsToTouch.Part;
};
--[[Task3 = {
Required = true;
Title = "???";
Desc = "???";
Task = "Own";
OwnWhat = nil;
};
Task4 = {
Required = true;
Title = "";
Desc = "";
Task = "Kill";
KillWhat = nil;
};
Task5 = {
Required = true;
Title = "";
Desc = "";
Task = "Collect";
CollectWhat = workspace.PartsToClone.Part
};
Task6 = {
Required = true;
Title = "";
Desc = "";
Task = "Own";
OwnWhat = workspace.PartsToClone.Part
};]]
-- ^ delete as many as u want but keep atleast one
};
EnableEndTask = true;
EndTask = {
Task = {
Title = "Go to the Vent";
Desc = "Locate the vent you found befoe lol";
Task = "Touch";
TouchPart = nil;
};
Type = "Cutscene" --Cutscene or Report. Cutscene is obvious and Report requires you to get back to npc.
};
AssignNewTask = false; -- give you another quest
Task = nil;
Rewards = {
["100"] = { -- Everything Completed
};
["75"] = { -- if less than 100 or higher than 75
};
["50"] = { -- if less than 75 or higher than 50
};
["25"] = { -- if less than 50 or higher than 25
};
["0"] = { -- if less than 25 or higher than 0
};
}
}
}
return module
I would still like to check your code, cuz it has unknown functions to me, like “typeof()”
For this line, You can change it to the following, I believe :
tasksUpdatedEvent.OnClientEvent:Connect(function(Tasks, TotalTasks)
if not Tasks or typeof(Tasks) ~= "Instance" then warn("Returning due to missing Argument Tasks [Instance Type Needed]") return end
if not TotalTasks or typeof(TotalTasks) ~= "number" then TotalTasks = 0 warn("Oops, Missing Argument TotalTasks or not a number type. Setting to Default 0") end
This will check if the totalTasks is a number and if it exists or Tasks is an instance or if it exists
ok, so i’ve modified my code a bit. now it looks like that:
local event = game:GetService("ReplicatedStorage").Events:WaitForChild("Tasks")
local plr = game:GetService("Players").LocalPlayer
local deb = false
local frm = plr.PlayerGui:WaitForChild("ObjNew").Frame.Tasks
local Progress = 1
event.OnClientEvent:Connect(function(Tasks)
local TasksModule = require(Tasks)
local ActualTask
local function Get()
for name, value in pairs(TasksModule) do
if tonumber(name) and tonumber(name) == Progress then
ActualTask = value
return value
else
end
end
end
if deb then return end
deb = true
local side
----------------------------------------------------------
local GetTask = Get()
if Get() then
frm.Parent.Title.Text = ActualTask.ObjName
local Tasks1 = ActualTask.Tasks
local TasksNum = 0
for i, v in pairs(Tasks1) do
TasksNum += 1
end
if not Tasks or typeof(Tasks) ~= "Instance" then warn("Return due to missing Argument Tasks [Instance Type Needed]") return end
if not TasksNum or typeof(TasksNum) ~= "number" then TasksNum = 0 warn("Missing Argument TasksNum or not a number type. Setting to Default. Which is 0.") end
for i,v in Tasks1 do
for i2,v2 in frm:GetChildren() do
if not v2:IsA("Frame") or not v2.Name:match("Task") then continue end
--if Tasks1..v2.Name == nil then v2.Visible = false continue end
for i3 = 1, TasksNum do
if tonumber(string.match(v2.Name, "%d+")) > TasksNum or TasksNum < 1 then v2.Visible = false continue end
v2.TaskName.Text = ((v.Required == true) and v.Title.." [REQUIRED]") or v.Title
v2.TaskRequired.Text = v.Desc
v2:SetAttribute("Task",string.match(v2.Name, "%d+"))
if v2.Visible ~= true then v2.Visible = true end
print(v, "Task Attribute has been set to", v2:GetAttribute("Task"))
end
deb = false
end
end
end
end)
Things that is commented i didn’t manage to fix. They output an error. But it still dublicates second task to both frames.
This. Tasks1 is a table and v2.Name is a string. so I can’t combine that.
Though it still prints both tasks, one and two. but it double as much and it does it alot.
Put local TasksModule = require(Tasks) before event.OnClientEvent:Connect(function(Tasks) since you only have to get it once or you’ll ust get it repeatly for no reason even tho the values inside the module probably doesn’t change much.
This is probably cause you have for i3 = 1, TasksNum do inside of for i2,v2 in frm:GetChildren() do or both of those are inside of for i,v in Tasks1 do. and this is probs why theres a duplication.
Did you check the game file? I explained the whole script and i also have a diffrent script as well as some tips. Maybe check it if you haven’t checked. Keep me updated
Edit : Your code feels complicated after a certain area What are you exactly trying to do. Like It seems the UI Updating has some complex requirements or maybe you have the elements in a certain place and you are strugling to work with. If you are having trouble working with the placements of elements try saving the work and working with a diffrent placement and compare the error and success
So I’ve managed to change it up a bit and it took me a while to jsut put module above the event. lol.
local event = game:GetService("ReplicatedStorage").Events:WaitForChild("Tasks")
local plr = game:GetService("Players").LocalPlayer
local deb = false
local frm = plr.PlayerGui:WaitForChild("ObjNew").Frame.Tasks
local Progress = 1
local TasksModule = require(game:GetService("ReplicatedStorage").Modules:WaitForChild("TasksLocated"))
event.OnClientEvent:Connect(function(Tasks,NPCName)
local ActualTask
local function Get()
for index,value in TasksModule do
print(index,value)
if index == NPCName then
local IDKTHEName = value
for name, value2 in pairs(IDKTHEName) do
if tonumber(name) and tonumber(name) == Progress then
ActualTask = value2
return value2
else
end
end
end
end
end
if deb then return end
deb = true
local side
----------------------------------------------------------
local GetTask = Get()
if Get() then
frm.Parent.Title.Text = ActualTask.ObjName
local Tasks1 = ActualTask.Tasks
local TasksNum = 0
for i, v in pairs(Tasks1) do
TasksNum += 1
end
if not Tasks or typeof(Tasks) ~= "Instance" then warn("Return due to missing Argument Tasks [Instance Type Needed]") return end
if not TasksNum or typeof(TasksNum) ~= "number" then TasksNum = 0 warn("Missing Argument TasksNum or not a number type. Setting to Default. Which is 0.") end
for i,v in Tasks1 do
for i2,v2 in frm:GetChildren() do
if not v2:IsA("Frame") or not v2.Name:match("Task") then continue end
--if Tasks1..v2.Name == nil then v2.Visible = false continue end
if tonumber(string.match(v2.Name, "%d+")) > TasksNum or TasksNum < 1 then v2.Visible = false continue end
v2.TaskName.Text = ((v.Required == true) and v.Title.." [REQUIRED]") or v.Title
v2.TaskRequired.Text = v.Desc
v2:SetAttribute("Task",string.match(v2.Name, "%d+"))
if v2.Visible ~= true then v2.Visible = true end
print(v, "Task Attribute has been set to", v2:GetAttribute("Task"))
deb = false
end
end
end
end)
so here’s the code. still dublicates 2nd task to each frame. Tomorow i will make comments for you to understand if you don’t. Just really tried of debugging and trying to fix it all day