What Is This Script Doing?

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.

1 Like

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.

1 Like

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

1 Like

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
1 Like

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)
1 Like

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.

1 Like

After an hours worth of researching this is what I’ve got (6 lines of code :sweat_smile:). 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

Screen Shot 2020-03-30 at 11.04.32 PM

1 Like

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

1 Like