This commit is contained in:
李浩 2025-04-08 19:09:05 +08:00
commit 9a1ed664b6
16 changed files with 4488 additions and 24 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3e4645aaac3d48d4896ad6e7b2a1f1cc
PrefabImporter:
externalObjects: {}
userData:
assetBundleName: uiknowledge_prefab
assetBundleVariant:

View File

@ -141,7 +141,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!114 &135073410
MonoBehaviour:
m_ObjectHideFlags: 0
@ -408,8 +408,8 @@ RectTransform:
m_Children: []
m_Father: {fileID: 1437752464}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 0.92707926}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 20, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
@ -562,9 +562,9 @@ RectTransform:
m_Father: {fileID: 1886396042}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_SizeDelta: {x: -17, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!114 &1347660168
MonoBehaviour:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 13457db631332b149901c3d79f802d84
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -27,6 +27,7 @@ public class ActionHelper
{ "UI3DObjSelect", typeof(QFramework.Example.UI3DObjSelect) },
{ "UITextTip", typeof(QFramework.Example.UITextTip) },
{ "UITextWindow", typeof(QFramework.Example.UITextWindow) },
{ "UIKnowledge", typeof(QFramework.Example.UIKnowledge) },
};

View File

@ -35,7 +35,6 @@ namespace QFramework.Example
{
Point.anchoredPosition = Utility.GetScreenPosByObj(transform as RectTransform);
}
}
#endif

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 762d12b9d2c220c46afe6eb3eda2e85c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,67 @@
using System;
using UnityEngine;
using UnityEngine.UI;
using QFramework;
namespace QFramework.Example
{
// Generate Id:d21887cc-bea5-4c87-8eae-a1d693d6555a
public partial class UIKnowledge
{
public const string Name = "UIKnowledge";
[SerializeField]
public UnityEngine.UI.Button CloseBtn;
[SerializeField]
public RectTransform LeftContent;
[SerializeField]
public UnityEngine.UI.ScrollRect Right;
[SerializeField]
public UnityEngine.UI.Image RightContent;
[SerializeField]
public RectTransform GlobalComs;
[SerializeField]
public RectTransform ItemComs;
[SerializeField]
public RectTransform LeftItem;
[SerializeField]
public UnityEngine.UI.Button BtnPrefab;
private UIKnowledgeData mPrivateData = null;
protected override void ClearUIComponents()
{
CloseBtn = null;
LeftContent = null;
Right = null;
RightContent = null;
GlobalComs = null;
ItemComs = null;
LeftItem = null;
BtnPrefab = null;
mData = null;
}
public UIKnowledgeData Data
{
get
{
return mData;
}
}
UIKnowledgeData mData
{
get
{
return mPrivateData ?? (mPrivateData = new UIKnowledgeData());
}
set
{
mUIData = value;
mPrivateData = value;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9a5d5c0eba3097b48b9c67e7e229ccee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,198 @@
using UnityEngine;
using UnityEngine.UI;
using QFramework;
using TMPro;
using System.Collections.Generic;
using System;
namespace QFramework.Example
{
public class UIKnowledgeData : UIPanelData
{
public XMLTool.Knowledge knowledge;
}
public partial class UIKnowledge : UIPanel
{
ResLoader loader;
Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>();
IAction curAction;
protected override void OnInit(IUIData uiData = null)
{
mData = uiData as UIKnowledgeData ?? new UIKnowledgeData();
// please add init code here
loader = ResLoader.Allocate();
CloseBtn.onClick.AddListener(() =>
{
Hide();
});
}
protected override void OnOpen(IUIData uiData = null)
{
if (Global.Instance.curModule.knowledge != null && Global.Instance.curModule.knowledge.items != null)
{
LeftContent.RemoveAllChildren();
string bg = Global.Instance.curModule.knowledge.bgImage;
LoadBgImage(bg, () =>
{
SetRightContentPos("");
RefreshComponents(Global.Instance.curModule.knowledge.components, GlobalComs);
});
foreach (var item in Global.Instance.curModule.knowledge.items)
{
ItemFactory(item);
}
}
}
public void ItemFactory(XMLTool.Knowledge.Item itemData, Transform parent = null)
{
Transform content = parent == null ? LeftContent : parent;
GameObject leftObj = GameObject.Instantiate(LeftItem.gameObject, content);
Transform subContent = leftObj.transform.Find("SubContent");
Toggle toggle = leftObj.transform.Find("Toggle").GetComponent<Toggle>();
TextMeshProUGUI label = toggle.transform.Find("Name").GetComponent<TextMeshProUGUI>();
label.text = itemData.title;
toggle.onValueChanged.AddListener(isOn =>
{
if (isOn)
{
LoadBgImage(itemData.bgImage, () =>
{
SetRightContentPos(itemData.setPos);
});
ItemComs.RemoveAllChildren();
RefreshComponents(itemData.components, ItemComs);
}
if (subContent.childCount > 0)
{
subContent.gameObject.SetActive(isOn);
if (isOn)
{
subContent.GetChild(0).GetComponentInChildren<Toggle>().isOn = true;
}
}
else
{
label.color = isOn == true ? Color.black : Color.white;
}
});
if (itemData.subs != null && itemData.subs.Count > 0)
{
foreach (var sub in itemData.subs)
{
ItemFactory(sub, subContent);
}
}
else
{
toggle.group = LeftContent.GetComponent<ToggleGroup>();
}
}
/// <summary>
/// ˢе±Ç°Ò³ÃæµÄ¹Ò¼þ
/// </summary>
public void RefreshComponents(List<XMLTool.Knowledge.Item.Component> coms, Transform content)
{
if (coms != null && coms.Count > 0)
{
foreach (var ComData in coms)
{
switch (ComData.type)
{
case "Button":
GameObject btn = GameObject.Instantiate(BtnPrefab.gameObject, content);
btn.GetComponent<RectTransform>().sizeDelta = Utility.GetVector2FromStrArray(ComData.size);
btn.transform.localPosition = Utility.GetVector2FromStrArray(ComData.pos);
btn.GetComponent<Button>().onClick.AddListener(() =>
{
if (curAction != null)
{
curAction.Deinit();
curAction = null;
}
curAction = ActionHelper.GetActionAndSub(ComData.action);
curAction.StartGlobal(() =>
{
curAction = null;
});
});
break;
}
}
}
}
public void LoadBgImage(string bg, Action callback = null)
{
if (string.IsNullOrEmpty(bg) == false)
{
if (sprites.ContainsKey(bg))
{
RightContent.sprite = sprites[bg];
RightContent.SetNativeSize();
callback?.Invoke();
}
else
{
var localImageUrl = Global.imagePath + bg;
loader.Add2Load(localImageUrl.ToNetImageResName(), (success, res) =>
{
if (success)
{
Sprite sprite = Utility.GetSprite(res.Asset.As<Texture2D>());
if (sprites.ContainsKey(bg) == false)
{
sprites.Add(bg, sprite);
}
}
});
TypeEventSystem.Global.Send<OnLoadingShow>();
loader.LoadAsync(() =>
{
callback?.Invoke();
RightContent.sprite = sprites[bg];
RightContent.SetNativeSize();
TypeEventSystem.Global.Send<OnLoadingHide>();
});
}
}
else
{
callback?.Invoke();
}
}
public void SetRightContentPos(string setPos)
{
Vector2 pos = default;
if (string.IsNullOrEmpty(setPos) == false)
{
pos = Utility.GetVector2FromStrArray(setPos);
}
RightContent.rectTransform.anchoredPosition = pos;
}
protected override void OnShow()
{
}
protected override void OnHide()
{
}
protected override void OnClose()
{
sprites.Clear();
loader.ReleaseAllRes();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fd25ee86b2071da4aa68360bc13232e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,7 +1,11 @@
using QFramework;
using QFramework.Example;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using UnityEngine;
using static XMLTool.Body3D;
namespace XMLTool
@ -42,6 +46,8 @@ namespace XMLTool
public Score score;
public Body3D body3d;
public Knowledge knowledge;
}
public class Device
@ -215,6 +221,32 @@ namespace XMLTool
public string isOff;
}
public class Knowledge
{
public class Item
{
public class Component
{
public string type;
public string size;
public string pos;
public Action action;
}
public string title;
public string bgImage;
public string setPos;
public List<Item> subs;
public List<Component> components;
}
public string bgImage;
public List<Item> items;
public List<Item.Component> components;
}
public class XmlParser
{
public static AppData ParseXml(string xmlString)
@ -390,6 +422,7 @@ namespace XMLTool
module.body3d.parts.Add(part.Name, part);
}
}
// 解析评分
XElement scoreNode = moduleElement.Element("Score");
if (scoreNode != null)
{
@ -409,8 +442,66 @@ namespace XMLTool
});
}
}
// 解析知识点
var knowledge = moduleElement.Element("Knowledge");
if (knowledge != null)
{
module.knowledge = new Knowledge();
module.knowledge.bgImage = knowledge.Attribute("bgImage")?.Value;
foreach (var itemXml in knowledge.Elements("Item"))
{
Knowledge.Item item = ParserKnowledgeItem(itemXml);
if (module.knowledge.items == null)
{
module.knowledge.items = new List<Knowledge.Item>();
}
module.knowledge.items.Add(item);
}
module.knowledge.components = ParserKnowledgeComponet(knowledge);
}
}
}
private static Knowledge.Item ParserKnowledgeItem(XElement itemXml)
{
Knowledge.Item item = new Knowledge.Item();
item.title = itemXml.Attribute("title")?.Value;
item.bgImage = itemXml.Attribute("bgImage")?.Value;
item.setPos = itemXml.Attribute("setPos")?.Value;
item.components = ParserKnowledgeComponet(itemXml);
foreach (var subXml in itemXml.Elements("Item"))
{
if (item.subs == null)
{
item.subs = new List<Knowledge.Item>();
}
// 增加子物体
item.subs.Add(ParserKnowledgeItem(subXml));
}
return item;
}
private static List<Knowledge.Item.Component> ParserKnowledgeComponet(XElement xmlData)
{
List<Knowledge.Item.Component> list = null;
foreach (var componentXml in xmlData.Elements("Component"))
{
if (list == null)
{
list = new List<Knowledge.Item.Component>();
}
Knowledge.Item.Component component = new Knowledge.Item.Component();
component.type = componentXml.Attribute("type")?.Value;
component.pos = componentXml.Attribute("pos")?.Value;
component.size = componentXml.Attribute("size")?.Value;
component.action = ParseAction(componentXml.Element("Action"));
list.Add(component);
}
return list;
}
private static Body3D.Body ParseBody(XElement bodyElement, Body parent = null)
{
Body3D.Body body = new Body3D.Body

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 MiB

View File

@ -10,22 +10,143 @@
<Enter>
<Action type="Parallel">
<Action type="UIShow" value="UIKnowledge" isShow="true"></Action>
</Action>
</Enter>
</State>
<Transision from="初始状态" to="状态2">
</Transision>
<!--<Transision from="初始状态" to="状态2">
<Condition type="ObjClick" value="Cube (1)"></Condition>
</Transision>-->
</FSM>
<Knowledge bgImage="Knowledge/ChangTu.png">
<Item title="第一步" setPos="0,0">
<Item title="第一步_第一个子步骤" bgImage="" setPos="0,100">
<Component type="Button" size="200,200" pos="200,-200">
<Action type="Log" value="第二步_第二个子步骤"></Action>
</Component>
<Component type="Button" size="200,200" pos="400,-200">
<Action type="Log" value="第二步_第二个子步骤"></Action>
</Component>
</Item>
</Item>
<Item title="第二步" setPos="0,400">
<Item title="第二步_第一个子步骤" bgImage="" setPos="0,500">
<Component type="Button" size="200,200" pos="200,-400">
<Action type="Log" value="第二步_第二个子步骤"></Action>
</Component>
<Component type="Button" size="200,200" pos="400,-400">
<Action type="Log" value="第二步_第二个子步骤"></Action>
</Component>
</Item>
<Item title="第二步_第二个子步骤" bgImage="" setPos="0,600"></Item>
</Item>
<Component type="Button" size="932,526" pos="20,-9653">
<Action type="Sequence">
<Action type="Log" value="第一步_第一个子步骤"></Action>
<Action type="Video" value="test.mp4" size="500,500" offset="10,10" finishedEvent="finished" closeEvent="close"></Action>
</Action>
</Component>
<Descript>
安徽非遗资源丰富涵盖民间文学、传统音乐、传统舞蹈、传统戏剧、曲艺、传统体育游艺与杂技、传统美术、传统技艺、民俗等多个类别。虚拟仿真系统高度还原了安徽特色非物质文化遗产美术场馆通过三维建模的形式对单反、摄像机、三角架、绿幕摄影器材进行讲解。学生在了解摄影器材基础后再学习镜头语言景别、镜号、摄影技巧相关理论知识。最后学生可在非遗美术场馆自主漫游调用摄影器材进行拍摄可灵活调整摄影器材拍摄位置、拍摄角度、曝光、ISO等相关参照相机会实时显示当前拍摄影像拍摄结束后仿真系统会导出当前拍摄视频可供下载观看。通过本仿真实验减少了对真实场景搭建、道具制作和运输等方面的投入并能够取得良好的摄影拍摄教学培训效果。
</Descript>
</Knowledge>
<!--<Body3D>
<Body name="头颈" icon="" path="Ren/Tou" >
<Body name="骨骼系统" path="Ren/Tou/GuGe" isShow="false">
<Body name="肋骨" path="Ren/Tou/GuGe/LeiGu">
<Body name="左肋" path="Ren/Tou/GuGe/LeiGu/ZuoLei">
<Body name="左一" path="Ren/Tou/GuGe/LeiGu/ZuoLei/1" tip="左一肋骨描述">
<ObjectToggle>
<Color isOn="0,255,255" isOff="255,255,255"></Color>
</ObjectToggle>
</Body>
<Body name="左二" path="Ren/Tou/GuGe/LeiGu/ZuoLei/2" tip="左二肋骨描述">
<ObjectToggle>
<Color isOn="0,255,255" isOff="255,255,255"></Color>
</ObjectToggle>
</Body>
</Body>
<Body name="右肋" path="Ren/Tou/GuGe/LeiGu/YouLei">
<Body name="右一" path="Ren/Tou/GuGe/LeiGu/YouLei/1" tip="7右一肋骨描述">
<ObjectToggle>
<Color isOn="0,255,255" isOff="255,255,255"></Color>
</ObjectToggle>
</Body>
<Body name="右二" path="Ren/Tou/GuGe/LeiGu/YouLei/2" tip="右二肋骨描述">
<ObjectToggle>
<Color isOn="0,255,255" isOff="255,255,255"></Color>
</ObjectToggle>
</Body>
</Body>
</Body>
</Body>
<Body name="皮肤系统" path="Ren/Tou/PiFu" isShow="false">
<Body name="肋骨" path="Ren/Tou/PiFu/LeiGu">
<Body name="左肋" path="Ren/Tou/PiFu/LeiGu/ZuoLei">
<Body name="左一" path="Ren/Tou/PiFu/LeiGu/ZuoLei/1"></Body>
<Body name="左二" path="Ren/Tou/PiFu/LeiGu/ZuoLei/2"></Body>
</Body>
<Body name="右肋" path="Ren/Tou/PiFu/LeiGu/YouLei">
<Body name="右一" path="Ren/Tou/PiFu/LeiGu/YouLei/1"></Body>
<Body name="右二" path="Ren/Tou/PiFu/LeiGu/YouLei/2"></Body>
</Body>
</Body>
</Body>
<Body name="肌肉" isBodyList="true" path="Ren/Tou/JiRou">
<Body name="111" path="Ren/Tou/JiRou/1">
<ObjectToggle>
<Color></Color>
</ObjectToggle>
</Body>
<Body name="222" path="Ren/Tou/JiRou/2">
<ObjectToggle>
<Color></Color>
</ObjectToggle>
</Body>
<Body name="333" path="Ren/Tou/JiRou/3">
<ObjectToggle>
<Color></Color>
</ObjectToggle>
</Body>
</Body>
-->
<!--<Body name="神经" isBodyList="true">
<Body name="aaa" path="Ren/Tou/ShenJing/1">
<ObjectToggle>
<Color></Color>
</ObjectToggle>
</Body>
<Body name="bbb" path="Ren/Tou/ShenJing/2">
<ObjectToggle>
<Color></Color>
</ObjectToggle>
</Body>
<Body name="ccc" path="Ren/Tou/ShenJing/3">
<ObjectToggle>
<Color></Color>
</ObjectToggle>
</Body>
</Body>-->
<!--
</Body>
<Body name="肩膀" icon="" path="Ren/JianBang" >
<Body name="肩膀系统1" path="Ren/JianBang/Cube">
<Body name="肋骨" path="Ren/JianBang/Cube/Cube (1)">
<Body name="左肋" path="Ren/JianBang/Cube/Cube (1)/Cube (2)">
<Body name="左一" path="Ren/JianBang/Cube/Cube (1)/Cube (2)/Cube (3)"></Body>
<Body name="左二" path="Ren/JianBang/Cube/Cube (1)/Cube (2)/Sphere"></Body>
</Body>
</Body>
</Body>
</Body>
</Body3D>-->
</Module>

View File

@ -338,6 +338,45 @@
</Step>
</Operation>
<!--知识点
title对应左侧树状图的名字
bgImage是右侧的长图
Component是长图上挂在的组件 目前仅支持Type=Button的按钮类型
Action是动作组 点击按钮后的动作
Component标签与bgImage属性 可以在根节点Knowledge上也可以在子节点Item上
位于根节点时 是全局的 位于Item节点时是切换Item后展示的针对与Item的
-->
<Knowledge bgImage="Knowledge/ChangTu.png">
<Item title="第一步" setPos="0,0">
<Item title="第一步_第一个子步骤" bgImage="" setPos="0,100">
<Component type="Button" size="200,200" pos="200,-200">
<Action type="Log" value="第二步_第二个子步骤"></Action>
</Component>
<Component type="Button" size="200,200" pos="400,-200">
<Action type="Log" value="第二步_第二个子步骤"></Action>
</Component>
</Item>
</Item>
<Item title="第二步" setPos="0,400">
<Item title="第二步_第一个子步骤" bgImage="" setPos="0,500">
<Component type="Button" size="200,200" pos="200,-400">
<Action type="Log" value="第二步_第二个子步骤"></Action>
</Component>
<Component type="Button" size="200,200" pos="400,-400">
<Action type="Log" value="第二步_第二个子步骤"></Action>
</Component>
</Item>
<Item title="第二步_第二个子步骤" bgImage="" setPos="0,600"></Item>
</Item>
<Component type="Button" size="932,526" pos="20,-9653">
<Action type="Sequence">
<Action type="Log" value="第一步_第一个子步骤"></Action>
<Action type="Video" value="test.mp4" size="500,500" offset="10,10" finishedEvent="finished" closeEvent="close"></Action>
</Action>
</Component>
</Knowledge>
<!--动作组-->
<Action name="初始化" type="Sequence">
@ -386,9 +425,9 @@
<Action type="Log" value="ddd"></Action>
</Action>
</Exit>
</State>-->
</State>
<Transision from="any" to="状态1">
<Condition type="ObjClick" value="Cube"></Condition>
<Condition type="UIClick" value="Cube"></Condition>
</Transision>
<Transision from="初始状态" to="状态2">
<Condition type="ObjClick" value="Cube (1)"></Condition>