前言
Unity答题系统,可适配单选或多选
偶然看到一种使用二进制表示选项的方法,让我茅塞顿开,没想到还能有这样的思路,所以拿出来分享一下
运行示例
方法思路
我这里答题系统做了一个简单的案例,思路主要是以下几点
- 通过读取StreamingAssets文件内的xml文件来获取题库,题库内存储的数据我会在下面介绍,后期打包后也可以修改题库
- 然后就是自定义类,存储获取到的题库
- 最后通过读取题库中的存储的十进制数,将十进制数转化为二进制,然后对照ASCII码表来匹配正确答案
获取题库方法
void GetData()
{
if (File.Exists(path))
{
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(path);
XmlNodeList nodeList = xmldoc.SelectSingleNode("Root").ChildNodes;
topic_Count = nodeList.Count;
foreach (XmlElement xel in nodeList) //36
{
int order = int.Parse(xel.GetAttribute("id"));
Data data = new Data();
foreach (XmlElement xe2 in xel.ChildNodes)
{
int j = 0;
foreach (XmlElement xe3 in xe2.ChildNodes)
{
switch (j)
{
case 0:
{
data.question.key = int.Parse(xe3.GetAttribute("key"));
data.question.title = xe3.InnerText;
}
break;
default:
data.question.answer.Add(xe3.InnerText);
data.question.isAnswer = new bool[data.question.answer.Count];
break;
}
j++;
}
}
QuestionBanks.Add(order, data);
}
}
}
xml题库文件配置如下
自定义类
public class Data
{
public int order;
public Question question = new Question();
}
public class Question
{
public string title;
public List<string> answer = new List<string>();
public bool[] isAnswer;
public int key;
}
public enum BtnState
{
normal,
check,
complete
}
答题卡部分
void ShowAnswerCard()
{
if (topic_Count > 0)
{
Debug.Log(topic_Count);
for (int i = 1; i <= topic_Count; i++)
{
GameObject obj = Instantiate(card);
obj.name = i.ToString();
obj.transform.SetParent(cardContent);
obj.GetComponentInChildren<Text>().text = i.ToString();
//存入答题卡列表
card_btn.Add(obj.GetComponent<Button>());
}
}
}
转化题库key值为选项
public static string NumToABC(int num)
{
string str = Convert.ToString(num, 2);
string strResult = null;
for (int i = str.Length - 1, j = 0; i >= 0; i--)
{
if (str.Length >= i)
{
string c = str.Substring(str.Length - 1, 1);
//转化Ascii码
if (c != "0")
{
char a = (char)(i + 65);
if (j == 0)
{
strResult += a;
}
else
{
strResult += "," + a;
}
j++;
}
}
}
if (strResult == null)
{
return "(未选择)";
}
else
{
return strResult;//返回转化后的选项
}
}
更新题库内容
private void InitateTopic(int order)
{
//进入之后先判断是否有选项-有选项匹配选项内容,无选项默认
// up down 切换 直接选择切换
if (order == 0 || order > QuestionBanks.Count)
{
Debug.Log("序列号有误" + order + " " + QuestionBanks.Count);
return;
}
if (GetComponent<ToggleGroup>())
{
Destroy(GetComponent<ToggleGroup>());
}
data = QuestionBanks[order];
int letterCount = Regex.Matches(NumToABC(data.question.key), "[a-zA-Z]").Count;
bool tog_IsOn = false;
for (int i = 0; i < answer_Tog.Length; i++)
{
answer_Tog[i].group = null;
answer_Tog[i].isOn = data.question.isAnswer[i];
answer_Tog[i].interactable = false;
answer_Tog[i].GetComponentInChildren<Text>().text = data.question.answer[i];
if (answer_Tog[i].isOn)
{
Debug.Log("有选项");
tog_IsOn = true;
}
}
if (tog_IsOn)
{
Debug.Log("有选项");
ensure_Btn.interactable = false;
if (selectedButton.image.color != selectedButton.colors.pressedColor)
{
selectedButton.image.color = selectedButton.colors.normalColor;
}
card_btn[currentOrder - 1].image.color = card_btn[currentOrder - 1].colors.pressedColor;
selectedButton = card_btn[currentOrder - 1];
if (GetComponent<ToggleGroup>())
{
Destroy(GetComponent<ToggleGroup>());
}
if (letterCount <= 1)
{
for (int i = 0; i < answer_Tog.Length; i++)
{
answer_Tog[i].isOn = data.question.isAnswer[i];
}
title_Txt.text = "<color=#FFFFFF00>XX</color>" +order+"."+ data.question.title+"(单选题)";
}
else
{
Debug.Log("多选");
for (int i = 0; i < answer_Tog.Length; i++)
{
answer_Tog[i].isOn = data.question.isAnswer[i];
}
title_Txt.text = "<color=#FFFFFF00>XX</color>" + order + "." + data.question.title+"(多选题)";
}
}
else
{
// Debug.Log("无选项"+selectedButton.name+" "+currentOrder);
ensure_Btn.interactable = true;
if (selectedButton.image.color!= selectedButton.colors.pressedColor)
{
selectedButton.image.color =selectedButton.colors.normalColor;
}
card_btn[currentOrder - 1].image.color = card_btn[currentOrder - 1].colors.highlightedColor;
selectedButton = card_btn[currentOrder - 1];
if (letterCount <= 1)
{
if (GetComponent<ToggleGroup>() == null)
{
gameObject.AddComponent<ToggleGroup>();
}
for (int i = 0; i < answer_Tog.Length; i++)
{
answer_Tog[i].group=GetComponent<ToggleGroup>();
answer_Tog[i].isOn = false;
answer_Tog[i].interactable = true;
}
GetComponent<ToggleGroup>().allowSwitchOff = true;
title_Txt.text = "<color=#FFFFFF00>XX</color>" + order + "." + data.question.title+ "(单选题)";
}
else
{
if (GetComponent<ToggleGroup>())
{
Destroy(GetComponent<ToggleGroup>());
}
for (int i = 0; i < answer_Tog.Length; i++)
{
answer_Tog[i].interactable = true;
answer_Tog[i].isOn = false;
}
title_Txt.text = "<color=#FFFFFF00>XX</color>" + order + "." + data.question.title + "(多选题)";
}
//存入四个选项状态
ensure_Btn.onClick.AddListener(() =>
{
ensure_Btn.interactable = false;
if (GetComponent<ToggleGroup>())
{
Destroy(GetComponent<ToggleGroup>());
}
AnswerClose(data);
string key = string.Empty;
key = string.Format("{0:D4}", int.Parse(Convert.ToString(data.question.key, 2)));
for (int i = 0; i < data.question.answer.Count; i++)
{
if (key.Substring(3 - i, 1) == "1" && !answer_Tog[i].isOn)
{
Debug.Log("选择错误");
return;
}
else if (key.Substring(3 - i, 1) == "0" && answer_Tog[i].isOn)
{
Debug.Log("选择错误");
return;
}
}
Debug.Log("选择正确");
});
}
}
存储选项方法
void AnswerClose(Data data)
{
for (int i = 0; i < answer_Tog.Length; i++)
{
answer_Tog[i].interactable = false;
data.question.isAnswer[i] = answer_Tog[i].isOn;
ensure_Btn.interactable = false;
if (answer_Tog[i].isOn)
{
Debug.Log("有选择");
card_btn[currentOrder - 1].image.color = card_btn[currentOrder - 1].colors.pressedColor;
selectedButton = card_btn[currentOrder - 1];
}
}
}
private void Start()
{
order = int.Parse(GetComponentInChildren<Text>().text);
btn.onClick.AddListener(() =>
{
QuestionBank.Instance.currentOrder = order;
Debug.Log(QuestionBank.Instance.selectedButton.name);
if (QuestionBank.Instance.selectedButton.GetComponent<CardBtn>().btnState!=BtnState.complete)
{
selectBtn = QuestionBank.Instance.selectedButton;
QuestionBank.Instance.selectedButton.image.color = selectBtn.colors.normalColor;
}
QuestionBank.Instance.selectedButton = btn;
QuestionBank.Instance.RestTopic();
});
}
总结
一个简单的demo,还有很多可以扩展的空间,比如通过excel类型的题库读取,或者是多扩展出填空题之类的