Tanoda
LineDrawer.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEngine;
7
8public class LineDrawer : MonoBehaviour
9{
10 public GameObject UIParent;
11 public GameObject linePrefab;
12 public Canvas canvas;
13 public float LineWidth = 8.95f;
14
15 private Dictionary<string, LineObject> lines;
16 public static LineDrawer Instance { get; private set; }
17
18 [SerializeField] private RectTransform canvasRect;
19 [SerializeField] private LineObject actualLine;
20
21 private void Awake()
22 {
23 Instance = this;
24 if (!canvasRect) canvasRect = canvas.GetComponent<RectTransform>();
25
26#if DANA
27 LineWidth = 6f;
28#endif
29
30 lines = new Dictionary<string, LineObject>();
31 }
32
33 internal void UpdateLines()
34 {
35 foreach (var o in lines)
36 {
37 UpdateLine(o.Value);
38 }
39 }
40 internal void UpdateLine(LineObject o)
41 {
42 var lr = o.lineRenderer;
43 try
44 {
45 lr.Points = new[] { lr.Points[0], (Vector2)(o.endRect.position - lr.transform.position) };
46 }
47 catch (Exception)
48 {
49 return;
50 }
51 var allAO = FindObjectsOfType<ActionObject>();
52 var orderedList = allAO.OrderBy(ao => Vector3.Distance(lr.transform.position, ao.transform.position));
53 foreach (var ao in orderedList)
54 {
55 //try
56 //{
57 // if (ao.GetInputs().Contains(o.Value.endID) || ao.GetOutputs().Contains(o.Value.startID))
58 // {
59 // continue;
60 // }
61 //}
62 //catch (Exception)
63 //{
64 // continue;
65 //}
66
67
68 var allSides = ao.GetSides();
69 var intersections = new List<Vector2>();
70
71 for (var i = 0; i < allSides.Count - 1; i++)
72 {
73 var x = allSides[i];
74 var y = allSides[i + 1];
75
76 if (Intersects(lr.transform.position, (Vector2)lr.transform.position + lr.Points[lr.Points.Length - 1], x, y, out var point))
77 {
78 //Debug.Log($"INTERSECTS!!!!!!!!!!!!! (itt: {point})");
79 intersections.Add(point);
80 }
81 }
82
83 var x1 = allSides[3];
84 var y1 = allSides[0];
85
86 if (Intersects(lr.transform.position, (Vector2)lr.transform.position + lr.Points[lr.Points.Length - 1], x1, y1, out var point1))
87 {
88 //Debug.Log($"INTERSECTS!!!!!!!!!!!!! (itt: {point})");
89 intersections.Add(point1);
90 }
91
92 if (intersections.Count == 2) //TODO logic: ha intersects 2 szomszédos oldallal -> 1 ponton kell, ha két párhuzamos -> 2 ponton
93 {
94
95 intersections = intersections.OrderBy(i => Vector2.Distance(lr.transform.position, i)).ToList();
96 var corner1 = ClosestPoint(intersections[0], allSides);
97 var corner2 = ClosestPoint(intersections[1], allSides);
98 intersections.Insert(1, corner1);
99 int index = 2;
100 bool magic = false;
101 if (corner1.x != corner2.x && corner1.y != corner2.y)
102 {
103 intersections.Insert(index, new Vector2(corner1.x, corner2.y));
104 index++;
105 magic = true;
106 }
107 intersections.Insert(index, corner2);
108
109 var currentLine = lr.Points.ToList();
110 var offset = -(Vector2)lr.transform.position;
111
112 currentLine.Insert(currentLine.Count - 1, corner1 + offset);
113 if (magic)
114 {
115 currentLine.Insert(currentLine.Count - 1, new Vector2(corner1.x, corner2.y) + offset);
116 }
117 currentLine.Insert(currentLine.Count - 1, corner2 + offset);
118
119 //lr.Points = new[] { lr.Points[0], intersections[0] + offset, intersections[1] + offset, intersections[2] + offset, intersections[3] + offset, (Vector2)(o.Value.endRect.position - lr.transform.position) };
120 //lr.Points = new[] { lr.Points[0], intersections[1] + offset, intersections[2] + offset, (Vector2)(o.Value.endRect.position - lr.transform.position) };
121 lr.Points = currentLine.ToArray();
122 }
123
124 if (intersections.Count == 1) //Saját magán megy át (99%) TODO: még van itt vmi huncutság
125 {
126 var currentLine = lr.Points.ToList();
127 var offset = -(Vector2)lr.transform.position;
128
129 if (Vector2.Distance(intersections[0] + offset, currentLine[0]) < 10 || Vector2.Distance(intersections[0] + offset, currentLine.Last()) < 10)
130 {
131 continue;
132 }
133
134 var corner2 = ClosestPoint(intersections[0], allSides);
135
136 var checkpoint = Vector2.MoveTowards(currentLine[0] + offset, corner2, 10);
137 var corner1 = ClosestPoint(checkpoint, allSides);
138
139
140 //currentLine.Insert(currentLine.Count - 1, corner1 + offset);
141 currentLine.Insert(currentLine.Count - 1, corner2 + offset);
142
143 lr.Points = currentLine.ToArray();
144 }
145 }
146 if (o.lineRenderer.transform.parent.transform.lossyScale != Vector3.zero)
147 {
148 o.lineRenderer.rectTransform.localScale = Divide(1, o.lineRenderer.transform.parent.transform.lossyScale);
150 LineWidth * o.lineRenderer.transform.parent.transform.lossyScale.x;
151 }
152
153 }
154
155 private Vector2 ClosestPoint(Vector2 point, List<Vector2> points)
156 {
157 var bestDist = 9999f;
158 Vector2 best = Vector2.zero;
159 foreach (var p in points)
160 {
161 var dist = Vector2.Distance(point, p);
162 if (dist < bestDist)
163 {
164 bestDist = dist;
165 best = p;
166 }
167 }
168
169 return best;
170 }
171
173 {
174 var lo = new LineObject();
175 lo.id = Guid.NewGuid().ToString();
176
177 lo.lineRenderer = Instantiate(linePrefab, UIParent.transform).GetComponent<UILineRenderer>();
178 lo.lineRenderer.BezierMode = UILineRenderer.BezierType.Catenary;
179 lo.lineRenderer.gameObject.name = lo.id;
180
181 //lo.lineRenderer.GetComponentInChildren<Button>().onClick.AddListener( () => Controller.Instance.RemoveConnection(lo.id) );
182
183 lines.Add(lo.id, lo);
184
185 return lo;
186 }
187
188 static bool Intersects(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, out Vector2 intersection)
189 {
190 intersection = Vector2.zero;
191
192 Vector2 b = a2 - a1;
193 Vector2 d = b2 - b1;
194 float bDotDPerp = b.x * d.y - b.y * d.x;
195
196 // if b dot d == 0, it means the lines are parallel so have infinite intersection points
197 if (bDotDPerp == 0.0f)
198 return false;
199
200 Vector2 c = b1 - a1;
201 float t = (c.x * d.y - c.y * d.x) / bDotDPerp;
202 if (t < 0 || t > 1)
203 return false;
204
205 float u = (c.x * b.y - c.y * b.x) / bDotDPerp;
206 if (u < 0 || u > 1)
207 return false;
208
209 intersection = a1 + t * b;
210
211 return true;
212 }
213
214 public void RemoveLine(string lineId)
215 {
216 RemoveLine(lines[lineId]);
217 }
218
219 public void RemoveLine(LineObject lineObj)
220 {
221 DestroyImmediate(lineObj.lineRenderer.gameObject);
222 lines.Remove(lineObj.id);
223 }
224
225 public Vector2 GetCanvasSize()
226 {
227 return new Vector2(-canvasRect.rect.width, canvasRect.rect.height);
228 }
229
230 public Vector2 GetCanvasOffset()
231 {
232 return new Vector2(canvasRect.position.x, canvasRect.position.y);
233 }
234
235 public void ReDraw(string id)
236 {
237 foreach (var item in GetLinesByActionId(id))
238 {
239 //item.Value.lineRenderer.Points[0] = RectTransformUtility.WorldToScreenPoint(null, item.Value.startRect.transform.position) + GetCanvasSize() / 2 - GetCanvasOffset();
240 //item.Value.lineRenderer.Points[1] = RectTransformUtility.WorldToScreenPoint(null, item.Value.endRect.transform.position) + GetCanvasSize() / 2 - GetCanvasOffset();
241 item.Value.lineRenderer.rectTransform.position = item.Value.startRect.transform.position;
242 if (item.Value.lineRenderer.transform.parent.transform.lossyScale != Vector3.zero)
243 {
244 item.Value.lineRenderer.rectTransform.localScale =
245 Divide(1, item.Value.lineRenderer.transform.parent.transform.lossyScale);
246 item.Value.lineRenderer.LineThickness =
247 LineWidth * item.Value.lineRenderer.transform.parent.transform.lossyScale.x;
248 }
249
250 item.Value.lineRenderer.Points[0] = Vector2.zero;
251 item.Value.lineRenderer.Points[1] =
252 item.Value.endRect.transform.position - item.Value.startRect.transform.position;
253 item.Value.lineRenderer.SetAllDirty();
254
255 (item.Value.lineRenderer.gameObject.transform as RectTransform).SetWidth((Mathf.Abs(item.Value.startRect.position.x - item.Value.endRect.position.x) + LineWidth) * 2);
256 (item.Value.lineRenderer.gameObject.transform as RectTransform).SetHeight((Mathf.Abs(item.Value.startRect.position.y - item.Value.endRect.position.y) + LineWidth) * 2);
257
258 UpdateLine(item.Value);
259 }
260 }
261
262 public void StartConnection(RectTransform startRect, string outputID, bool blue = false)
263 {
264//#if !UNITY_WEBGL
265// blue = false;
266//#endif
267 actualLine = AddLine();
268
269 if (blue) actualLine.lineRenderer.color = new Color(0, 0.7883066f, 0.8679245f);
270
271 actualLine.startRect = startRect;
272 actualLine.startID = outputID;
273
274 actualLine.lineRenderer.rectTransform.position = actualLine.startRect.transform.position;
275 actualLine.lineRenderer.rectTransform.localScale =
276 Divide(1, actualLine.lineRenderer.transform.parent.transform.lossyScale);
277 actualLine.lineRenderer.LineThickness =
278 LineWidth * actualLine.lineRenderer.transform.parent.transform.lossyScale.x;
279
280 actualLine.lineRenderer.Points[0] = Vector2.zero;
281 actualLine.lineRenderer.Points[1] = actualLine.lineRenderer.Points[0];
282 }
283
284 public LineObject EndConnection(RectTransform endRect, string inputID, bool weldParent = false)
285 {
286//#if !UNITY_WEBGL
287// weldParent = false;
288//#endif
289 actualLine.endRect = endRect;
290
291 if (weldParent) actualLine.lineRenderer.color = Color.yellow;
292
293 actualLine.lineRenderer.rectTransform.position = actualLine.startRect.transform.position;
294 actualLine.lineRenderer.rectTransform.localScale =
295 Divide(1, actualLine.lineRenderer.transform.parent.transform.lossyScale);
296 actualLine.lineRenderer.LineThickness =
297 LineWidth * actualLine.lineRenderer.transform.parent.transform.lossyScale.x;
298
299 actualLine.lineRenderer.Points[1] =
300 actualLine.endRect.transform.position - actualLine.startRect.transform.position;
301 actualLine.lineRenderer.SetAllDirty();
302
303 actualLine.endID = inputID;
304
305 (actualLine.lineRenderer.gameObject.transform as RectTransform).SetWidth((Mathf.Abs(actualLine.startRect.position.x - actualLine.endRect.position.x) + LineWidth) * 2);
306 (actualLine.lineRenderer.gameObject.transform as RectTransform).SetHeight((Mathf.Abs(actualLine.startRect.position.y - actualLine.endRect.position.y) + LineWidth) * 2);
307
308 return actualLine;
309 }
310
311 public void EndConnection()
312 {
313 RemoveLine(actualLine);
314 }
315
316 public void DragConnection(Vector2 position)
317 {
318 var temp = new Vector2(actualLine.startRect.transform.position.x, actualLine.startRect.transform.position.y);
319 actualLine.lineRenderer.LineThickness =
320 LineWidth * actualLine.lineRenderer.transform.parent.transform.lossyScale.x;
321 actualLine.lineRenderer.Points[1] = position - temp;
322 actualLine.lineRenderer.SetAllDirty();
323
324 (actualLine.lineRenderer.gameObject.transform as RectTransform).SetWidth((Mathf.Abs(actualLine.startRect.position.x - actualLine.lineRenderer.Points[1].x) + LineWidth) * 2);
325 (actualLine.lineRenderer.gameObject.transform as RectTransform).SetHeight((Mathf.Abs(actualLine.startRect.position.y - actualLine.lineRenderer.Points[1].y) + LineWidth) * 2);
327 }
328
329 public List<KeyValuePair<string, LineObject>> GetLinesByActionId(string id)
330 {
331 return lines.Where(l =>
332 Controller.Instance.GetActionById(id).GetInputs().Contains(l.Value.endID) ||
333 Controller.Instance.GetActionById(id).GetOutputs().Contains(l.Value.startID)).ToList();
334 }
335
336 public Vector3 Divide(Vector3 x, Vector3 y)
337 {
338 return new Vector3(x[0] / y[0], x[1] / y[1], x[2] / y[2]);
339 }
340
341 public Vector3 Divide(float x, Vector3 y)
342 {
343 return new Vector3(x / y[0], x / y[1], x / y[2]);
344 }
345
346 public Vector3 Divide(Vector3 x, float y)
347 {
348 return new Vector3(x[0] / y, x[1] / y, x[2] / y);
349 }
350}
351
352[Serializable]
353public class LineObject
354{
355 public string id;
357 public string startID;
358 public string endID;
359 public RectTransform startRect;
360 public RectTransform endRect;
361}
UnityEngine.Color Color
Definition: TestScript.cs:32
List< string > GetInputs()
List< string > GetOutputs()
ActionObject GetActionById(string id)
Definition: Controller.cs:950
static Controller Instance
Definition: Controller.cs:16
LineObject AddLine()
Definition: LineDrawer.cs:172
static LineDrawer Instance
Definition: LineDrawer.cs:16
GameObject linePrefab
Definition: LineDrawer.cs:11
List< KeyValuePair< string, LineObject > > GetLinesByActionId(string id)
Definition: LineDrawer.cs:329
Vector3 Divide(Vector3 x, Vector3 y)
Definition: LineDrawer.cs:336
GameObject UIParent
Definition: LineDrawer.cs:10
Canvas canvas
Definition: LineDrawer.cs:12
void ReDraw(string id)
Definition: LineDrawer.cs:235
Vector3 Divide(Vector3 x, float y)
Definition: LineDrawer.cs:346
Vector2 GetCanvasOffset()
Definition: LineDrawer.cs:230
Vector2 GetCanvasSize()
Definition: LineDrawer.cs:225
void DragConnection(Vector2 position)
Definition: LineDrawer.cs:316
float LineWidth
Definition: LineDrawer.cs:13
void EndConnection()
Definition: LineDrawer.cs:311
LineObject EndConnection(RectTransform endRect, string inputID, bool weldParent=false)
Definition: LineDrawer.cs:284
Vector3 Divide(float x, Vector3 y)
Definition: LineDrawer.cs:341
void StartConnection(RectTransform startRect, string outputID, bool blue=false)
Definition: LineDrawer.cs:262
void RemoveLine(string lineId)
Definition: LineDrawer.cs:214
void RemoveLine(LineObject lineObj)
Definition: LineDrawer.cs:219
RectTransform startRect
Definition: LineDrawer.cs:359
string startID
Definition: LineDrawer.cs:357
string endID
Definition: LineDrawer.cs:358
RectTransform endRect
Definition: LineDrawer.cs:360
string id
Definition: LineDrawer.cs:355
UILineRenderer lineRenderer
Definition: LineDrawer.cs:356
static ScrollScaler Instance
Definition: ScrollScaler.cs:11
void AutoScroll(Vector2 mousePos)
Vector2[] Points
Points to be drawn in the line.
Credit Erdener Gonenc - @PixelEnvision.