So the script works but how do I connect this to an end screen showing how many they got right?
Add onto the finish function above, its the last thing that runs. Whatever objects you want to change or be displayed, you need to change there property values.
I’m guessing you’d want to change the visibility of the test frame and then change the visibility of a score frame. Possibly compare the result with a set value to determine if they pass. Possibly set a textLabels text preoperty to the score.
Heres a good resource for learning more about UI’s, object properties, connections, functions, and handlers. I think it’d be pretty helpful in figuring out how to manipulate UI’s and objects with scripts.
When I added some code and an end screen the whole script doesn’t work. No errors come out in the output though. Here’s what I have
local questions = { {"Red",{"Red","Orange","Yellow","Green","Blue","Purple"},1}, {"Orange",{"Red","Orange","Yellow","Green","Blue","Purple"},2}, {"Yellow",{"Red","Orange","Yellow","Green","Blue","Purple"},3}, {"Green",{"Red","Orange","Yellow","Green","Blue","Purple"},4}, {"Blue",{"Red","Orange","Yellow","Green","Blue","Purple"},5}, {"Purple",{"Red","Orange","Yellow","Green","Blue","Purple"},6} } local numberCorrect = 0 local NumberOfQuestions = 6 local function finish() local percentCorrect = math.floor(numberCorrect/NumberOfQuestions * 100) game.Players.LocalPlayer.PlayerGui.ColorBlindLockScreenTest.Frame.Visible = false --I ADDED THIS game.Players.LocalPlayer.PlayerGui.ColorBlindLockScreenTest.TestEnd.Visible = true script.TestEnd.Number.text = percentCorrect end local Question, Answers, CorrectAnswer local function changeQuestion() -- load question local TempQuestionNumber = math.random(1,#questions) local QuestionData = questions[TempQuestionNumber] Question, Answers, CorrectAnswer = unpack(QuestionData) -- Set all frames visibility to false local UI_objs=script.Parent.Frame:GetChildren() for i,obj in pairs(UI_objs) do if (obj:IsA('Frame')) then obj.Visible=false end end -- Set the corresponding frame's visibility to true if it exists if script.Parent.Frame:FindFirstChild(Answers[CorrectAnswer]) then script.Parent.Frame:FindFirstChild(Answers[CorrectAnswer]).Visible=true end table.remove(questions,TempQuestionNumber) end local function answer(name) if string.match(name, Answers[CorrectAnswer]) then -- If button name contains answer than mark correct; works within this specific context, may not work for another numberCorrect = numberCorrect+1 end if #questions<=0 then -- If all questions are taken then finish test finish() else changeQuestion() -- Otherwise change question end end -- Connect all buttons to answer function local UI_objs=script.Parent.Frame:GetChildren() for i,obj in pairs(UI_objs) do if (obj:IsA('TextButton')) then obj.MouseButton1Click:Connect(function () answer(obj.Name) end) end end changeQuestion()
The Frame and Text I added (If you have any questions or want to see anything else in more detail please let me know
Thanks for all the help!
Before the frame holding all the questions was named ‘frame’, now its named test. So replace every part that say script.Parent.Frame
with script.Parent.Test
Names be important
This is another method of navigation relative to the script. I see you’ve accessed the other frame from the root players which works too. You do have one error in the newly added statement too, the last line on the finish function. It should look like script.Parent.TestEnd.Number.Text
Otherwise you’re assuming the testEnd frame is under script.
So I want to make another test using decals instead of frames colored in, and 2 of the text buttons will be taken away. Will this script (changed a little) still work for it?
Its probably just going to get a bit more complicated. What I did, was I checked the testFrame for all buttons, and connected all the buttons to change the question. If the button pressed had the color of the correct answer in its name, then it would mark it correct. So I don’t think its best to handle the multiple tests with the same code.
What I recommend doing, is making a frame for each test with two frames ‘Questions’ and ‘Answers’, and name the buttons so that 1 answer will have the same name as one question. You can then use a variation of this script above per test.
Something like:
local questions = {
{"Red",{"Red","Orange","Yellow","Green","Blue","Purple"},1},
{"Orange",{"Red","Orange","Yellow","Green","Blue","Purple"},2},
{"Yellow",{"Red","Orange","Yellow","Green","Blue","Purple"},3},
{"Green",{"Red","Orange","Yellow","Green","Blue","Purple"},4},
{"Blue",{"Red","Orange","Yellow","Green","Blue","Purple"},5},
{"Purple",{"Red","Orange","Yellow","Green","Blue","Purple"},6}
}
local numberCorrect = 0
local NumberOfQuestions = 6
local function finish()
local percentCorrect = math.floor(numberCorrect/NumberOfQuestions * 100)
script.Parent.Test.Test.Visible = false
--I ADDED THIS
end
local Question, Answers, CorrectAnswer
local function changeQuestion()
-- load question
local TempQuestionNumber = math.random(1,#questions)
local QuestionData = questions[TempQuestionNumber]
Question, Answers, CorrectAnswer = unpack(QuestionData)
-- Set all frames visibility to false
local UI_objs=script.Parent.Questions:GetChildren()
for i,obj in pairs(UI_objs) do
if (obj:IsA('Frame')) then
obj.Visible=false
end
end
-- Set the corresponding frame's visibility to true if it exists
if script.Parent.Questions:FindFirstChild(Answers[CorrectAnswer]) then
script.Parent.Questions:FindFirstChild(Answers[CorrectAnswer]).Visible=true
end
table.remove(questions,TempQuestionNumber)
end
local function answer(name)
if name== Answers[CorrectAnswer] then -- If button name equals correct answer
numberCorrect = numberCorrect+1
end
if #questions<=0 then -- If all questions are taken then finish test
finish()
else
changeQuestion() -- Otherwise change question
end
end
-- Connect all buttons to answer function
local UI_objs=script.Parent.Answers:GetChildren()
for i,obj in pairs(UI_objs) do
if (obj:IsA('TextButton')) then
obj.MouseButton1Click:Connect(function () answer(obj.Name) end)
end
end
changeQuestion()
So the frames or UI imagelabels you want displayed will be in Questions, and the buttons will be in answers. You can share the same end test between all tests too, or you can make each test have its on endTest frame. In any case, this will keep the script managable, and organize your UI. You can then use a seperate UI to switch between the tests.
Let me know if you have any questions
I set it up like this is it okay?
Also for the first test I made with the colors, the test won’t show once you take it. Is there something in the script that prevents the player from taking it multiple times?
Yeah, there is. The script starts without a connection, so a button doesn’t activate the test. And once you finish a question it removes the question form the table. I modeled the script relatively similar to what you had before. If you want to restart the test there should be a new connection with some button that reactivates the test.
something like, and change the table name at the beginning of the script to const_questions, and add questions=const_questions
right below the table.
local function startTest()
questions=const_questions
numberCorrect=0
changeQuestion()
end
Do you mean something like a restart button? A platform that the player steps on activates it, so I just want it so when the player steps on the platform again, it will activate it again.
Kay, you want a connection similar to this then. Or you can also use a connection script in the part that sends a signal to the player. But I think you’ll find this easier.
local players=game:GetService('Players')
local player=players.LocalPlayer
player.CharacterAdded:Connect(function (character)
local humanoid=character:WaitForChild('Humanoid')
humanoid.Touched:Connect(function (part)
if part.Name=='Test Platform or whatever restarts it' then
startTest()
end
end)
end)
Does this go into starter gui? Also I didn’t define startTest
local startTest = (what do I define it as?)
I’m keeping everything under the scope of one script, so same script as before. When I accessed startTest I did it with (), so that means startTest should be a function. And by its name, it purpose should be to start a new test. Since thats what you want to happen when a part of a certain name is touched. I outlined what a function for that would look like above to.
Start test is underlined in blue, also I’m not sure if I’m supposed to add it at the very top or bottom. Nothing comes out in the output, but it doesn’t work.
local players=game:GetService('Players')
local player=players.LocalPlayer
player.CharacterAdded:Connect(function (character)
local humanoid=character:WaitForChild('Humanoid')
humanoid.Touched:Connect(function (part)
if part.Name=='CBBrick' then
startTest()
end
end)
end)
local questions = {
{"Red",{"Red","Orange","Yellow","Green","Blue","Purple"},1},
{"Orange",{"Red","Orange","Yellow","Green","Blue","Purple"},2},
{"Yellow",{"Red","Orange","Yellow","Green","Blue","Purple"},3},
{"Green",{"Red","Orange","Yellow","Green","Blue","Purple"},4},
{"Blue",{"Red","Orange","Yellow","Green","Blue","Purple"},5},
{"Purple",{"Red","Orange","Yellow","Green","Blue","Purple"},6}
}
local numberCorrect = 0
local NumberOfQuestions = 6
local function finish()
local percentCorrect = math.floor(numberCorrect/NumberOfQuestions * 100)
--DISABLES THE GUI
game.Players.LocalPlayer.PlayerGui.ColorBlindLockScreenTest.Frame.Visible = false
game.Players.LocalPlayer.PlayerGui.ColorBlindLockScreenTest.TestEnd.Visible = true
game.Players.LocalPlayer.PlayerGui.ColorBlindLockScreenTest.TestEnd.Number.Text = percentCorrect
end
local Question, Answers, CorrectAnswer
local function changeQuestion()
-- load question
local TempQuestionNumber = math.random(1,#questions)
local QuestionData = questions[TempQuestionNumber]
Question, Answers, CorrectAnswer = unpack(QuestionData)
-- Set all frames visibility to false
local UI_objs=script.Parent.Frame:GetChildren()
for i,obj in pairs(UI_objs) do
if (obj:IsA('Frame')) then
obj.Visible=false
end
end
-- Set the corresponding frame's visibility to true if it exists
if script.Parent.Frame:FindFirstChild(Answers[CorrectAnswer]) then
script.Parent.Frame:FindFirstChild(Answers[CorrectAnswer]).Visible=true
end
table.remove(questions,TempQuestionNumber)
end
local function answer(name)
if string.match(name, Answers[CorrectAnswer]) then -- If button name contains answer than mark correct; works within this specific context, may not work for another
numberCorrect = numberCorrect+1
end
if #questions<=0 then -- If all questions are taken then finish test
finish()
else
changeQuestion() -- Otherwise change question
end
end
-- Connect all buttons to answer function
local UI_objs=script.Parent.Frame:GetChildren()
for i,obj in pairs(UI_objs) do
if (obj:IsA('TextButton')) then
obj.MouseButton1Click:Connect(function () answer(obj.Name) end)
end
end
changeQuestion()
not sure what you mean by underlined in blue, but at the top heres whats happening.
When your roblox player gets a new character, so your character spawns, it will start listening to every time the player touches an object called ‘CBBrick’. When that happens it tries to call the function startTest(), which should be a function that starts the test. But you don’t seem to have that function. Also put all of this at the end, since code only knows things named above it.
Wouldn’t start test be the same as changeQuestion()? Correct me if I’m wrong.
local function changeQuestion() -- load question local TempQuestionNumber = math.random(1,#questions) local QuestionData = questions[TempQuestionNumber] Question, Answers, CorrectAnswer = unpack(QuestionData) -- Set all frames visibility to false local UI_objs=script.Parent.Frame:GetChildren() for i,obj in pairs(UI_objs) do if (obj:IsA('Frame')) then obj.Visible=false end end
Actually its very close, before using the part to start the test, changeQuestion() was used to change the test to the first question. But its also used to change the question; so if this was connected directly to the part a character touches then the player might change the question without answering. You also want a function to reset the data table every time the test starts, since the data is removed when you change questions.
After an hours worth of researching this is what I’ve got (6 lines of code ). Not sure how many mistakes I’ve made probably a lot, please tell me what I’ve done wrong. Thanks.
local questions = {
{"Red",{"Red","Orange","Yellow","Green","Blue","Purple"},1},
{"Orange",{"Red","Orange","Yellow","Green","Blue","Purple"},2},
{"Yellow",{"Red","Orange","Yellow","Green","Blue","Purple"},3},
{"Green",{"Red","Orange","Yellow","Green","Blue","Purple"},4},
{"Blue",{"Red","Orange","Yellow","Green","Blue","Purple"},5},
{"Purple",{"Red","Orange","Yellow","Green","Blue","Purple"},6}
}
--Reset The Data Table
local function resetData()
table.insert(questions,questions)
end
local numberCorrect = 0
local NumberOfQuestions = 6
local function finish()
local percentCorrect = math.floor(numberCorrect/NumberOfQuestions * 100)
--Disables The Gui
game.Players.LocalPlayer.PlayerGui.ColorBlindLockScreenTest.Frame.Visible = false
game.Players.LocalPlayer.PlayerGui.ColorBlindLockScreenTest.TestEnd.Visible = true
game.Players.LocalPlayer.PlayerGui.ColorBlindLockScreenTest.TestEnd.Number.Text = percentCorrect
end
local Question, Answers, CorrectAnswer
local function changeQuestion()
-- load question
local TempQuestionNumber = math.random(1,#questions)
local QuestionData = questions[TempQuestionNumber]
Question, Answers, CorrectAnswer = unpack(QuestionData)
-- Set all frames visibility to false
local UI_objs=script.Parent.Frame:GetChildren()
for i,obj in pairs(UI_objs) do
if (obj:IsA('Frame')) then
obj.Visible=false
end
end
-- Set the corresponding frame's visibility to true if it exists
if script.Parent.Frame:FindFirstChild(Answers[CorrectAnswer]) then
script.Parent.Frame:FindFirstChild(Answers[CorrectAnswer]).Visible=true
end
table.remove(questions,TempQuestionNumber)
end
local function answer(name)
if string.match(name, Answers[CorrectAnswer]) then -- If button name contains answer than mark correct; works within this specific context, may not work for another
numberCorrect = numberCorrect+1
end
if #questions<=0 then -- If all questions are taken then finish test
finish()
else
changeQuestion() -- Otherwise change question
end
end
-- Connect all buttons to answer function
local UI_objs=script.Parent.Frame:GetChildren()
for i,obj in pairs(UI_objs) do
if (obj:IsA('TextButton')) then
obj.MouseButton1Click:Connect(function () answer(obj.Name) end)
end
end
changeQuestion()
--Starts the test
local function startTest()
resetData()
end
local players=game:GetService('Players')
local player=players.LocalPlayer
player.CharacterAdded:Connect(function (character)
local humanoid=character:WaitForChild('Humanoid')
humanoid.Touched:Connect(function (part)
if part.Name=='CBBrick' then
startTest()
end
end)
end)
lol sorry, thats not gonna work out. You can’t really restore data into a table from the same table.
You want to have a table that doesn’t change and one that does.
Here’s the code put altogether I think your looking for, check out the comments to try and understand how the code works.
Code
local players=game:GetService('Players')
local player=players.LocalPlayer
local questions = { -- Table used to verify which questions are correct
{"Red",{"Red","Orange","Yellow","Green","Blue","Purple"},1},
{"Orange",{"Red","Orange","Yellow","Green","Blue","Purple"},2},
{"Yellow",{"Red","Orange","Yellow","Green","Blue","Purple"},3},
{"Green",{"Red","Orange","Yellow","Green","Blue","Purple"},4},
{"Blue",{"Red","Orange","Yellow","Green","Blue","Purple"},5},
{"Purple",{"Red","Orange","Yellow","Green","Blue","Purple"},6}
}
local current_questions={}
local numberCorrect = 0
local NumberOfQuestions = 6
local testInSession=false
local function finishTest()
-- Calculate number correct
local percentCorrect = math.floor(numberCorrect/NumberOfQuestions * 100)
--Disables The Gui
script.Parent.Questions.Visible = false
script.Parent.Questions.Answers = false
script.Parent.TestEnd.Visible = true
game.Players.LocalPlayer.PlayerGui.ColorBlindLockScreenTest.TestEnd.Number.Text = percentCorrect
wait(5) -- Time to allow player to step off part, before allowing the test to begin again
testInSession=false
end
local Question, Answers, CorrectAnswer
local function changeQuestion()
-- load question
local TempQuestionNumber = math.random(1,#current_questions)
local QuestionData = questions[TempQuestionNumber]
Question, Answers, CorrectAnswer = unpack(QuestionData) -- update these variables with the newest question
-- Set all frames visibility to false
local UI_objs=script.Parent.Questions:GetChildren()
for i,obj in pairs(UI_objs) do
obj.Visible=false
end
-- Set the corresponding question ui obj visibility to true if it exists
if script.Parent.Questions:FindFirstChild(Answers[CorrectAnswer]) then
script.Parent.Questions:FindFirstChild(Answers[CorrectAnswer]).Visible=true
end
table.remove(current_questions,TempQuestionNumber)
end
local function answer(name) -- The answer function has the name of the button pressed
if name==Answers[CorrectAnswer] then -- if that name is equal to the correct answer then add 1 to the number correct
numberCorrect = numberCorrect+1
end
if #current_questions<=0 then -- If all questions are taken then finish test
finishTest()
else
changeQuestion() -- Otherwise change question
end
end
--Starts the test
local function startTest()
-- Enable the UI
script.Parent.Questions.Visible=true
script.Parent.Answers.Visible=true
script.Parent.TestEnd.Visible=false
current_questions={} -- Ensure current questions is empty
for index,value in pairs(questions) do -- For every question
current_questions[index]=value -- Insert it into the current_questions table
end
-- This clones the question table into a new table
numberCorrect=0 -- Reset number correct to 0
testInSession=true -- Set a debounce variable so that the test will not be restarted unless it was finished
changeQuestion() -- Start test by popping a question off the table
end
player.CharacterAdded:Connect(function (character) -- When our character spawns
local humanoid=character:WaitForChild('Humanoid') -- Get the humanoid when its ready
humanoid.Touched:Connect(function (part) -- If the character touches something then pass 'part' into this function
if part.Name=='CBBrick' and testInSession==false then -- Check part name and if player is currently not taking this test
startTest()
end
end)
end)
-- Connect all buttons to answer function
local UI_objs=script.Parent.Answers:GetChildren() -- Get all the answers
for i,obj in pairs(UI_objs) do -- Go through them
if (obj:IsA('TextButton')) then -- Check if there a button
obj.MouseButton1Click:Connect(function () answer(obj.Name) end) -- Connect the button to the answer function; so when the buttons are clicked they call the answer function
end
end
You also want to change the UI structure, because the buttons shouldn’t have the same name as the answers in the same frame. This will confuse the script looking for objects of a certain name, because two exist.
So this pairs well with the code above
What does upvalue answer mean? I keep getting it as an error. Also it’s saying that there’s something wrong with line 115, but it doesn’t say what’s wrong. I went to look, but I couldn’t find anything wrong with it.
11:08:28.139 - Script 'Players.Play_MazeOfHeck.PlayerGui.ColorBlindLockScreenTest.TestScript', Line 64 - upvalue answer 11:08:28.140 - Script 'Players.Play_MazeOfHeck.PlayerGui.ColorBlindLockScreenTest.TestScript', Line 115
Picture Of My Setup
Thanks for taking your own time out of your day to help me, I hope you have a good rest of your day.
Sir.Play_MazeOfHeck