目录导航
1、3.0版本的答题系统同样延续了前两个版本一样的方式,题库信息存储在xml文档中,通过www的形式加载并解析,构建题目数据类。3.0版本增加了一个管理题目选项的数据结构,修复了1.0版本中题目选择后点击下一题或上一题已经选择的题目信息不保存的bug,这次可以通过题目管理类QuestionNumber来维护这些数据,让题目初始化的时候全部创建好并缓存到该类的数据结构中,需要的时候直接显示或隐藏即可,避免了频繁的实例化题目对象,浪费内存。
2、3.0版本保存了上一题、下一题和交卷功能,同时增加了左侧题目导航栏功能,可以选答任一题目;增加了正误标识图功能,提交后显示答题结果:选对的标识图为绿色,选错或未选的为红色。
3、题库xml文档节点信息如下:




以上预支体工作完成之后可以将其从Hierarchy视图里删除或隐藏掉。

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Xml;
public class Question : MonoBehaviour
{
/// <summary>
/// 左边题目导航栏,用作题目管理
/// </summary>
public class QuestionNumber
{
/// <summary>
/// 题目对应的问题和选项
/// </summary>
public class QuestionContent
{
private QuestionNumber number;
private List<ToggleItem> options;
public QuestionContent(QuestionNumber _number, List<ToggleItem> tog)
{
number = _number;
options = tog;
}
/// <summary>
/// 控制选项的显隐
/// </summary>
/// <param name="value"></param>
public void SetVisible(bool value)
{
foreach (ToggleItem item in options)
{
item.gameObject.SetActive(value);
}
}
}
private List<QuestionContent> cacheQuestions = new List<QuestionContent>();
private QuestionBtnItem BtnItem;
private GameObject text;
public QuestionNumber(QuestionBtnItem btnItem, GameObject tex)
{
BtnItem = btnItem;
text = tex;
}
/// <summary>
/// 控制题目显隐
/// </summary>
/// <param name="value"></param>
public void SetVisible(bool value)
{
text.SetActive(value);
}
/// <summary>
/// 添加题目到题目缓存列表
/// </summary>
/// <param name="question"></param>
public void AddQuestion(QuestionContent question)
{
cacheQuestions.Add(question);
}
public void RemoveQuestion(QuestionContent question)
{
cacheQuestions.Remove(question);
}
}
public static Question Instance;//脚本单例,提供给外部访问
public Button previousBtn;//上一题按钮
public Button nextBtn;//下一题按钮
public Button closeBtn;//关闭按钮
public Button submitBtn;//提交按钮
public Transform questionItem;//选项toggle父物体
public Transform btnContent;//题目导航父物体
public Transform tagContent;//正误标识父物体
public Transform contentText;//题目文本父物体
private string questionPath;//题库xml文件路径
private int questionCount = 0;//当前题目序号
private ToggleGroup questionGroup;
private ToggleGroup questionItemGroup;
//private List<ToggleItem> _AnswerData;//
[HideInInspector]
public List<QuestionBtnItem> _QuesitonBtnItemDatas;//左侧题目列表数据
List<Image> tagImages = new List<Image>();//正误标识图
private List<QuestionNumber> mQuestionlist = new List<QuestionNumber>();//左侧题目列表
private List<QuestionNumber.QuestionContent> mContenList = new List<QuestionNumber.QuestionContent>();//题目选项列表
QuestionDatas questionData;//题库数据
int questionTotalScore = 0;//总分
private void Awake()
{
Instance = this;
}
private void Start()
{
questionPath = "file://" + Application.dataPath + "/data/Question/Question.xml";
Init();
}
/// <summary>
/// 初始化
/// </summary>
private void Init()
{
questionGroup = questionItem.GetComponent<ToggleGroup>();
questionItemGroup = btnContent.GetComponent<ToggleGroup>();
//_AnswerData = new List<ToggleItem>();
StartCoroutine(LoadQuestion(questionPath));
closeBtn.onClick.AddListener(delegate
{
gameObject.SetActive(false);
});
previousBtn.onClick.AddListener(PreviousClick);
submitBtn.onClick.AddListener(SubmitClick);
nextBtn.onClick.AddListener(NextClick);
}
/// <summary>
/// 加载题库协程
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
IEnumerator LoadQuestion(string path)
{
yield return null;
using (WWW www = new WWW(path))
{
yield return www;
XmlDocument doc = new XmlDocument();
doc.LoadXml(www.text);
questionData = new QuestionDatas(doc.FirstChild);
}
InitQuestionPanel(questionData);
}
/// <summary>
/// 初始化答题面板
/// </summary>
/// <param name="questionData"></param>
private void InitQuestionPanel(QuestionDatas questionData)
{
_QuesitonBtnItemDatas = new List<QuestionBtnItem>();
for (int i = 0; i < questionData.questionItemDatas.Count; i++)
{
GameObject text = GameObject.Instantiate(Resources.Load<GameObject>("Question/Text"));//实例化题目
text.GetComponent<Text>().text = questionData.questionItemDatas[i].Problem;
text.transform.SetParent(contentText);
text.transform.localScale = Vector3.one;
QuestionBtnItem btnItem = GameObject.Instantiate(Resources.Load<QuestionBtnItem>("Question/QuestionTog"));//实例化左侧题目导航
Image tagImg = GameObject.Instantiate(Resources.Load<Image>("Question/tagImage"));//实例化下方正误标识图
tagImg.gameObject.GetComponentInChildren<Text>().text = (i + 1).ToString();
tagImg.transform.SetParent(tagContent);
tagImg.transform.localScale = Vector3.one;
tagImages.Add(tagImg);
_QuesitonBtnItemDatas.Add(btnItem);
btnItem.Init(i, (id) =>
{
CallBackId(id);
});
QuestionNumber tmpQuestion = new QuestionNumber(btnItem, text);//初始化题目对象
tmpQuestion.SetVisible(false);
mQuestionlist.Add(tmpQuestion);
btnItem.thisBtn.group = questionItemGroup;
btnItem.transform.SetParent(btnContent);
btnItem.transform.localScale = Vector3.one;
CreateQuestionItem(questionData.questionItemDatas[i]);
}
mQuestionlist[questionCount].SetVisible(true);//初始显示第一题
mContenList[questionCount].SetVisible(true);
}
/// <summary>
/// 点击左侧题目回调函数
/// </summary>
/// <param name="id"></param>
private void CallBackId(int id)
{
if (id != questionCount)
{
mQuestionlist[questionCount].SetVisible(false);//上一道题目隐藏
mContenList[questionCount].SetVisible(false);
questionCount = id;
mQuestionlist[questionCount].SetVisible(true);//显示当前题目内容
mContenList[questionCount].SetVisible(true);
}
}
/// <summary>
/// 创建题目
/// </summary>
/// <param name="questionItemData"></param>
private void CreateQuestionItem(QuestionItemDatas questionItemData)
{
List<ToggleItem> tmp = new List<ToggleItem>();
for (int i = 0; i < questionItemData.answerDatas.Count; i++)
{
ToggleItem tog = GameObject.Instantiate(Resources.Load<ToggleItem>("Question/Toggle"));//实例化选项toggle
tog.Init(questionItemData, questionItemData.answerDatas[i]);//toggle初始化
tog.thisTog.group = questionGroup;
tog.transform.SetParent(questionItem);
tog.transform.localScale = Vector3.one;
tmp.Add(tog);
}
QuestionNumber.QuestionContent questionContent = new QuestionNumber.QuestionContent(mQuestionlist[questionCount], tmp);//初始化选项对象
questionContent.SetVisible(false);
mQuestionlist[questionCount].AddQuestion(questionContent);
mContenList.Add(questionContent);
}
/// <summary>
/// 上一题点击事件
/// </summary>
private void PreviousClick()
{
if (questionCount > 0)
{
questionCount--;
CheckOtherQuestion();
_QuesitonBtnItemDatas[questionCount].ChangeQuestionState(QuestionState.Select);
}
}
/// <summary>
/// 下一题点击事件
/// </summary>
private void NextClick()
{
if (questionCount < questionData.questionItemDatas.Count - 1)
{
questionCount++;
CheckOtherQuestion();
_QuesitonBtnItemDatas[questionCount].ChangeQuestionState(QuestionState.Select);
}
}
/// <summary>
/// 检查其他未作答的题目
/// </summary>
private void CheckOtherQuestion()
{
for (int i = 0; i < _QuesitonBtnItemDatas.Count; i++)
{
if (!_QuesitonBtnItemDatas[i].isSelectAnswer)
{
_QuesitonBtnItemDatas[i].img.sprite = _QuesitonBtnItemDatas[i].Default;//未作答恢复默认状态
}
}
}
/// <summary>
/// 提交事件
/// </summary>
private void SubmitClick()
{
//double questionTotalScore = 0;
for (int i = 0; i < _QuesitonBtnItemDatas.Count; i++)
{
if (_QuesitonBtnItemDatas[i].QuestionScore > 0)
{
questionTotalScore += questionData.questionItemDatas[i].RightVar;
tagImages[i].color = Color.green;
}
else
{
tagImages[i].color = Color.red;
}
}
}
/// <summary>
/// 题目数据类
/// </summary>
public class QuestionDatas
{
public List<QuestionItemDatas> questionItemDatas;
public QuestionDatas(XmlNode node)
{
questionItemDatas = new List<QuestionItemDatas>();
for (int i = 0; i < node.ChildNodes.Count; i++)
{
questionItemDatas.Add(new QuestionItemDatas(node.ChildNodes[i]));
}
}
}
/// <summary>
/// 一道题目数据类
/// </summary>
public class QuestionItemDatas
{
/// <summary>
/// 正确答案分值
/// </summary>
public int RightVar;
/// <summary>
/// 问题
/// </summary>
public string Problem;
public int Id;
public QuestionItemDatas(XmlNode node)
{
answerDatas = new List<AnswerDatas>();
Problem = node["Name"].InnerText;
Id = int.Parse(node.Attributes["Id"].InnerText);
XmlNodeList answerList = node["Answer"].ChildNodes;
for (int i = 0; i < answerList.Count; i++)
{
answerDatas.Add(new AnswerDatas(answerList[i]));
}
}
public List<AnswerDatas> answerDatas;
}
/// <summary>
/// 一道题目对应的选项数据类
/// </summary>
public class AnswerDatas
{
/// <summary>
/// 选项对应的分数
/// </summary>
public int score;
/// <summary>
/// 选项内容
/// </summary>
public string answerName;
public AnswerDatas(XmlNode node)
{
answerName = node.Attributes["Name"].InnerText;
score = int.Parse(node.InnerText);
}
}
}
将该脚本拖拽到UI上即可,并给其中对象拖拽赋值:

using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 题目默认、选中、完成作答三个状态
/// </summary>
public enum QuestionState
{
Default,
Select,
Finished
}
public class QuestionBtnItem : MonoBehaviour
{
public int Id;
public Image img;
public Toggle thisBtn;
public Sprite Default;//默认灰色图
public Sprite Finished;//完成深色图
public Sprite Select;//选中颜色图
private System.Action<int> callBack;
private QuestionState questionState = QuestionState.Default;//题目默认未选中状态
public bool isSelectAnswer = false;//当前题目是否已选择答案
//public string SelectAnswer = "";
private float questionScore = 0;
public float QuestionScore
{
get { return questionScore; }
set { questionScore = value; }
}
public void Init(int i,System.Action<int > callBack=null)
{
thisBtn = gameObject.GetComponent<Toggle>();
if (i == 0)
{
ChangeQuestionState(QuestionState.Select);//默认选中第一道题
}
Id = i;
this.callBack = callBack;
thisBtn.name = (i+1).ToString();
thisBtn.GetComponentInChildren<Text>().text = "第 " + thisBtn.name + " 题";
thisBtn.onValueChanged.AddListener((isSelect) =>
{
if (callBack!=null)
{
callBack(Id);//选中就调用一次回调函数
}
});
}
/// <summary>
/// 修改题目状态
/// </summary>
/// <param name="state"></param>
public void ChangeQuestionState(QuestionState state)
{
switch (state)
{
case QuestionState.Default:
img.sprite = Default;
break;
case QuestionState.Select:
thisBtn.isOn = true;
break;
case QuestionState.Finished:
isSelectAnswer = true;
img.sprite = Finished;
break;
}
}
}
将该脚本拖拽给QuestionTog对象:赋值题目的三种状态图

using UnityEngine;
using UnityEngine.UI;
public class ToggleItem : MonoBehaviour
{
public Toggle thisTog;
public Text optionText;//选项文本
public float Score;//选项对应分值
public void Init(Question.QuestionItemDatas questionItemData, Question.AnswerDatas answerData)
{
Score = answerData.score;
optionText.text = answerData.answerName;
thisTog.onValueChanged.AddListener((isSelect) =>
{
Question.Instance._QuesitonBtnItemDatas[questionItemData.Id].ChangeQuestionState(QuestionState.Finished);
Question.Instance._QuesitonBtnItemDatas[questionItemData.Id].QuestionScore = Score;//将选择的选项分值赋值给当前题目
});
}
}
将改脚本拖拽给选项Toggle:





创作不易,喜欢就一键三连呀,点点关注哦!
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
如果我使用ruby版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更
我安装了ruby版本管理器,并将RVM安装的ruby实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby。有没有办法让emacs像shell一样尊重ruby的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit