1
0
Fork 0
LaboratoryProtection/Assets/UnityTest/功能模块/_2连线题/Scripts/UIWiring.cs

618 lines
20 KiB
C#

using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Triggers;
using PMaker.Await;
using PMaker.Extension;
using Sirenix.OdinInspector;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityEngine.UI.Extensions;
public class UIWiring : AwaitBehaviour
{
//#if UNITY_EDITOR
// private static bool DrawColoredEnumElement(Rect rect, bool value)
// {
// if (Event.current.type == EventType.MouseDown && rect.Contains(Event.current.mousePosition))
// {
// value = !value;
// GUI.changed = true;
// Event.current.Use();
// }
//#if UNITY_EDITOR
// UnityEditor.EditorGUI.DrawRect(rect.Padding(1), value ? new Color(0.1f, 0.8f, 0.2f) : new Color(0, 0, 0, 0.5f));
//#endif
// return value;
// }
// [TableMatrix(VerticalTitle = "序号", HorizontalTitle = "答案", DrawElementMethod = "DrawColoredEnumElement", ResizableColumns = false)]
// // 0 2 0 1 3
// public bool[,] answers;
//[Button]
//public void SetAnswers()
//{
// Debug.Log(answers.GetLength(0));
// var length = answers.GetLength(0);
// intAnswers = new int[length];
// for (int row = 0; row < length; row++)
// {
// for (int i = 0; i < answers.GetLength(1); i++)
// {
// if (answers[row, i] == true)
// {
// intAnswers[row] = i;
// break;
// }
// }
// }
// this.SetDirty();
//}
//#endif
public int[] intAnswers;
public Button confirmBtn;
public bool isSingle = true;
public UILineRenderer lineRendererPrefab;
public UILineRenderer currentLine;
public List<Transform> roots;
public List<Button> allbtns;
public HashSet<Transform> items;
[Sirenix.OdinInspector.ReadOnly]
public SegmentContainer<Button, UILineRenderer> segmentContainer;
#if UNITY_EDITOR
private void Reset()
{
confirmBtn = this.GetComponentInChildren<Button>(true);
lineRendererPrefab = Resources.Load<UILineRenderer>("Prefabs/lineRender");
this.roots = this
.transform
.Children()
.Where(_ => _.name.Contains("Root"))
.ToList();
this.items = new HashSet<Transform>();
this.items.UnionWith(this.roots.SelectMany(_ => _.Children()));
var row = this.roots[0].childCount;
var col = this.roots[1].childCount;
//this.answers = new bool[row, col];
}
[Button]
private void ResetValue()
{
confirmBtn = this.GetComponentInChildren<Button>(true);
lineRendererPrefab = Resources.Load<UILineRenderer>("Prefabs/lineRender");
this.roots = this
.transform
.Children()
.Where(_ => _.name.Contains("Root"))
.ToList();
//this.items = new HashSet<Transform>();
//this.items.UnionWith(this.roots.SelectMany(_ => _.Children()));
this.allbtns = this.roots.SelectMany(_ => _.Children()).Select(_ => _.GetComponent<Button>()).ToList();
}
#endif
private bool IsSameParent(Transform a, Transform b)
{
var result = a.parent == b.parent;
Debug.Log(result);
return result;
}
private Vector3 GetPos(Transform transform)
{
//var pos = btn.transform.position;
var pos = transform.Find("pos").position;
return pos;
}
void Start()
{
this.items = new HashSet<Transform>();
this.items.UnionWith(this.allbtns.Select(_ => _.transform));
var lineRoot = this.transform.Find("LinePool");
this.segmentContainer = new SegmentContainer<Button, UILineRenderer>();
var canvas = this.transform.GetComponentInParent<Canvas>();
var camera = canvas.worldCamera;
Vector2 GetRealPos(Vector2 vector)
{
var pos = RectTransformUtility.WorldToScreenPoint(camera, vector);
pos = this.CoordinateTransform(currentLine, pos);
return pos;
}
bool OnEndDrag(Button startNode, Button endNode)
{
// 是否为节点
var result1 = this.items.Contains(endNode.transform);
if (result1 != true)
{
return false;
}
// 是否为同一父物体
var result2 = IsSameParent(startNode.transform, endNode.transform);
if (result2 == true)
{
return false;
}
// 是否可以连线
var result3 = this.segmentContainer.IsJoinable(startNode, endNode);
if (result3 != true)
{
return false;
}
//var pos = RectTransformUtility.WorldToScreenPoint(camera, GetPos(endNode.transform));
//currentLine.Points[1] = camera.WorldToScreenPoint(GetPos(endNode.transform));
var pos = GetRealPos(GetPos(endNode.transform));
currentLine.Points[1] = pos;
currentLine.SetAllDirty();
var segment = new SegmentContainer<Button, UILineRenderer>.Segment()
{
startNode = startNode,
endNode = endNode,
line = currentLine,
};
this.segmentContainer.AddSegment(segment);
return true;
}
//var key = false;
//foreach (var item in allbtns)
//{
// var btn = item;
// 点击后移除所有与该节点相连的对象
//btn.OnClickAsObservable()
// .Where(_ => key == false)
// .Where(_ => currentLine == false)
// .Subscribe(_ => {
// var allLines = this.segmentContainer.GetSegments(btn)?.Select(value => value.line).ToArray();
// if (allLines == null)
// {
// return;
// }
// foreach (var line in allLines)
// {
// Destroy(line.gameObject);
// }
// this.segmentContainer.ClearNode(btn);
// })
// .AddTo(this);
// // 点击生成线段
// btn//.OnEndDragAsObservable()
// .OnClickAsObservable()
// //.Where(_ => key == true)
// //.Where(_ => currentLine == true)
// .Subscribe(_ => {
// if (key == true && currentLine == true)
// {
// var endNode = GetHover()?.GetComponentInParent<Button>();
// Debug.Log(endNode);
// var result = false;
// if (endNode == true)
// {
// result = OnEndDrag(btn, endNode);
// }
// if (result != true)
// {
// GameObject.Destroy(currentLine.gameObject);
// }
// currentLine = null;
// key = false;
// }
// else if (key == false && currentLine == false)
// {
// if (this.isSingle == true)
// {
// var s = this.segmentContainer.GetSegments(btn);
// if (s != null && s.Count > 0)
// {
// Debug.Log("已连线");
// var allLines = s.Select(value => value.line).ToArray();
// foreach (var line in allLines)
// {
// Destroy(line.gameObject);
// }
// this.segmentContainer.ClearNode(btn);
// return;
// }
// }
// //var pos = camera.WorldToScreenPoint(GetPos(btn.transform));
// //Debug.Log(pos);
// //var pos = RectTransformUtility.WorldToScreenPoint(camera, GetPos(btn.transform));
// currentLine = Instantiate(lineRendererPrefab, lineRoot);
// //pos = this.CoordinateTransform(currentLine, pos);
// var pos = GetRealPos(GetPos(btn.transform));
// Debug.Log(pos);
// currentLine.Points[0] = pos;
// key = true;
// }
// //else
// //{
// // var allLines = this.segmentContainer.GetSegments(btn)?.Select(value => value.line).ToArray();
// // if (allLines == null)
// // {
// // return;
// // }
// // foreach (var line in allLines)
// // {
// // Destroy(line.gameObject);
// // }
// // this.segmentContainer.ClearNode(btn);
// //}
// })
// .AddTo(this);
// //btn.OnDragAsObservable()
// // .Where(_ => currentLine == true)
// // .Subscribe(_ => {
// // currentLine.Points[1] = this.CoordinateTransform(currentLine, _.position);
// // currentLine.SetAllDirty();
// // })
// // .AddTo(this);
// //btn//.OnBeginDragAsObservable()
// // .OnClickAsObservable()
// // .Where(_ => key == false)
// // .Subscribe(_ => {
// // if (this.isSingle == true)
// // {
// // var s = this.segmentContainer.GetSegments(btn);
// // if (s != null && s.Count > 0)
// // {
// // Debug.Log("已连线");
// // return;
// // }
// // }
// // //var pos = camera.WorldToScreenPoint(GetPos(btn.transform));
// // //Debug.Log(pos);
// // //var pos = RectTransformUtility.WorldToScreenPoint(camera, GetPos(btn.transform));
// // currentLine = Instantiate(lineRendererPrefab, lineRoot);
// // //pos = this.CoordinateTransform(currentLine, pos);
// // var pos = GetRealPos(GetPos(btn.transform));
// // Debug.Log(pos);
// // currentLine.Points[0] = pos;
// // key = true;
// // })
// // .AddTo(this);
//}
var root1 = this.roots[0].transform.GetComponentsInChildren<Button>(true);
var root2 = this.roots[1].transform.GetComponentsInChildren<Button>(true);
var all = this.allbtns;
var token = this.GetCancellationTokenOnDestroy();
UniTask.Create(async () => {
while (token.IsCancellationRequested != true)
{
var index = await UniTask.WhenAny(root1.Select(_ => _.OnClickAsync(token)));
var btn = root1[index];
if (this.isSingle == true)
{
var s = this.segmentContainer.GetSegments(btn);
if (s != null && s.Count > 0)
{
Debug.Log("已连线");
var allLines = s.Select(value => value.line).ToArray();
foreach (var line in allLines)
{
Destroy(line.gameObject);
}
this.segmentContainer.ClearNode(btn);
continue;
}
}
currentLine = Instantiate(lineRendererPrefab, lineRoot);
var pos = GetRealPos(GetPos(btn.transform));
Debug.Log(pos);
currentLine.Points[0] = pos;
await UniTask.WhenAny(all.Select(_ => _.OnClickAsync(token)));
var endNode = GetHover()?.GetComponentInParent<Button>();
Debug.Log(endNode);
var result = false;
if (endNode == true)
{
result = OnEndDrag(btn, endNode);
}
if (result != true)
{
GameObject.Destroy(currentLine.gameObject);
}
currentLine = null;
}
});
//foreach (var item in root1)
//{
//}
this.UpdateAsObservable()
.Where(_ => currentLine == true)
.Subscribe(_ => {
currentLine.Points[1] = this.CoordinateTransform(currentLine, Input.mousePosition);
currentLine.SetAllDirty();
})
.AddTo(this);
}
private GameObject GetHover()
{
var data = new PointerEventData(EventSystem.current)
{
position = Input.mousePosition,
};
var results = new List<RaycastResult>();
EventSystem.current.RaycastAll(data, results);
return results.FirstOrDefault().gameObject;
}
public bool[] GetRight()
{
var btns = this.roots[0].Children().Select(_ => _.GetComponent<Button>()).ToArray();
var outs = new bool[btns.Length];
//var col = this.answers.GetLength(1);
for (int i = 0; i < btns.Length; i++)
{
var item = btns[i];
var set = this.segmentContainer.GetNodes(item);
if (set != null)
{
var result = true;
var answer = this.intAnswers[i];
Debug.Log($"答案{answer}");
var btn = this.roots[1].GetChild(answer).GetComponent<Button>();
if (set.Contains(btn) != true)
{
result = false;
}
//for (int j = 0; j < col; j++)
//{
// var btn = this.roots[1].GetChild(j).GetComponent<Button>();
// Debug.Log($"答案{this.answers[i, j]}");
//}
outs[i] = result;
}
}
return outs;
}
public override async UniTask WaitAsync(CancellationToken cancellationToken = default)
{
await this.StartAsync();
foreach (var item in this.segmentContainer.Clear())
{
Debug.Log(item);
Destroy(item.line);
}
confirmBtn.gameObject.SetActive(true);
await this.confirmBtn.OnClickAsync(cancellationToken);
var isRight = this.GetRight();
foreach (var item in isRight)
{
Debug.Log(item);
}
// 改变线颜色 TODO
var btns = this.roots[0].Children().Select(_ => _.GetComponent<Button>());
var index = 0;
foreach (var item in btns)
{
var s = this.segmentContainer.GetSegments(item);
if (s == null)
{
break;
}
if (isRight[index] == true)
{
foreach (var tempS in s)
{
tempS.line.color = Color.green;
}
}
else
{
foreach (var tempS in s)
{
tempS.line.color = Color.red;
}
}
index++;
}
//while (cancellationToken.IsCancellationRequested != true)
//{
// await this.confirmBtn.OnClickAsync(cancellationToken);
// foreach (var item in this.GetRight())
// {
// Debug.Log(item);
// }
//}
confirmBtn.gameObject.SetActive(false);
}
private Vector2 CoordinateTransform(UILineRenderer lineRenderer, Vector2 position)
{
var rect = lineRenderer.GetComponent<RectTransform>().rect;
var x = rect.width / Screen.width;
var y = rect.height / Screen.height;
position.x *= x;
position.y *= y;
return position;
}
}
[Searchable]
public class SegmentContainer<TNode, TLine>
{
[SerializeField]
[DictionaryDrawerSettings]
private Dictionary<TNode, HashSet<Segment>> _segmentMapper = new Dictionary<TNode, HashSet<Segment>>();
[SerializeField]
[DictionaryDrawerSettings]
private Dictionary<TNode, HashSet<TNode>> _nodeMapper = new Dictionary<TNode, HashSet<TNode>>();
private void AddSegmentMapper(TNode node, Segment segment)
{
if (_segmentMapper.ContainsKey(node) == false)
{
_segmentMapper.Add(node, new HashSet<Segment>());
}
var set = _segmentMapper[node];
set.Add(segment);
}
private void RemoveSegmentMapper(TNode node, Segment segment)
{
if (_segmentMapper.ContainsKey(node) == false)
{
return;
}
var set = _segmentMapper[node];
if (set == null)
{
return;
}
set.Remove(segment);
}
private void AddNodeMapper(TNode startNode, TNode endNode)
{
if (_nodeMapper.ContainsKey(startNode) == false)
{
_nodeMapper.Add(startNode, new HashSet<TNode>());
}
var set = _nodeMapper[startNode];
set.Add(endNode);
}
private void RemoveNodeMapper(TNode startNode, TNode endNode)
{
if (_nodeMapper.ContainsKey(startNode) == false)
{
return;
}
var set = _nodeMapper[startNode];
if (set == null)
{
return;
}
set.Remove(endNode);
}
public void AddSegment(Segment segment)
{
AddSegmentMapper(segment.startNode, segment);
AddSegmentMapper(segment.endNode, segment);
AddNodeMapper(segment.startNode, segment.endNode);
AddNodeMapper(segment.endNode, segment.startNode);
}
public void RemoveSegment(Segment segment)
{
RemoveSegmentMapper(segment.startNode, segment);
RemoveSegmentMapper(segment.endNode, segment);
RemoveNodeMapper(segment.startNode, segment.endNode);
RemoveNodeMapper(segment.endNode, segment.startNode);
}
public HashSet<Segment> GetSegments(TNode node)
{
_segmentMapper.TryGetValue(node, out var segments);
return segments;
}
public HashSet<TNode> GetNodes(TNode node)
{
_nodeMapper.TryGetValue(node, out var nodes);
return nodes;
}
public void ClearNode(TNode node)
{
if (_segmentMapper.ContainsKey(node) != true)
{
return;
}
foreach (var item in _segmentMapper[node].ToArray())
{
RemoveSegment(item);
}
_segmentMapper[node].Clear();
}
public bool IsJoinable(TNode startNode, TNode endNode)
{
if (this._nodeMapper.ContainsKey(startNode) == false)
{
return true;
}
var nodes = this._nodeMapper[startNode];
if (nodes == null)
{
return true;
}
if (nodes.Contains(endNode) == true)
{
return false;
}
return true;
}
public IEnumerable<Segment> Clear()
{
var allSegment = new List<Segment>();
foreach (var item in _segmentMapper)
{
allSegment.AddRange(item.Value);
this.ClearNode(item.Key);
}
return allSegment.Distinct();
}
public struct Segment
{
public TNode startNode;
public TNode endNode;
public TLine line;
}
}