Unity building interactive program record

1: Effect display

Functional description:

Click the Humanities and History button to enter the Humanities and History interface. There are pictures at the top and text introductions at the bottom. The pictures and text can be modified externally, and the number of pictures can also be modified externally. Click the left and right swipe buttons on the pictures to slide them to view, or click the buttons on the left and right to slide them to view them.

Click the 3D model button to enter the 3D model interface. The top is the model. The model can be rotated with one finger and zoomed in and out with two fingers. The bottom is the model data, the left is the fixed data, and the right is the number of participants and the accuracy rate of the knowledge question and answer. This part is used json storage.

Click the Question and Answer button to enter the Question and Answer interface. Questions for the Question and Answer can be imported externally. Select the option below and submit it.


2: Content description

1. Humanities and History Part

Picture part above

Create a new ScrollView, adjust the size, mount the Grid Layout Group on the Conent, adjust the size and spacing, the size and spacing here are the same as the spacing in the code, as shown below

Hang the SliderCanMoveScrollView (picture page turning) code above, set the width of the picture, the distance between the interval and the left side, and the number of pictures (totalNum, the number of pictures is modified externally through the ConfigFile file)

As shown in the picture: the picture length is 600, the interval is 400, and the left margin is 40

code show as below

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using DG.Tweening;
/// <summary>
/// 图片翻页
/// </summary>
public class SliderCanMoveScrollView : MonoBehaviour, IBeginDragHandler, IEndDragHandler
{
    //content的长度计算方法:(cellLength + spacing)*(num-1)
    [SerializeField] RectTransform contentTrans;
    ImageManage ImageManage;
    private float beginMousePositionX;
    private float endMousePositionX;
    private ScrollRect scrollRect;

    public int cellLength;
    public int spacing;
    public int leftOffset;
    float moveOneItemLength;

    Vector3 currentContentLocalPos;//上一次的位置
    Vector3 contentInitPos;//Content初始位置
    Vector2 contentTransSize;//Content初始大小

    int totalItemNum;
    int currentIndex;

    public bool needSendMessage;
    [SerializeField] Text text;

    public string totalNum;

    public int TotalItemNum { get => totalItemNum; set => totalItemNum = value; }

    private void Awake()
    {
        totalItemNum = int.Parse(ConfigFile.LoadString(totalNum));

        //获取个数
        scrollRect = GetComponent<ScrollRect>();
        //数据赋值
        moveOneItemLength = cellLength + spacing;
        currentContentLocalPos = contentTrans.localPosition;
        contentTransSize = contentTrans.sizeDelta;
        contentInitPos = contentTrans.localPosition;
        currentIndex = 1;
        SetContentLength(totalItemNum);
        ImageManage = contentTrans.GetComponent<ImageManage>();
    }

    private void Start()
    {
        currentIndex = 1;
        if (contentTrans.childCount > 1 && ImageManage.ImageList[0] != null)
            text.text = ImageManage.ImageList[0].name;

        //text.text = ImageManage.ImageList[0].name;
    }

    public void Init()
    {
        currentIndex = 1;
        if (contentTrans != null)
        {
            contentTrans.localPosition = contentInitPos;
            currentContentLocalPos = contentInitPos;

        }
    }

    /// <summary>
    /// 通过拖拽与松开来达成翻页效果
    /// </summary>
    /// <param name="eventData"></param>

    public void OnEndDrag(PointerEventData eventData)
    {
        endMousePositionX = Input.mousePosition.x;
        float offSetX = 0;
        float moveDistance = 0;//当次需要滑动的距离
        offSetX = beginMousePositionX - endMousePositionX;

        if (offSetX > 0)//右滑
        {
            Debug.Log("右滑");
            if (currentIndex >= totalItemNum)
            {
                return;
            }
            if (needSendMessage)
            {
                UpdatePanel(true);
            }

            moveDistance = -moveOneItemLength;
            currentIndex++;
            text.text = ImageManage.ImageList[currentIndex - 1].name;
        }
        else//左滑
        {
            Debug.Log("左滑");

            if (currentIndex <= 1)
            {
                return;
            }
            if (needSendMessage)
            {
                UpdatePanel(false);
            }
            moveDistance = moveOneItemLength;
            currentIndex--;
            text.text = ImageManage.ImageList[currentIndex - 1].name;
        }

        DOTween.To(() => contentTrans.localPosition, lerpValue => contentTrans.localPosition = lerpValue, currentContentLocalPos + new Vector3(moveDistance, 0, 0), 0.5f).SetEase(Ease.OutQuint);
        currentContentLocalPos += new Vector3(moveDistance, 0, 0);
    }

    /// <summary>
    /// 按钮来控制翻书效果
    /// </summary>

    public void ToNextPage()
    {
        float moveDistance = 0;
        if (currentIndex >= totalItemNum)
        {
            return;
        }

        moveDistance = -moveOneItemLength;
        currentIndex++;

        if (needSendMessage)
        {
            UpdatePanel(true);
        }
        DOTween.To(() => contentTrans.localPosition, lerpValue => contentTrans.localPosition = lerpValue, currentContentLocalPos + new Vector3(moveDistance, 0, 0), 0.5f).SetEase(Ease.OutQuint);
        currentContentLocalPos += new Vector3(moveDistance, 0, 0);
        text.text = ImageManage.ImageList[currentIndex - 1].name;

    }

    public void ToLastPage()
    {
        float moveDistance = 0;
        if (currentIndex <= 1)
        {
            return;
        }

        moveDistance = moveOneItemLength;
        currentIndex--;

        if (needSendMessage)
        {
            UpdatePanel(false);
        }
        DOTween.To(() => contentTrans.localPosition, lerpValue => contentTrans.localPosition = lerpValue, currentContentLocalPos + new Vector3(moveDistance, 0, 0), 0.5f).SetEase(Ease.OutQuint);
        currentContentLocalPos += new Vector3(moveDistance, 0, 0);
        text.text = ImageManage.ImageList[currentIndex - 1].name;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        beginMousePositionX = Input.mousePosition.x;
    }

    //设置Content的大小
    public void SetContentLength(int itemNum)
    {
        contentTrans.sizeDelta = new Vector2(contentTrans.sizeDelta.x + (cellLength + spacing) * (itemNum - 1), contentTrans.sizeDelta.y);
        totalItemNum = itemNum;
    }

    //初始化Content的大小
    public void InitScrollLength()
    {
        contentTrans.sizeDelta = contentTransSize;
    }

    //发送翻页信息的方法
    public void UpdatePanel(bool toNext)
    {
        if (toNext)
        {
            gameObject.SendMessageUpwards("ToNextLevel");
        }
        else
        {
            gameObject.SendMessageUpwards("ToLastLevel");
        }
    }
}

Hang the two methods of left and right sliding on the button. The size of the content should be enlarged and reduced according to the number of pictures, so combine the variable of the number of pictures with the content. This code must be combined with ImageManage, otherwise the picture cannot be loaded.


Place the code for externally imported images on Content, set the image path and number of images, and set an Image prefabricated body to dynamically generate the corresponding number of images under content.

(The acquisition of the picture name, the point where I was stuck at that time, will be recorded separately)

 sprite.name = Path.GetFileNameWithoutExtension(dirs[j]);

code show as below

 

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 图片外部加载和图片的数量的动态添加,删除
/// </summary>
public class ImageManage : MonoBehaviour
{
    List<Sprite> imageList = new List<Sprite>();   //加载的图片的列表
    List<Image> images = new List<Image>();
    public List<Sprite> ImageList { get => imageList; set => imageList = value; }

    private void Awake()
    {
        //获取content下面的子物体
        FindAllChildToList(transform, images);

        //加载所有图片
        LoadAllPic();
    }
    void Start()
    {
        for (int i = 0; i < images.Count; i++)
        {
            int index = i;
            //当图片的数量小于生成的图片存储数组的数量,让图片存储的图片变成第一个
            if (index > imageList.Count - 1)
            {
                index = 0;
            }
            //将图片赋值到预制体上
            images[i].GetComponent<Image>().sprite = imageList[index];

        }
    }

    [Header("图片路径")]
    public string imagePathStr;
    #region  获取streamingAssets/Content里面的所有文件的数量,获取父物体下的所有子物体
    public void FindAllChildToList<Image>(Transform parent, List<Image> list)
    {
        //"/streamingAssets/Content1"
        var imagePath = Application.dataPath + imagePathStr;
        if (Directory.Exists(imagePath))
        {
            DirectoryInfo direction = new DirectoryInfo(imagePath);
            FileInfo[] files = direction.GetFiles("*", SearchOption.AllDirectories);
            foreach (Transform child in parent)
            {
                //图片数等于场景中的图片组件
                if (parent.childCount == files.Length / 2)
                {
                    //将图片放入父物体中
                    Image go = child.GetComponent<Image>();
                    if (go != null)
                    {
                        list.Add(child.GetComponent<Image>());
                    }
                    FindAllChildToList(child, list);
                }

                //图片数小于场景中的图片组件
                if (parent.childCount > files.Length / 2)
                {
                    Debug.Log("image组多");
                    int num = parent.childCount - files.Length / 2;
                    for (int i = parent.childCount - 1; i > num; i--)
                    {
                        Destroy(parent.GetChild(i).gameObject);
                    }

                    //将图片放入父物体中
                    Image go = child.GetComponent<Image>();
                    if (go != null)
                    {
                        list.Add(child.GetComponent<Image>());
                    }
                    FindAllChildToList(child, list);
                }

                //图片数小于场景中的图片组件
                if (parent.childCount < files.Length / 2)
                {
                    //Debug.Log("图多");
                    //在content下增加image对象
                    GameObject projectile = Instantiate(GameObject.Find("Image"), transform);

                    //修改图片的名字
                    for (int i = 0; i < parent.childCount; i++)
                    {
                        projectile.name = (i + 1).ToString();
                    }

                    //将图片放入父物体中
                    Image go = child.GetComponent<Image>();
                    if (go != null)
                    {
                        list.Add(child.GetComponent<Image>());
                    }
                    FindAllChildToList(child, list);
                }
            }
        }
    }
    #endregion

    public string LoadImagePath;
    #region 外部加载图片
    //外部加载图片
    void LoadAllPic()
    {
        //从StreamingAssets中加载图片
        string imgtype = "*.BMP|*.JPG|*.GIF|*.PNG";
        string[] ImageType = imgtype.Split('|');
        for (int k = 0; k < ImageType.Length; k++)
        {
            //获取streamingAssets文件夹下所有的图片路径  
            string[] dirs = Directory.GetFiles(Application.streamingAssetsPath + LoadImagePath, ImageType[k]);
            for (int j = 0; j < dirs.Length; j++)
            {
                Texture2D tx = new Texture2D(100, 100);
                tx.LoadImage(getImageByte(dirs[j]));
                Sprite sprite = Sprite.Create(tx, new Rect(0, 0, tx.width, tx.height), new Vector2(-500, -500));
                //获取图片名称
                sprite.name = Path.GetFileNameWithoutExtension(dirs[j]);
                //将获取的图片加到图片列表中
                imageList.Add(sprite);
            }
        }
    }

    private static byte[] getImageByte(string imagePath)
    {
        FileStream files = new FileStream(imagePath, FileMode.Open);
        byte[] imgByte = new byte[files.Length];
        files.Read(imgByte, 0, imgByte.Length);
        files.Close();
        return imgByte;
    }
    #endregion
}

 Because there are four different parts of pictures, the code is mounted on the corresponding ScrollView and content. You only need to modify the corresponding picture path and number of pictures.


text part below

The text part below also creates a new ScrollView (because the text is imported from outside, you may need to slide it, build a ScrollView to slide up and down to view), put the code on the text itself, and add the Content Size Fitter component to set the width to adapt. Two of them There are two codes, one is an external import of text, and the other is a Text component that does not read newline spaces.

Drag the corresponding content and text in, and write the image path in it

code show as below

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 文字内容的外部加载
/// </summary>
public class TextManager : MonoBehaviour
{
    public string filePath;  //内容文件的名称

    [SerializeField] Text contentTxt;                   //内容展示
    [SerializeField] RectTransform content;

    private void Start()
    {
        SetContentTxt();
    }

    private void Update()
    {
        content.sizeDelta = new Vector2(content.sizeDelta.x, contentTxt.GetComponent<RectTransform>().sizeDelta.y + 50);
    }
    private void SetContentTxt()
    {
        //标题或文件名称为空时 不执行
        if (filePath.Equals(""))
        {
            Debug.Log("标题内容的string字段为空");
            return;
        }
        //内容的文字替换
        contentTxt.text = File.ReadAllText(Application.streamingAssetsPath + $"/ContentTxt/{filePath}.txt", Encoding.UTF8);

    }
}

Among them, text import may cause garbled Chinese characters. At this time, modify the encoding format of the txt text of the text to be imported to UTF-8 format, as shown in the figure

Modification method: Click File------Save As----Encoding, select UTF-8, and then click Save.

 Text component code that does not read newline spaces

using UnityEngine.UI;
using UnityEngine;

/// <summary>
/// 不读取换行空格的Text组件
/// </summary>
[RequireComponent(typeof(Text))]
public class NonBreakingSpaceText : MonoBehaviour
{
    private Text txt;//Text文本组件

    private const string NonBreakingSpace = "\u00A0";//不换行空格的Unicode编码

    private void Awake()
    {
        txt = GetComponent<Text>();

        OnTextChange();
        txt.RegisterDirtyLayoutCallback(OnTextChange);
    }

    private void OnTextChange()
    {
        if (txt.text.Contains(" "))
        {
            txt.text = txt.text.Replace(" ", NonBreakingSpace);
        }
    }
}

Because there are also four parts below, you need to set different paths on each part of the text and read different txt files.


2. Model part

Mount the DoubleTouchManager code for two-finger operation on the camera. The code is as follows

using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using UnityEngine.EventSystems;

public class DoubleTouchManager : MonoBehaviour
{
    public LayerMask layer;

    static DoubleTouchManager intance;
    public static DoubleTouchManager GetIntance()
    {
        return intance;
    }

    private void Awake()
    {
        intance = this;
    }
    void Start()
    {
    }

    Item _mouseObj;//射线检测获取item

    //封装 用于item判断是否10秒后位置复原
    public Item MouseObj { get => _mouseObj; set => _mouseObj = value; }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            Debug.Log("按下ESC退出");
            Application.Quit();
        }

        #region 鼠标控制旋转缩放
        //没有手指触摸时才可执行鼠标
        if (Input.touches.Length <= 0)
        {
            //鼠标左键按下 记录鼠标位置
            if (Input.GetMouseButtonDown(0))
            {
                MouseObj = RayDetection(Input.mousePosition);
                //item为空不执行
                if (MouseObj != null)
                    MouseObj._OldPos = Input.mousePosition;//修改item的oldPos值;
            }

            //鼠标拖动旋转物体碰撞的物体不为空
            if (Input.GetMouseButton(0) && MouseObj != null)
                MouseObj.OnMuseButtonLeftRot();


            //鼠标滚轮控制放大缩小
            float value = Input.GetAxis("Mouse ScrollWheel");
            if (value != 0)
            {
                //滑动发出射线获取碰撞到的item
                Item _obj = RayDetection(Input.mousePosition);

                //item为空不执行
                if (_obj != null)
                    _obj.OnMuseButtonRightScale(value);
            }

            //鼠标拖动旋转物体碰撞的物体不为空
            if (Input.GetMouseButtonUp(0))
                MouseObj = null;

            return;
        }
        #endregion

        #region 多指触摸
        Debug.Log("触摸数量:" + Input.touches.Length);
        for (int i = 0; i < Input.touches.Length; i++)
        {
            //射线检测获取Item
            Item newItem = RayDetection(Input.GetTouch(i).position);

            if (MouseObj == null)
                MouseObj = newItem;
            else if (MouseObj != newItem)
            {
                MouseObj.InitData(); //初始化数据
                MouseObj = newItem;
            }

            //if (MouseObj == null)
            //    MouseObj = GetFirstPickGameObject(Input.GetTouch(i).position);

            if (MouseObj != null)
            {
                if (!MouseObj.istouch1 || MouseObj.touch1ID == Input.GetTouch(i).fingerId)
                {
                    //手指1存在 并且这个手指id相同时
                    MouseObj.Touch1(i);
                    Debug.Log("danzhi");
                }
                else if (!MouseObj.istouch2 || MouseObj.touch2ID == Input.GetTouch(i).fingerId)
                {
                    //手指1存在 手指不相同
                    MouseObj.Touch2(i);
                }

                Debug.Log("检测到物体");

            }
        }
        #endregion


    }

    #region 射线检测 检测并返回碰撞的Item
    Item RayDetection(Vector2 pos)
    {
        Ray ray = Camera.main.ScreenPointToRay(pos);
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit, int.MaxValue, layer))
            return hit.transform.GetComponent<Item>();

        return null;

    }

    #endregion

    #region UI射线检测
    /// <summary>
    /// 获取点击的UI类型Item
    /// </summary>
    /// <param name="position">点击屏幕坐标</param>
    /// <returns></returns>
    public Item GetFirstPickGameObject(Vector2 position)
    {
        EventSystem eventSystem = EventSystem.current;
        PointerEventData pointerEventData = new PointerEventData(eventSystem);
        pointerEventData.position = position;
        //射线检测ui
        List<RaycastResult> uiRaycastResultCache = new List<RaycastResult>();
        eventSystem.RaycastAll(pointerEventData, uiRaycastResultCache);
        if (uiRaycastResultCache.Count > 0 && uiRaycastResultCache[0].gameObject.GetComponent<Item>() != null)
            return uiRaycastResultCache[0].gameObject.GetComponent<Item>();
        return null;
    }
    #endregion

    #region 2D BoxClider物体射线检测
    //Transform RayDetection(Vector3 pos)
    //{
    //    pos.z = 10;
    //    Vector3 screenPos = Camera.main.ScreenToWorldPoint(pos);
    //    RaycastHit2D hit = Physics2D.Raycast(screenPos, Vector2.zero);
    //    if (hit && hit.transform == gearBtn)
    //    {
    //        return hit.transform;
    //    }

    //    return null;
    //}

    #endregion

}

Set TouchItem, set the level to touchItem, add BoxCollider component and Item code

 

The touchItem is placed behind the model, and the model is placed under an empty object. The size of this empty object must be 1, 1, 1. The moveObj in the model is this empty object. The center point of this empty object is also the center of the model. If the points are consistent, if they are not consistent, the rotation will look awkward.

Item code is as follows

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Item : MonoBehaviour
{
    [Range(0, 10f)]
    [SerializeField] float rotSpeed = 10;  //旋转速度
    Vector3 originRot;//原旋转位置
    Vector3 originScale;//原大小
    public bool istouch1; //触摸1是否存在
    public bool istouch2; //触摸2是否存在

    [SerializeField] float minSize = 0.9f;
    [SerializeField] float maxSize = 1.3f;
    public Transform moveobj;

    float recoverTime;      //恢复时间
    void Start()
    {
        InitData();

        timer = Time.realtimeSinceStartup;
        originRot = moveobj.localEulerAngles;
        originScale = moveobj.localScale;

        recoverTime = int.Parse(ConfigFile.LoadString("recoverTime"));
        Debug.Log(recoverTime);

        minSize = float.Parse(ConfigFile.LoadString("minSize"));
        maxSize = float.Parse(ConfigFile.LoadString("maxSize"));
        Debug.Log(minSize);
        Debug.Log(maxSize);

    }

    #region 初始化
    public void InitData()
    {
        touch1ID = -1;
        touch1Index = -1;
        istouch1 = false;

        touch2ID = -1;
        istouch2 = false;
    }
    #endregion


    float spaceTimer;  //按钮双击时间间隔
    float timer = 0;
    float time2 = 0;
    bool RotationRemove = false;    //旋转是否恢复
    void Update()
    {
        //当没有触摸时并且鼠标选中的item不是自己时
        if (touch1ID == -1 && DoubleTouchManager.GetIntance().MouseObj != this)
        {
            //长按使屏幕停止旋转
            if (Time.realtimeSinceStartup - timer <= 0.5f)
            {
                //如果视频存在,模型不能旋转,不能选中,如果不存在或视频界面消失,模型自动旋转

                moveobj.Rotate(0, 10 * Time.deltaTime, 0);

                timer = Time.realtimeSinceStartup;
            }


            //大于n秒无人操作,电视恢复原来的大小,然后持续旋转
            if (Time.realtimeSinceStartup - time2 >= recoverTime)
            {
                Debug.Log("无人操作,自动复原");
                moveobj.Rotate(0, 10 * Time.deltaTime, 0);

                if (moveobj != null)
                {
                    if (RotationRemove)
                    {
                        moveobj.eulerAngles = originRot;
                        RotationRemove = false;
                    }
                    moveobj.localScale = originScale;
                }
            }

        }
        else
        {
            //Debug.Log("选中模型");
            time2 = Time.realtimeSinceStartup;
            //Debug.Log(((int)time2));
            RotationRemove = true;
        }
    }

    public int touch1ID = -1;
    int touch1Index = -1;
    Vector2 oldRot;
    public void Touch1(int i)
    {
        //当有双指时 不执行旋转
        if (istouch2)
        {
            Debug.Log("检测到双指,退出方法");
            return;
        }

        touch1Index = i;
        istouch1 = true;

        //防止多次触碰出现问题
        if (touch1Index >= Input.touchCount)
        {
            Debug.Log("单指 防止多次触碰出现问题");
            touch1ID = -1;
            touch1Index = -1;
            istouch1 = false;
            return;
        }

        Touch touch = Input.GetTouch(touch1Index);

        //判断id是否相同
        if (touch1ID == -1)
            touch1ID = touch.fingerId;
        else
            if (touch1ID != touch.fingerId)
        {
            touch1ID = -1;
            touch1Index = -1;
            istouch1 = false;
            //id不同 不执行
            return;
        }

        //单指操作 
        if (touch.phase == TouchPhase.Began)
            oldRot = touch.position;

        if (touch.phase == TouchPhase.Moved)
        {
            Vector3 newRot = new Vector3((touch.position.y - oldRot.y), -(touch.position.x - oldRot.x), 0) * Time.deltaTime * rotSpeed;
            var rotation = Quaternion.Euler(newRot);
            moveobj.rotation *= rotation;
            //moveobj.eulerAngles = new Vector3(0, moveobj.eulerAngles.y, 0); //只让Y轴旋转

            oldRot = touch.position;
            Debug.Log("旋转");
        }

        //手指抬起 或者系统取消对触摸的跟踪
        if (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
        {
            touch1ID = -1;
            touch1Index = -1;
            istouch1 = false;
            Debug.Log("手指抬起 或者系统取消对触摸的跟踪");
        }

    }

    public int touch2ID = -1;

    Vector2 oldPos1;
    Vector2 oldPos2;
    public void Touch2(int i)
    {
        istouch2 = true;

        //防止多次触碰出现问题
        if (touch1Index >= Input.touchCount || i >= Input.touchCount)
        {
            Debug.Log("多指: 防止多次触碰出现问题");
            touch1ID = -1;
            touch2ID = -1;
            istouch1 = false;
            istouch2 = false;
            return;
        }

        Touch touch1 = Input.GetTouch(touch1Index);
        Touch touch2 = Input.GetTouch(i);

        //判断id是否相同
        if (touch1ID == -1 || touch2ID == -1)
        {
            touch1ID = touch1.fingerId;
            touch2ID = touch2.fingerId;
        }
        else
        {
            if (touch1ID != touch1.fingerId || touch2ID != touch2.fingerId)
            {
                //id不同 不执行 
                touch1ID = -1;
                touch2ID = -1;
                istouch1 = false;
                istouch2 = false;
                Debug.Log("id不同 不执行 ");
                return;
            }
        }


        //双指操作
        if (touch2.phase == TouchPhase.Began)
        {
            oldPos1 = touch1.position;
            oldPos2 = touch2.position;
            Debug.Log("TouchPhase.Began");
            //return;
        }


        if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
        {
            float oldDistance = Vector2.Distance(oldPos1, oldPos2);  //计算原先两指的距离
            float newDistance = Vector2.Distance(touch1.position, touch2.position);  //当前移动后两指的距离

            //(新距离)减去(旧距离)得出的差如果是负数的话缩小,正数就放大
            float offset = newDistance - oldDistance;
            Debug.Log("3: 判断两指有一个在运动时: " + offset);

            //放大因子, 一个像素按 0.01倍来算(100可调整)
            float scaleFactor = offset / 100;
            //计算物体scale要放大的值
            Vector3 localScale = moveobj.localScale + (Vector3.one * scaleFactor);

            //设置放大缩小的范围值
            Vector3 scale = new Vector3(Mathf.Clamp(localScale.x, minSize, maxSize),
                Mathf.Clamp(localScale.y, minSize, maxSize),
                Mathf.Clamp(localScale.z, minSize, maxSize));

            moveobj.localScale = scale;//赋值
            Debug.Log("大小: " + scale);

            //记住最新的触摸点位置,下次使用  
            oldPos1 = touch1.position;
            oldPos2 = touch2.position;
        }

        if (touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended)
        {
            touch1ID = -1;
            touch2ID = -1;
            istouch1 = false;
            istouch2 = false;
            Debug.Log("手指抬起2");
        }

        if (touch1.phase == TouchPhase.Canceled || touch2.phase == TouchPhase.Canceled)
        {
            touch1ID = -1;
            touch2ID = -1;
            istouch1 = false;
            istouch2 = false;
            Debug.Log("系统取消对触摸的跟踪2");
        }

    }

    #region 鼠标控制旋转和放大缩小

    //用于鼠标左键第一次按下时记录鼠标位置
    Vector2 _oldPos;
    public Vector2 _OldPos { get => _oldPos; set => _oldPos = value; }

    //左键控制旋转
    public void OnMuseButtonLeftRot()
    {
        Vector3 newRot = new Vector3(Input.mousePosition.y - _OldPos.y, -(Input.mousePosition.x - _OldPos.x), 0) * Time.deltaTime * rotSpeed;
        var rotation = Quaternion.Euler(newRot);
        moveobj.rotation *= rotation;
        //moveobj.eulerAngles = new Vector3(moveobj.eulerAngles.x, moveobj.eulerAngles.y, 0);
        //moveobj.eulerAngles = new Vector3(0, moveobj.eulerAngles.y, 0); //只让Y轴旋转
        _OldPos = Input.mousePosition;
        //Debug.Log("旋转");
    }

    //滑轮控制放大
    public void OnMuseButtonRightScale(float value)
    {
        //计算物体scale要放大的值
        Vector3 localScale = moveobj.localScale + Vector3.one * value;

        //设置放大缩小的范围值
        Vector3 scale = new Vector3(Mathf.Clamp(localScale.x, minSize, maxSize),
            Mathf.Clamp(localScale.y, minSize, maxSize),
            Mathf.Clamp(localScale.z, minSize, maxSize));

        moveobj.localScale = scale;//赋值
        //Debug.Log("大小: " + scale);

    }
    #endregion

    public void BtnEvent()
    {
        bool isSelect = true;
        //双击选中模型放大
        if (Time.realtimeSinceStartup - spaceTimer <= 0.5f)
        {
            Debug.Log("shuangji");
            isSelect = !isSelect;
            transform.GetComponent<BoxCollider>().enabled = isSelect;

            //moveobj.eulerAngles = originRot;
            //moveobj.localScale = originScale;
        }
    }

}

Four models, all set up like this, require four touchItems and four models


In the data part below, the left side is fixed text, and the right side is related to the answer. In the answer part, explanations are given.


3. Answer part

The overall logic of the answering part is the same as the previous answering system.

The difference here is that four different question banks are displayed at the same time, so the game object linked to each code corresponds to a question bank, so when reading the xml file, a new mQuestionPanel must be created, and each code corresponds to an xml file.

Then a json is added to store the number of participants and the correct answer rate, and four json files are generated in streamingAssets.

code show as below

using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
/// <summary>
/// 答题部分(含首界面参与人数和正确率的json存储)
/// </summary>
//将类序列化到文件中,同时序列化到编辑器中
[System.Serializable]
public class PlayerCoin
{
    public float count;
    public string name;
}

//存储一系列类数据,必须创建一个链表,链表必须存在在类中,才能被序列化
public class PlayerCoinList
{
    public List<PlayerCoin> playerCoinList = new List<PlayerCoin>();
}

public class Panel_Question : MonoBehaviour
{
    #region 在编辑器中添加的内容
    [Header("root界面: 答题界面 ")]
    [SerializeField] GameObject answerRoot;

    [Header("按钮:提交")]
    [SerializeField] Button submitBtn;

    [Header(" 题型图片")]
    [SerializeField] Image QTImg;
    [Header("单选题 多选题 判断题")]
    [SerializeField] List<Sprite> QTSprites;

    [Header("文本:题目序号 解析内容 ")]
    [SerializeField] Text questionID;
    [SerializeField] Text analysisData;

    [Header("内容scroll的content  选项scroll的content*2  下方选项的父物体 ")]
    [SerializeField] RectTransform contentScrollContent;
    [SerializeField] RectTransform questionBtnRoot;
    [SerializeField] RectTransform selectContent;
    [SerializeField] RectTransform XiaFangOptions;

    [SerializeField] ToggleGroup questionGroup;

    [Header("下方模型界面 下方答题界面 模型")]
    [SerializeField] GameObject belowModel;
    [SerializeField] GameObject belowAnswer;
    [SerializeField] GameObject model;

    [Header("一个人的正确率 全部人员的综合正确率 正确率的圆环")]
    public Text correctNum;      //一个人的正确率
    public Text allCorrectNum;   //全部人员的综合正确率
    public Image correctImg;  //正确率的圆环
    public Image allCorrectImg;  //正确率的圆环
    #endregion

    public PlayerCoinList list = new PlayerCoinList();
    PlayerCoin joinNumData;      //保存参与人数的数据
    PlayerCoin correctData;      //保存巫师
    PlayerCoin allCorrectData;      //保存巫师
    PlayerCoin sumData;      //保存巫师

    public Text joinNum;     //骑士的金币数量的显示文字

    // 答题界面数据内容
    QuestionPanelData mQuestionPanelData;
    QuestionPanel mQuestionPanel;
    // 每一道题的题目内容
    QuestionData mQuestionData;
    // 题目内容物体
    GameObject mQuestion;
    // 选项的链表
    List<Options> options = new List<Options>();
    List<Options> options1 = new List<Options>();

    List<int> randomNum = new List<int>();  //存放随机数

    int index = 0;      //题目计数
    string path;        //题目路径

    public List<QuestionPanelData> questionPanelData;
    public List<QuestionPanel> questionPanel;

    #region 单例和初始化
    static Panel_Question instance;

    public static Panel_Question GetInstance()
    {
        return instance;
    }

    private void Awake()
    {
        //按钮监听
        submitBtn.onClick.AddListener(submitClick);
        path = "file://" + Application.dataPath + "/StreamingAssets/" + gameObject.name + ".xml";
    }
    #endregion

    #region Start和Update
    private void Start()
    {
        StartCoroutine(LoadingQuesiton(path));
        //Debug.Log(path);
        //设置多选字段为空
        StringToNull();

        //默认提交按钮不能使用,没有提交
        submitBtn.interactable = false;
        //GenerateData();
        //数据的读取
        LoadDate();
    }

    string[] optionContent;
    string temp;

    //多选的每个选项
    string optionA = "";
    string optionB = "";
    string optionC = "";
    string optionD = "";
    bool isSub;     //是否点击了提交按钮
    private void Update()
    {
        //遍历上方所有选项,设置提交按钮能否使用
        foreach (var item in options)
        {
            //题型图片的设置
            if (mQuestionData.answerData.Count == 4)
            {
                if (mQuestionData.IsSingleChoice)//单选图片
                {
                    QTImg.sprite = QTSprites[0];
                }
                else                            //多选图片
                {
                    QTImg.sprite = QTSprites[1];
                }
            }
            else if (mQuestionData.answerData.Count == 2)//判断图片
            {
                QTImg.sprite = QTSprites[2];
            }

            //提取选项
            optionContent = item.optionText.GetComponent<Text>().text.Split('.');

            //题目判断
            if (item.thisToggle.isOn)
            {
                if (!isSub)
                {
                    submitBtn.interactable = true;
                    isSub = true;
                }
                //如果是单选的话,直接把正确答案跟选择的答案比较
                if (mQuestionData.IsSingleChoice)
                {
                    temp = optionContent[0];
                }
                else
                {
                    if (optionContent[0] == "A")
                        optionA = "A";
                    else if (optionContent[0] == "B")
                        optionB = "B";
                    else if (optionContent[0] == "C")
                        optionC = "C";
                    else if (optionContent[0] == "D")
                        optionD = "D";
                    temp = optionA + optionB + optionC + optionD;
                }
            }
            else
            {
                if (!mQuestionData.IsSingleChoice)
                {
                    if (optionContent[0] == "A")
                        optionA = "";
                    else if (optionContent[0] == "B")
                        optionB = "";
                    else if (optionContent[0] == "C")
                        optionC = "";
                    else if (optionContent[0] == "D")
                        optionD = "";
                    temp = optionA + optionB + optionC + optionD;
                    Debug.Log("多选2" + temp);
                }
            }

        }

        //遍历下方所有选项,设置提交按钮能否使用
        foreach (var item in options1)
        {
            //题型图片的设置
            if (mQuestionData.answerData.Count == 4)
            {
                if (mQuestionData.IsSingleChoice)//单选图片
                {
                    QTImg.sprite = QTSprites[0];
                }
                else                            //多选图片
                {
                    QTImg.sprite = QTSprites[1];
                }
            }
            else if (mQuestionData.answerData.Count == 2)//判断图片
            {
                QTImg.sprite = QTSprites[2];
            }

            //提取选项
            optionContent = item.optionText.GetComponent<Text>().text.Split('.');

            //题目判断
            if (item.thisToggle.isOn)
            {
                if (!isSub)
                {
                    submitBtn.interactable = true;
                    isSub = true;
                }
                //如果是单选的话,直接把正确答案跟选择的答案比较
                if (mQuestionData.IsSingleChoice)
                {
                    temp = optionContent[0];
                }
                else
                {
                    if (optionContent[0] == "A")
                        optionA = "A";
                    else if (optionContent[0] == "B")
                        optionB = "B";
                    else if (optionContent[0] == "C")
                        optionC = "C";
                    else if (optionContent[0] == "D")
                        optionD = "D";
                    temp = optionA + optionB + optionC + optionD;
                }
            }
            else
            {
                if (!mQuestionData.IsSingleChoice)
                {
                    if (optionContent[0] == "A")
                        optionA = "";
                    else if (optionContent[0] == "B")
                        optionB = "";
                    else if (optionContent[0] == "C")
                        optionC = "";
                    else if (optionContent[0] == "D")
                        optionD = "";
                    temp = optionA + optionB + optionC + optionD;
                    Debug.Log("多选2" + temp);
                }
            }

        }
    }
    #endregion

    #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);
            //答题panel数据类的赋值
            mQuestionPanel = new QuestionPanel(doc.FirstChild);
        }
    }
    #endregion

    #region 初始化第一道题
    public void InitQuestionPanel(QuestionPanelData questionPanelData)
    {
        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);

        totalNum = mQuestionPanelData.questionData.Count;
        //Debug.Log(totalNum);

        if (mQuestion != null)
        {
            Destroy(mQuestion);
        }

        //实例化题目预制体
        mQuestion = Instantiate(Resources.Load<GameObject>(QuestionText), 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);
            }
        }

        if (options1.Count > 0)
        {
            for (int i = 0; i < options1.Count; i++)
            {
                Destroy(options1[i].gameObject);
            }
        }
        options = new List<Options>();
        options1 = new List<Options>();

        //实例化选项预制体
        for (int i = 0; i < questionData.answerData.Count; i++)
        {
            Options option = Instantiate(Resources.Load<Options>("Options"), selectContent);
            Options option1 = Instantiate(Resources.Load<Options>("Options1"), XiaFangOptions);

            option.Init(questionData.answerData[i]);
            option1.Init(questionData.answerData[i]);

            option1.optionText.text = option1.optionText.text.Split('.')[0];

            //如果是单选则设置为一个toggle组
            if (questionData.IsSingleChoice)
            {
                option.thisToggle.group = questionGroup;
                option1.thisToggle.group = questionGroup;
            }

            options.Add(option);
            options1.Add(option1);

        }
        for (int i = 0; i < options.Count; i++)
        {
            options[i].GetComponent<RectTransform>().localScale = new Vector3(1, 1, 1);
            options1[i].GetComponent<RectTransform>().localScale = new Vector3(1, 1, 1);
        }
    }
    #endregion

    #region 开始答题
    public string QuestionText;
    int totalNum;
    // 开始答题
    public void StartAnswer()
    {
        //读取xml文件
        StartCoroutine(LoadingQuesiton(path));

        //题目和答案的读取
        for (int i = 0; i < mQuestionPanel.questionPanelData.Count; i++)
        {
            InitQuestionPanel(mQuestionPanel.questionPanelData[i]);
        }

    }
    #endregion

    #region 下一题
    private void nextClick()
    {
        if (index < mQuestionPanelData.questionData.Count - 1)
        {
            index++;
            CreateQuestion(mQuestionPanelData.questionData[index]);
        }

        //设置提交按钮只能点击一次
        submitBtn.interactable = false;
        isSub = false;

    }
    #endregion

    #region 题目提交事件
    int score = 0;          //题目正确时的得分
    string rightAnswer;     //正确选项的字符串
    float sum = 0;          //所有正确率的和
    private void submitClick()
    {
        isSub = true;
        //遍历上方题目的选项,有选择的就可以提交核验答案,并显示解析内容
        foreach (var item in options)
        {
            if (item.thisToggle.isOn)
            {
                rightAnswer = "";
                for (int i = 0; i < mQuestionData.answerData.Count; i++)
                {
                    switch (i)
                    {
                        case 0:
                            if (mQuestionData.answerData[i].Score > 0)//xml文档里面score属性对应的数值是用来判断该选项是否为正确选项
                            {
                                rightAnswer += "A";
                            }
                            break;
                        case 1:
                            if (mQuestionData.answerData[i].Score > 0)
                            {
                                rightAnswer += "B";
                            }
                            break;
                        case 2:
                            if (mQuestionData.answerData[i].Score > 0)
                            {
                                rightAnswer += "C";
                            }
                            break;
                        case 3:
                            if (mQuestionData.answerData[i].Score > 0)
                            {
                                rightAnswer += "D";
                            }
                            break;
                    }
                }
            }
            //选择一个选项之后不能在选择其他选项
            item.thisToggle.interactable = false;
        }

        //遍历下方题目的选项,有选择的就可以提交核验答案,并显示解析内容
        foreach (var item in options1)
        {
            if (item.thisToggle.isOn)
            {
                rightAnswer = "";
                for (int i = 0; i < mQuestionData.answerData.Count; i++)
                {
                    switch (i)
                    {
                        case 0:
                            if (mQuestionData.answerData[i].Score > 0)//xml文档里面score属性对应的数值是用来判断该选项是否为正确选项
                            {
                                rightAnswer += "A";
                            }
                            break;
                        case 1:
                            if (mQuestionData.answerData[i].Score > 0)
                            {
                                rightAnswer += "B";
                            }
                            break;
                        case 2:
                            if (mQuestionData.answerData[i].Score > 0)
                            {
                                rightAnswer += "C";
                            }
                            break;
                        case 3:
                            if (mQuestionData.answerData[i].Score > 0)
                            {
                                rightAnswer += "D";
                            }
                            break;
                    }
                }
            }
            //选择一个选项之后不能在选择其他选项
            item.thisToggle.interactable = false;
        }

        //题目正确与否的判断
        if (rightAnswer == temp)
        {
            //把多选的字符串置空
            StringToNull();
            analysisData.text = String.Format("正确");
            score += 1;
        }
        else
        {
            //错误数量计数
            //把多选的字符串置空
            StringToNull();
            analysisData.text = String.Format("很遗憾,答错了!正确答案是:{0}\n", rightAnswer);
        }

        //设置提交按钮不能使用
        submitBtn.interactable = false;

        //如果当前题目是最后一题,提交之后,返回模型界面   
        if (index + 1 == mQuestionPanelData.questionData.Count)
        {
            //参与人数增加和数据的存储
            joinNumData.count += 1;
            joinNum.text = "参与人数:" + joinNumData.count.ToString();

            Debug.Log("这是最后一题,界面消失");
            if (totalNum != 0)
            {
                float numTemp = (score * 1.00f / totalNum) * 100;
                correctData.count = Mathf.Round((score * 1.00f / totalNum) * 100);
                correctNum.text = correctData.count.ToString() + "%";
                correctImg.fillAmount = correctData.count / 100;

                sumData.count += correctData.count;
                allCorrectData.count = (Mathf.Round(sumData.count / joinNumData.count));
                allCorrectNum.text = allCorrectData.count.ToString() + "%";
                Debug.Log(allCorrectNum.text);
                allCorrectImg.fillAmount = (sumData.count / joinNumData.count) / 100;
            }
            //数据的存储
            SaveData();
            Invoke("BackToMain", 3);
        }
        else                        //如果不是,三秒后跳转到下一题
            Invoke("nextClick", 3);

        //提交后,该题目不可再选择修改
        submitBtn.interactable = false;
    }
    #endregion

    #region 返回模型界面
    void BackToMain()
    {
        //计数归零
        index = 0;
        score = 0;
        num = 0;

        //提交按钮的初始化
        submitBtn.interactable = false;
        isSub = false;

        //界面的显示与隐藏
        belowModel.SetActive(true);
        belowAnswer.SetActive(false);
        model.SetActive(true);

        transform.GetChild(3).gameObject.SetActive(false);
        transform.GetChild(2).gameObject.SetActive(true);
    }
    #endregion

    #region 多选字符串归零
    void StringToNull()
    {
        optionA = "";
        optionB = "";
        optionC = "";
        optionD = "";
    }
    #endregion

    #region 随机顺序出题(这里没用到)
    public void GetRandomNum()
    {
        //利用哈希函数获取随机数
        HashSet<int> nums = new HashSet<int>();
        System.Random r = new System.Random();
        while (nums.Count != 9)
        {
            nums.Add(r.Next(0, 9));
        }
        //Debug.Log(topicMax);
        foreach (var item in nums)
        {
            randomNum.Add(item);
            Debug.Log(item);
        }
    }

    #endregion

    #region 生成实例并赋初值
    void GenerateData()
    {
        joinNumData = new PlayerCoin();
        joinNumData.count = 0;
        joinNumData.name = "joinNum";

        correctData = new PlayerCoin();
        correctData.count = 0;
        correctData.name = "correct";

        allCorrectData = new PlayerCoin();
        allCorrectData.count = 0;
        allCorrectData.name = "allCorrect";

        sumData = new PlayerCoin();
        sumData.count = 0;
        sumData.name = "sum";

        list.playerCoinList.Add(joinNumData);
        list.playerCoinList.Add(correctData);
        list.playerCoinList.Add(allCorrectData);
        list.playerCoinList.Add(sumData);
    }
    #endregion



    #region 数据存储
    void SaveData()
    {
        //将list转化成一个json文件
        string json = JsonUtility.ToJson(list, true);
        //设置保存的路径
        string filePath = Application.streamingAssetsPath + "/playCoinList" + gameObject.name + ".json"; ;
        //文件的写入
        using (StreamWriter sw = new StreamWriter(filePath))
        {
            sw.WriteLine(json);
            sw.Close();
            sw.Dispose();
        }
    }

    #endregion



    #region 数据的读取

    void LoadDate()
    {
        string json;
        string filePath = Application.streamingAssetsPath + "/playCoinList" + gameObject.name + ".json";

        //检测json文件是否存在
        if (File.Exists(filePath))
        {
            //json文件存在,直接进行数据读取
            using (StreamReader sr = new StreamReader(filePath))
            {
                json = sr.ReadToEnd();
                sr.Close();
            }
            //将json文件转化为内存中的一个变量
            list = JsonUtility.FromJson<PlayerCoinList>(json);

            //将读取的数据赋值
            joinNumData = list.playerCoinList[0];
            correctData = list.playerCoinList[1];
            allCorrectData = list.playerCoinList[2];
            sumData = list.playerCoinList[3];

            //更新文本显示
            joinNum.text = "参与人数:" + joinNumData.count.ToString();
            correctNum.text = correctData.count.ToString() + "%";
            correctImg.fillAmount = correctData.count / 100;

            allCorrectData.count = (Mathf.Round(sumData.count / (joinNumData.count)));
            allCorrectNum.text = allCorrectData.count.ToString() + "%";
            Debug.Log(allCorrectData.count);
            allCorrectImg.fillAmount = (sumData.count / joinNumData.count) / 100;
        }
        else
        {
            //json文件不存在,先创建,再进行读取
            GenerateData();
        }


    }
    #endregion
}

#region 答题数据类
// 答题panel数据类
public class QuestionPanel
{
    public 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]));
            //Debug.Log(questionPanelData);
        }
    }
}

// 答题界面数据类
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]));
        }
    }
}

// 题目数据类
public class QuestionData
{
    // 是否为单选,true为单选,false为多选
    private bool isSingleChoice;
    // 解析内容
    public string Analysis;
    // 题目内容
    public string problem;
    public List<AnswerData> answerData;

    public bool IsSingleChoice { get => isSingleChoice; set => isSingleChoice = value; }

    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]));
        }
    }
}

// 答案数据类
public class AnswerData
{
    // 选项的内容
    public string option;
    // 选项对应的分数
    public int Score;
    public AnswerData(XmlNode node)
    {
        option = node.Attributes["option"].InnerText;
        Score = int.Parse(node.InnerText);
    }
}
#endregion

 4. Interface switching part control

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 三个按钮的管理器
/// </summary>
public class MainManager : MonoBehaviour
{
    [Header("人文历史按钮 模型按钮 答题按钮")]
    [SerializeField] Button historyBtn;
    [SerializeField] Button modelBtn;
    [SerializeField] Button answerBtn;

    [Header("中间part面板:人文历史部分 模型部分 答题部分 模型所在位置")]
    public GameObject historyPart;
    public GameObject modelPart;
    public GameObject answerPart;
    public GameObject modelRoot;

    [Header("下方部分:人文历史部分 模型部分 答题部分")]
    public GameObject belowHistoryPart;
    public GameObject belowModelPart;
    public GameObject belowAnswerPart;

    [SerializeField] Slider slider;
    static MainManager instance;

    public static MainManager GetInstance()
    {
        return instance;
    }

    void Awake()
    {
        //按钮监听
        historyBtn.onClick.AddListener(HistoryEvent);
        modelBtn.onClick.AddListener(ModelEvent);
        answerBtn.onClick.AddListener(AnswerEvent);

        //默认界面显示
        ModelEvent();

        instance = this;
    }

    #region 按钮事件
    void HistoryEvent()
    {
        historyPart.SetActive(true);
        belowHistoryPart.SetActive(true);

        modelPart.SetActive(false);
        belowModelPart.SetActive(false);
        modelRoot.SetActive(false);

        answerPart.SetActive(false);
        belowAnswerPart.SetActive(false);

    }

    public void ModelEvent()
    {
        historyPart.SetActive(false);
        belowHistoryPart.SetActive(false);

        modelPart.SetActive(true);
        belowModelPart.SetActive(true);
        modelRoot.SetActive(true);

        answerPart.SetActive(false);
        belowAnswerPart.SetActive(false);

    }

    void AnswerEvent()
    {
        historyPart.SetActive(false);
        belowHistoryPart.SetActive(false);

        modelPart.SetActive(false);
        belowModelPart.SetActive(false);
        modelRoot.SetActive(false);

        answerPart.SetActive(true);
        belowAnswerPart.SetActive(true);

        slider.value += 0.01f;
    }
    #endregion
}

 5. Instructions for use

 

(I don’t want to write it until later. I will add what is needed in the future) 

Guess you like

Origin blog.csdn.net/shijinlinaaa/article/details/132868960