How to make questions & answers random in my script C#?
Hello Unity Answers,
I want to make my questions and answers random because at the moment the question is the same one when the player collides into the cube and the answers are in the same place as well.
Is there away to make it change randomly upon collision with a cube.
So for example, if the player runs out of time and is sent back to the start, I would like a new question to appear on screen, not "What year did Ebola begin?"
Also the answer is 1976, which is set in the top left button, can I place this somewhere else?
Any ideas/help/suggestions would be much appreciated.
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Question1 : MonoBehaviour {
private Rect windowRect = new Rect (500, 100, 400, 200); //Window size
public bool question1;
private int count;
public Text countText;
private bool showTimer = true;
private float Timer = 10f;
void start()
{
count = 0;
SetCountText ();
}
void FixedUpdate(){
if (showTimer == true) {
Timer -= Time.deltaTime;
}
if (Timer <= 0f) {
showTimer = false;
Timer = 10f;
Destroy (this.gameObject);
Application.LoadLevel (Application.loadedLevel);
}
}
void OnGUI(){
{
windowRect = GUI.Window (0, windowRect, WindowFunction, "Ebola Quiz Island"); //window on screen
}
}
void WindowFunction (int windowID)
{
// Draw any Controls inside the window here
GUI.Label (new Rect (30, 25, 200, 50), " What year did Ebola begin?"); // Question
if (GUI.Button (new Rect (20, 100, 100, 30), "1976")) // Correct Answer
{
Destroy (this.gameObject);
count = count + 1;
SetCountText ();
}
if (GUI.Button (new Rect (280, 100, 100, 30), "1986")) //Wrong answer
{
Destroy (this.gameObject);
Application.LoadLevel(Application.loadedLevel);
}
if (GUI.Button (new Rect (20, 150, 100, 30), "1996")) // wrong answer
{
Destroy (this.gameObject);
Application.LoadLevel(Application.loadedLevel);
}
if (GUI.Button (new Rect (280, 150, 100, 30), "1966")) // wrong answer
{
Destroy (this.gameObject);
Application.LoadLevel(Application.loadedLevel);
}
if (showTimer == true)
{
GUI.Label (new Rect (300, 25, 200, 50), "Timer: " + Timer.ToString ("F0"));
}
}
void SetCountText()
{
countText.text = "Score: " + count.ToString ();
}
}
Answer by equus_ligneus · Apr 10, 2015 at 11:53 PM
The easiest way to implement this is to create instances of a question class (preferrably not in a scene but in the project folder) which hold the question and the possible answers and let them handle randomizing the button positions.
using UnityEngine;
using System.Collections.Generic;
// A Question
public class MyQuestion : ScriptableObject {
// the question
public string question;
// the different answers (answer[0] is right answer by default)
public string[] answers;
// the order, in which answers are displayed
private int[] m_order;
//This does not work outside the Editor
#if UNITY_EDITOR
// Create Questions from Folder Context Menu
[UnityEditor.MenuItem("Assets/Create/Question")]
public static void CreateQuestion()
{
string resourcePath = "Assets/Resources/Questions";
// makes sure you have a directory to save your question to.
if (!System.IO.Directory.Exists(Application.dataPath + "/Resources"))
{
UnityEditor.AssetDatabase.CreateFolder("Assets", "Resources");
}
if (!System.IO.Directory.Exists(Application.dataPath + "/Resources/Questions"))
{
UnityEditor.AssetDatabase.CreateFolder("Assets/Resources", "Questions");
}
// create question
MyQuestion myQuestion = CreateInstance<MyQuestion>();
// name question
int questions = UnityEditor.AssetDatabase.FindAssets("", new string[1]{resourcePath}).Length;
myQuestion.name = "Question_" + questions;
// save question to project folder
UnityEditor.AssetDatabase.CreateAsset(myQuestion, resourcePath + "/" + myQuestion.name + ".asset");
}
#endif
public void OnEnable()
{
if (question == null)
{
question = "";
}
if (answers == null)
{
answers = new string[4] { "", "", "", "" };
}
// Prevents exceptions in OnGUI if you forget to call RandomizeAnswers()
m_order = new int[answers.Length];
for (int i = 0; i < m_order.Length; ++i)
{
m_order[i] = i;
}
}
// Randomizes the order in which answers are presented
public void RandomizeAnswers()
{
System.Random random = new System.Random();
List<int> order = new List<int>();
// get indices
for (int i = 0; i < answers.Length; ++i)
{
order.Add(i);
}
m_order = new int[answers.Length];
int index = 0;
// shuffle indices
while (order.Count > 0)
{
int index2 = random.Next(order.Count);
m_order[index] = order[index2];
order.RemoveAt(index2);
++index;
}
}
/* Your Question display function
* returns true (right answer), false (wrong answer) or null (nothing chosen) */
public bool? ShowQuestion(Rect _area)
{
// bool that can be true, false or null. ? makes any struct nullable
bool? result = null;
// just a simple layout
GUILayout.BeginArea(_area);
// display question
GUILayout.Label(question);
for (int i = 0; i < answers.Length; ++i)
{
// display buttons in random order
if (GUILayout.Button(answers[m_order[i]]))
{
if (m_order[i] == 0) // right choice
{
result = true;
}
else // wrong choice
{
result = false;
}
}
}
GUILayout.EndArea();
return result;
}
}
(You can save instances of classes that inherit from ScriptableObject as assets in in your project)
Now to randomize the questions themselves, one way to go is use a central question pool that holds all questions and ask for new question every time the question trigger is entered.
using UnityEngine;
using System.Collections;
// Singleton for managing the question pool
public class MyQuestionPool {
// static instance
private static MyQuestionPool m_questionPool = null;
// all questions
private MyQuestion[] m_questions = null;
private System.Random m_random = null;
private MyQuestionPool()
{
m_random = new System.Random();
InitQuestions();
}
// Loads questions
private void InitQuestions()
{
/* Resources.Load looks inside the Assets/Resources-folder
* full path is Assets/Resources/Questions */
m_questions = Resources.LoadAll<MyQuestion>("Questions");
}
// Gets the question pool
public static MyQuestionPool Instance
{
get
{
if (m_questionPool == null)
{
m_questionPool = new MyQuestionPool();
}
return m_questionPool;
}
}
// Gets a random question
public MyQuestion GetQuestion()
{
if (m_questions != null && m_questions.Length > 0)
{
int index = m_random.Next(m_questions.Length);
m_questions[index].RandomizeAnswers();
return m_questions[index];
}
return null;
}
}
At last, the trigger:
using UnityEngine;
using System.Collections;
// A question trigger
public class MyQuestionTrigger : MonoBehaviour {
// current question
private MyQuestion m_question = null;
public void OnGUI()
{
// Display Question
if (m_question)
{
bool? result = m_question.ShowQuestion(new Rect(Screen.width / 2 - 200, Screen.height / 2 - 200, 400, 400));
if (result == null)
{
// no answer, wait...
return;
}
else if (result == true)
{
// right answer given
}
else
{
// wrong answer given
}
// discard question
m_question = null;
}
}
public void OnTriggerEnter(Collider _col)
{
// Get Question
m_question = MyQuestionPool.Instance.GetQuestion();
}
}
With this you can add questions until you run out of RAM, Array-Indices or ideas for new questions. You can edit them in your inspector. Just do not delete questions or it will screw with the way new questions are named.
I should add that since $$anonymous$$yQuestionPool is not a $$anonymous$$onoBehaviour it will not be destroyed during level loads.
Hi. im currently working on a similar project. and still a newbie. so may i ask how do u implement these scripts?
Out of the three scripts, only $$anonymous$$yQuestionTrigger needs to be put on a GameObject. An instance of $$anonymous$$yQuestion can be created like a new script (right-clicking in the Project-window >"Question").
At runtime, when you run into a $$anonymous$$yQuestionTrigger, the trigger asks a static $$anonymous$$yQuestionPool instance to get a question. If the $$anonymous$$yQuestionPool instance has not been created, it will create itself and load all $$anonymous$$yQuestions from the Resources-folder. Then it will return a random question, which the trigger will display until a) the question has been answered (right or wrong does not matter) or b) the player runs into the same trigger again. I hope I could help.
Your answer
Follow this Question
Related Questions
Loading Game Crash 1 Answer
Multiplayer Hiding Layer just for Local Player 0 Answers
Beginner trying to set up random variable for game + and then some. 2 Answers
Random Generator Instantiate Tiles C# = PLEASE HELP = 0 Answers
How to instantiate (MonoBehaviour) script multiple times and call void? 1 Answer