首先要感谢周周的Unity小屋大佬,原文链接如下
https://blog.csdn.net/qq_42437783/article/details/121613573?spm=1001.2014.3001.5506
在此基础上增加了一些功能,使其比较完善
通过xml文件写入问题答案和解析,点击开始答题进入答题界面,在规定时间内答题,倒计时结束,自动关闭答题界面,显示结束界面和得分,倒计时未结束,可以答题,答过的题不可二次修改,点击下方的小点按钮,选择对应的题目,题目选择完毕后,下方按钮也有对应标识,不可再次点击。
程序运行如下:
答题界面与周周的Unity小屋布置的框架一样,注意预制体,xml文件的位置等。添加了得分,倒计时等。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Options : MonoBehaviour
{
/// <summary>
/// 当前选项组件
/// </summary>
public Toggle thisToggle;
/// <summary>
/// 选项的内容文本
/// </summary>
public Text optionText;
/// <summary>
/// 选项对应的分数
/// </summary>
public int score;
/// <summary>
/// 选项的状态
/// </summary>
public bool IsSelect = false;
public void Init(AnswerData answerData)
{
optionText.text = answerData.option;
score = answerData.Score;
thisToggle.onValueChanged.AddListener((isSelect) => { IsSelect =isSelect; });
}
}
这个脚本挂载上option预制体上,吧对应的内容拖到对应位置即可。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using UnityEngine;
using UnityEngine.UI;
public class Panel_Question : MonoBehaviour
{
[Header("root界面:开始界面的root 答题界面的root 结束界面的root 提示界面的root")]
[SerializeField] GameObject startRoot;
[SerializeField] GameObject answerRoot;
[SerializeField] GameObject endRoot;
[SerializeField] GameObject hintRoot;
[Header("按钮:开始答题 上一题,提交,下一题")]
[SerializeField] Button startBtn;
[SerializeField] Button previousBtn;
[SerializeField] Button submitBtn;
[SerializeField] Button nextBtn;
[SerializeField] Button backToMainBtn;
[Header("按钮:确认提交 取消提交")]
[SerializeField] Button affirmSubBtn;
[SerializeField] Button cancelSubBtn;
[Header("文本:题目序号 解析内容 得分 倒计时 最后得分")]
[SerializeField] Text questionID;
[SerializeField] Text analysisData;
[SerializeField] Text scoreTxt;
[SerializeField] Text countDownTxt;
[SerializeField] Text endTxt;
[Header("内容scroll的content 单选scroll的content 选项scroll的content")]
[SerializeField] Transform contentScrollContent;
[SerializeField] Transform questionBtnRoot;
[SerializeField] Transform selectContent;
[SerializeField] Transform scrollView;
[SerializeField] ToggleGroup questionGroup;
// 答题界面数据内容
private QuestionPanelData mQuestionPanelData;
// 每一道题的题目内容
private QuestionData mQuestionData;
// 题目内容物体
private GameObject mQuestion;
// 选项的链表
private List<Options> options = new List<Options>();
//倒计时的总时间
public float secound ;
[SerializeField] GameObject prefab;
static Panel_Question instance;
public static Panel_Question GetInstance()
{
return instance;
}
private void Awake()
{
Init();
instance = this;
}
/// <summary>
/// 按钮监听
/// </summary>
private void Init()
{
startBtn.onClick.AddListener(StartAnswer);
previousBtn.onClick.AddListener(previousClick);
submitBtn.onClick.AddListener(submitClick);
nextBtn.onClick.AddListener(nextClick);
backToMainBtn.onClick.AddListener(BackToMain);
affirmSubBtn.onClick.AddListener(AffirmSub);
cancelSubBtn.onClick.AddListener(CancelSub);
}
private void Start()
{
//读取xml文件
StartCoroutine(LoadingQuesiton(DataPath.QuestionData));
scoreTxt.text = "得分: 0";
countDownTxt.text = "答题时间还剩:" + secound;
//界面的显示与隐藏
startRoot.SetActive(true);
answerRoot.SetActive(false);
endRoot.SetActive(false);
hintRoot.SetActive(false);
}
private void Update()
{
if (endRoot.activeSelf)
{
//如果倒计时结束前答题完成,关闭倒计时的协程,时间重新赋值
StopCoroutine(TimeChange());
secound = 0;
}
}
#region 读取xml文件
IEnumerator LoadingQuesiton(string path)
{
yield return null;
using (WWW www = new WWW(path))
{
yield return www;
XmlDocument doc = new XmlDocument();
doc.LoadXml(www.text);
new QuestionPanel(doc.FirstChild);
}
}
#endregion
#region 初始化第一道题
public void InitQuestionPanel(QuestionPanelData questionPanelData)
{
//this.gameObject.SetActive(true);
mQuestionPanelData = questionPanelData;
CreateQuestion(questionPanelData.questionData[index]);
}
#endregion
#region 创建题目
bool isFirst = false;
public void CreateQuestion(QuestionData questionData)
{
//数据赋值
analysisData.text = "";
mQuestionData = questionData;
questionID.text = string.Format("第{0}题(共" + mQuestionPanelData.questionData.Count + "题)", index + 1);
if (mQuestion != null)
{
Destroy(mQuestion);
}
//实例化题目预制体
mQuestion = Instantiate(Resources.Load<GameObject>(DataPath.QuestionText));
mQuestion.transform.SetParent(contentScrollContent);
mQuestion.transform.localScale = Vector3.one;
mQuestion.GetComponent<Text>().text = questionData.problem;
if (options.Count > 0)
{
for (int i = 0; i < options.Count; i++)
{
Destroy(options[i].gameObject);
}
}
options = new List<Options>();
//实例化按钮选项组序列
if (!isFirst)
for (int i = 0; i < mQuestionPanelData.questionData.Count; i++)
{
Instantiate(prefab, scrollView);
isFirst = true;
}
//当前题目的按钮序列的标识变大
for (int i = 0; i < mQuestionPanelData.questionData.Count; i++)
{
if (i!= index)
scrollView.GetChild(i).gameObject.GetComponent<RectTransform>().localScale = new Vector2(1, 1);
else
scrollView.GetChild(i).gameObject.GetComponent<RectTransform>().localScale = new Vector2(1.5f, 1.5f);
}
//实例化选项预制体
for (int i = 0; i < questionData.answerData.Count; i++)
{
Options option = Instantiate(Resources.Load<Options>("Options"));
option.Init(questionData.answerData[i]);
option.transform.SetParent(selectContent);
//如果是单选则设置为一个toggle组
if (questionData.isSingleChoice)
{
option.thisToggle.group = questionGroup;
}
options.Add(option);
}
}
#endregion
#region 开始答题 上一题 下一题 提交按钮事件
// 开始答题
public void StartAnswer()
{
for (int i = 0; i < QuestionPanel.questionPanelData.Count; i++)
{
InitQuestionPanel(QuestionPanel.questionPanelData[i]);
}
startRoot.SetActive(false);
answerRoot.SetActive(true);
secound = 30;
//开启倒计时
StartCoroutine(TimeChange());
}
// 上一题点击事件
private void previousClick()
{
if (index > 0)
{
index--;
CreateQuestion(mQuestionPanelData.questionData[index]);
}
if (scrollView.GetChild(index).GetComponent<Button>().interactable == false)
foreach (var item in options)
item.thisToggle.interactable = false;
}
// 下一题点击事件
private void nextClick()
{
if (index < mQuestionPanelData.questionData.Count - 1)
{
index++;
CreateQuestion(mQuestionPanelData.questionData[index]);
isFirstClick = false;
}
if (scrollView.GetChild(index).GetComponent<Button>().interactable == false)
foreach (var item in options)
item.thisToggle.interactable = false;
}
int score = 0;
bool isFirstClick = false; //是否是第一次答对,只有点击第一次提交的时候加分,再点提交不加分
// 题目提交事件
private void submitClick()
{
//遍历当前题目的选项,有选择的就可以提交核验答案,并显示解析内容
foreach (var item in options)
{
if (item.thisToggle.isOn)
{
//回答正确加一分
if (item.score > 0)
{
analysisData.text = "回答正确";
if (!isFirstClick)
{
score += 1;
isFirstClick = true;
}
scoreTxt.text = "得分:" + score.ToString();
}
else
analysisData.text = "回答错误,解析:" + mQuestionData.Analysis;
}
//选择一个选项之后不能在选择其他选项
item.thisToggle.interactable = false;
}
//如果当前题目是最后一题,提交之后,出现提示界面
if (index + 1 == mQuestionPanelData.questionData.Count)
{
startRoot.SetActive(false);
answerRoot.SetActive(true);
endRoot.SetActive(false);
hintRoot.SetActive(true);
}
//提交后,该题目不可再选择修改
scrollView.GetChild(index).GetComponent<Image>().color = Color.green;
scrollView.GetChild(index).GetComponent<Button>().interactable = false;
}
//返回主界面
void BackToMain()
{
startRoot.SetActive(true);
answerRoot.SetActive(false);
endRoot.SetActive(false);
score = 0;
scoreTxt.text = "得分:" + score.ToString();
for (int i = 0; i < scrollView.childCount; i++)
{
scrollView.GetChild(i).GetComponent<Image>().color = Color.white;
scrollView.GetChild(i).GetComponent<Button>().interactable = true;
Debug.Log(456789);
}
index = 0;
}
int index = 0;
//缩列按钮事件
public void ThisBtn(ButtonItem item)
{
for (int i = 0; i < scrollView.childCount; i++)
{
CreateQuestion(mQuestionPanelData.questionData[item.transform.GetSiblingIndex()]);
index = item.transform.GetSiblingIndex();
}
}
//确认提交 显示结束界面
void AffirmSub()
{
startRoot.SetActive(false);
answerRoot.SetActive(false);
endRoot.SetActive(true);
hintRoot.SetActive(false);
endTxt.text = "答题结束\n 您的得分是:" + score.ToString();
}
//取消提交 返回原来的界面
void CancelSub()
{
startRoot.SetActive(false);
answerRoot.SetActive(true);
endRoot.SetActive(false);
hintRoot.SetActive(false);
}
#endregion
#region 倒计时的协程
IEnumerator TimeChange()
{
while (secound > 0)
{
yield return new WaitForSeconds(1);
countDownTxt.text = "答题时间还剩:"+secound.ToString()+"秒";
secound--;
}
if (secound<=0)
{
//界面的显示与隐藏
startRoot.SetActive(false);
answerRoot.SetActive(false);
endRoot.SetActive(true);
endTxt.text = "答题结束\n 您的得分是:" + score.ToString();
}
}
#endregion
}
/// <summary>
/// 答题panel数据类
/// </summary>
public class QuestionPanel
{
public static List<QuestionPanelData> questionPanelData;
public QuestionPanel(XmlNode node)
{
questionPanelData = new List<QuestionPanelData>();
for (int i = 0; i < node.ChildNodes.Count; i++)
{
questionPanelData.Add(new QuestionPanelData(node.ChildNodes[i]));
}
}
}
/// <summary>
/// 答题界面数据类
/// </summary>
public class QuestionPanelData
{
public List<QuestionData> questionData;
public QuestionPanelData(XmlNode node)
{
questionData = new List<QuestionData>();
for (int i = 0; i < node.ChildNodes.Count; i++)
{
questionData.Add(new QuestionData(node.ChildNodes[i]));
}
}
}
/// <summary>
/// 题目数据类
/// </summary>
public class QuestionData
{
// 是否为单选,true为单选,false为多选
public bool isSingleChoice;
// 解析内容
public string Analysis;
// 题目内容
public string problem;
public List<AnswerData> answerData;
public QuestionData(XmlNode node)
{
isSingleChoice = bool.Parse(node.Attributes["SelectType"].InnerText);
Analysis = node["Analysis"].InnerText;
problem = node["Problem"].InnerText;
answerData = new List<AnswerData>();
XmlNodeList nodelist = node["Answer"].ChildNodes;
for (int i = 0; i < nodelist.Count; i++)
{
answerData.Add(new AnswerData(nodelist[i]));
}
}
}
/// <summary>
/// 答案数据类
/// </summary>
public class AnswerData
{
// 选项的内容
public string option;
// 选项对应的分数
public int Score;
public AnswerData(XmlNode node)
{
option = node.Attributes["option"].InnerText;
Score = int.Parse(node.InnerText);
}
}
这个代码挂在canvas上,其中代码中的命名与场景中的命名一致,将对应物体添加到对应位置上,其中ButtonItem是挂载上image上的,image是一个预制体,内容如下。
ButtonItem代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ButtonItem : MonoBehaviour
{
Button Btn;
// Start is called before the first frame update
void Start()
{
Btn = GetComponent<Button>();
Btn.onClick.AddListener(ThisBtn);
}
public void ThisBtn()
{
Panel_Question.GetInstance().ThisBtn(this);
}
}
其中,用www读取xml文件时,会报错,是xml格式有问题,我在读取时报错是XmlException: Data at the root level is invalid. Line 1, position 1.通过代码重新生成一个xml文件,再在其中添加想写的内容即可。我生成XmlTest的代码如下。有需要的可以参考
using UnityEngine;
using System.IO;
using System.Xml;
public class XmlTest : MonoBehaviour
{
// Use this for initialization
void Start()
{
CreateXml();
}
///
/// Creates the xml.
///
private void CreateXml()
{
//设置保存路径
string path = Application.dataPath + "/XML/" + "ConfigFile.xml";
//判断文件是否存在
if (File.Exists(path) == false)
{
//创建一个xml文件
XmlDocument xml = new XmlDocument();
//创建最上层节点
XmlElement root = xml.CreateElement("Root");
//创建子节点
XmlElement element = xml.CreateElement("Question");
element.SetAttribute("SelectType", "True");
//创建子节点的第一个子节点,设置属性并添加内容
XmlElement Child1 = xml.CreateElement("Problem");
Child1.InnerText = "这里输入您的题目";
//创建子节点的第二个子节点,设置属性并添加内容
XmlElement Child2 = xml.CreateElement("Answer");
//创建三级子节点
XmlElement item1 = xml.CreateElement("Item");
item1.SetAttribute("option", "A.答案一");
item1.InnerText = "0";
XmlElement item2 = xml.CreateElement("Item");
item2.SetAttribute("option", "B.答案一");
item2.InnerText = "0";
XmlElement item3 = xml.CreateElement("Item");
item3.SetAttribute("option", "C.答案一");
item3.InnerText = "1";
XmlElement item4 = xml.CreateElement("Item");
item4.SetAttribute("option", "D.答案一");
item4.InnerText = "0";
//二级子节点
XmlElement Child3 = xml.CreateElement("Analysis");
Child3.InnerText = "这里输入解析";
//创建子节点
XmlElement element2 = xml.CreateElement("Question");
element2.SetAttribute("SelectType", "True");
//创建子节点的第一个子节点,设置属性并添加内容
XmlElement Child2_1 = xml.CreateElement("Problem");
Child2_1.InnerText = "这里输入您的题目gvfrebr";
//创建子节点的第二个子节点,设置属性并添加内容
XmlElement Child2_2= xml.CreateElement("Answer");
//创建三级子节点
XmlElement item2_1 = xml.CreateElement("Item");
item2_1.SetAttribute("option", "A.答案一");
item2_1.InnerText = "0";
XmlElement item2_2 = xml.CreateElement("Item");
item2_2.SetAttribute("option", "B.答案44");
item2_2.InnerText = "0";
XmlElement item2_3 = xml.CreateElement("Item");
item2_3.SetAttribute("option", "C.答案3");
item2_3.InnerText = "1";
XmlElement item2_4 = xml.CreateElement("Item");
item2_4.SetAttribute("option", "D.答案一");
item2_4.InnerText = "0";
//二级子节点
XmlElement Child2_3 = xml.CreateElement("Analysis");
Child2_3.InnerText = "这里输入解析";
//把节点一层一层的添加至xml中,注意他们之间的先后顺序,这是生成XML文件的顺序
element2.AppendChild(Child2_1);
Child2_2.AppendChild(item2_1);
Child2_2.AppendChild(item2_2);
Child2_2.AppendChild(item2_3);
Child2_2.AppendChild(item2_4);
element2.AppendChild(Child2_2);
element2.AppendChild(Child2_3);
root.AppendChild(element2);
element.AppendChild(Child1);
Child2.AppendChild(item1);
Child2.AppendChild(item2);
Child2.AppendChild(item3);
Child2.AppendChild(item4);
element.AppendChild(Child2);
element.AppendChild(Child3);
root.AppendChild(element);
xml.AppendChild(root);
//保存XML文档
xml.Save(path);
Debug.Log("Xml 创建成功!");
}
}
}
也可以只生成两个root根节点,然后内容自己再xml中写,就不用通过代码添加了。
通过xml文件读取的数据的路径通过一个代码封装静态变量,全局使用,代码如下:DataPath
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 全局静态类,用来定义静态字段,方便调用
/// </summary>
public class DataPath
{
public static string QuestionData = "file://" + Application.dataPath + "/XML/" + "ConfigFile.xml";
public static string QuestionText = "QuestionText";
}
链接:https://pan.baidu.com/s/1R3TwGfd2PC5Q_c09duGC7A?pwd=jl98
提取码:jl98
电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。 准备工作: 1、U盘一个(尽量使用8G以上的U盘)。 2、一台正常联网可使用的电脑。 3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。 4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。 U盘启动盘制作步骤: 注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。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
目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里编辑 3.解析依赖到项目中
Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、
因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实
在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题: