using System.Collections; using System.Collections.Generic; using System.Linq; using TMPro; using Unity.Mathematics; using UnityEngine; using static CommunicationEvents; public class FactSpawner : MonoBehaviour { public GameObject Sphere, TestPoint, Line, Ray, Angle, Ring, Prism, Cone, Square, Circle; private void OnEnable() { AddFactEvent.AddListener(SpawnFactRepresentation); AnimateNonExistingFactEvent.AddListener(AnimateNonExistingFactTrigger); StartT0Event.AddListener(AnimateFunctionCalls); } private void OnDisable() { AddFactEvent.RemoveListener(SpawnFactRepresentation); AnimateNonExistingFactEvent.RemoveListener(AnimateNonExistingFactTrigger); StartT0Event.RemoveListener(AnimateFunctionCalls); } public void SpawnFactRepresentation(Fact fact) { switch (fact) { case PointFact PointFact: SpawnPoint(PointFact); break; case TestPointFact TestPointFact: SpawnTestPoint(TestPointFact); break; case LineFact LineFact: SpawnLine(LineFact); break; //case RightAngleFact AngleFact: //needed for Hint System case AbstractAngleFact AngleFact: SpawnAngle(AngleFact); break; case RayFact RayFact: SpawnRay(RayFact); break; case CircleFact CircleFact: SpawnRingAndCircle(CircleFact); break; case QuadFact QuadFact: SpawnQuad(QuadFact); break; case TriangleFact TrisFact: SpawnTris(TrisFact); break; case ConeVolumeFact ConeVolumeFact: SpawnCone(ConeVolumeFact); break; case TruncatedConeVolumeFact TruncatedConeVolumeFact: SpawnTruncatedCone(TruncatedConeVolumeFact); break; case SquareFact squareFact: SpawnSquare(squareFact); break; default: break; }; } public void SpawnSquare(SquareFact fact){ GameObject square = GameObject.Instantiate(Square); square.transform.SetPositionAndRotation(fact.Position, fact.Rotation); square.transform.localScale = Vector3.Scale(square.transform.localScale, fact.LocalScale); square.GetComponentInChildren<TextMeshPro>().text = fact.GetLabel(StageStatic.stage.factState) + " = " + System.Math.Round(fact.Area, 2) + "m²"; } public void SpawnPoint(PointFact fact) { GameObject point = GameObject.Instantiate(Sphere); fact.WorldRepresentation = point.GetComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; point.transform.SetPositionAndRotation(fact.Position, fact.Rotation); } public void SpawnTestPoint(TestPointFact fact) { GameObject point = GameObject.Instantiate(TestPoint); fact.WorldRepresentation = point.GetComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; point.transform.SetPositionAndRotation(fact.Position, fact.Rotation); } public void SpawnLine(LineFact fact) { //Change FactRepresentation to Line GameObject line = GameObject.Instantiate(Line); fact.WorldRepresentation = line.GetComponentInChildren<FactObject3D>(); fact.WorldRepresentation.Fact = fact; //Place the Line in the centre of the two points line.transform.position = fact.Position; //Change scale and rotation, so that the two points are connected by the line //and without affecting Scale of the Text line.transform.GetChild(0).localScale = fact.LocalScale; line.transform.GetChild(0).rotation = fact.Rotation; line.GetComponentInChildren<TextMeshPro>().text = fact.GetLabel(StageStatic.stage.factState) + " = " + System.Math.Round(fact.Distance, 2) + " m"; } public void SpawnRay(RayFact fact) { //Change FactRepresentation to Line GameObject line = GameObject.Instantiate(Ray); fact.WorldRepresentation = line.GetComponentInChildren<FactObject3D>(); fact.WorldRepresentation.Fact = fact; //Place the Line in the centre of the two points line.transform.position = fact.Position; //Change scale and rotation, so that the two points are connected by the line //and without affecting Scale of the Text line.transform.GetChild(0).localScale = fact.LocalScale; line.transform.GetChild(0).rotation = fact.Rotation; } //Spawn an angle: point with id = angleFact.Pid2 is the point where the angle gets applied public void SpawnAngle(AbstractAngleFact fact) { //Change FactRepresentation to Angle GameObject angle = GameObject.Instantiate(Angle); fact.WorldRepresentation = angle.GetComponentInChildren<FactObject3D>(); fact.WorldRepresentation.Fact = fact; angle.transform.SetPositionAndRotation(fact.Position, fact.Rotation); //Set text of angle TextMeshPro[] texts = angle.GetComponentsInChildren<TextMeshPro>(); foreach (TextMeshPro t in texts) { //Change Text not to the id, but to the angle-value (from both sides) t.text = System.Math.Round((float)fact.angle, 2) + "°"; } //Generate angle mesh CircleSegmentGenerator[] segments = angle.GetComponentsInChildren<CircleSegmentGenerator>(); foreach (CircleSegmentGenerator c in segments) c.setAngle((float)fact.angle); } public void SpawnRingAndCircle(CircleFact fact) { var ringAndCircleGO = new GameObject("RingAndCircle"); SpawnRing(fact, ringAndCircleGO.transform); SpawnCircle(fact, ringAndCircleGO.transform); ringAndCircleGO.transform.SetPositionAndRotation(fact.Position, fact.Rotation); fact.WorldRepresentation = ringAndCircleGO.AddComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; } public void SpawnRing(CircleFact circleFact, Transform parent = null) { GameObject ring = GameObject.Instantiate(Ring, parent); TorusGenerator[] tori = ring.GetComponentsInChildren<TorusGenerator>(); foreach (var torus in tori) torus.torusRadius = circleFact.radius + (float)Math3d.vectorPrecission; } public void SpawnCircle(CircleFact circleFact, Transform parent = null) { GameObject circle = Instantiate(Circle, parent); //Set radius circle.transform.localScale = Vector3.Scale(circle.transform.localScale, circleFact.LocalScale); } public void SpawnQuad(QuadFact fact) { GameObject prism = GameObject.Instantiate(Prism); fact.WorldRepresentation = prism.GetComponentInChildren<FactObject3D>(); fact.WorldRepresentation.Fact = fact; prism.transform.SetPositionAndRotation(fact.Position, fact.Rotation); PrismGenerator[] prisms = prism.GetComponentsInChildren<PrismGenerator>(); foreach (var gen in prisms) gen.Vertices = fact.Points.Select(p => p.Position).ToArray(); } public void SpawnTris(TriangleFact fact) { GameObject prism = GameObject.Instantiate(Prism); fact.WorldRepresentation = prism.GetComponentInChildren<FactObject3D>(); fact.WorldRepresentation.Fact = fact; prism.transform.SetPositionAndRotation(fact.Position, fact.Rotation); PrismGenerator[] prisms = prism.GetComponentsInChildren<PrismGenerator>(); foreach (var gen in prisms) gen.Vertices = fact.Verticies; } public void SpawnCone(ConeVolumeFact fact) { GameObject prism = GameObject.Instantiate(Cone); fact.WorldRepresentation = prism.GetComponentInChildren<FactObject3D>(); fact.WorldRepresentation.Fact = fact; prism.transform.SetPositionAndRotation(fact.Position, fact.Rotation); ConeGenerator[] prisms = prism.GetComponentsInChildren<ConeGenerator>(); foreach (var gen in prisms) { gen.topPosition = fact.Point.Position - fact.Circle.Position; gen.topRadius = 0f; gen.bottomRadius = fact.Circle.radius; } } public void SpawnTruncatedCone(TruncatedConeVolumeFact fact) { GameObject prism = GameObject.Instantiate(Cone); fact.WorldRepresentation = prism.GetComponentInChildren<FactObject3D>(); fact.WorldRepresentation.Fact = fact; prism.transform.SetPositionAndRotation(fact.Position, fact.Rotation); ConeGenerator[] prisms = prism.GetComponentsInChildren<ConeGenerator>(); foreach (var gen in prisms) { gen.topPosition = fact.CircleTop.Position - fact.CircleBase.Position; gen.topRadius = fact.CircleTop.radius; gen.bottomRadius = fact.CircleBase.radius; } } public void AnimateNonExistingFactTrigger(Fact fact) { StartCoroutine(_BlossomAndDie(fact)); IEnumerator _BlossomAndDie(Fact fact) { SpawnFactRepresentation(fact); yield return new WaitForSeconds(GlobalBehaviour.HintAnimationDuration); RemoveFactEvent.Invoke(fact); fact.freeAutoLabel(StageStatic.stage.factState); } } public void AnimateFunctionCalls() { float MaxAnimationDuration = 10f; StartCoroutine(_AnimateFunctionCalls()); IEnumerator _AnimateFunctionCalls() { float trigger_time = Time.time; Queue<FunctionCallFact> FCFs = new( StageStatic.stage.factState.MyFactSpace.Values .Where(f => f is FunctionCallFact) .Select(f => f as FunctionCallFact) .OrderBy(f => f.Domain.t_0) ); FCFs.TryDequeue(out FunctionCallFact up_next); while (up_next != null) { float curren_time = Time.time - trigger_time; while (up_next != null && up_next.Domain.t_0 <= curren_time) { if (up_next.Domain.t_n <= curren_time) { FCFs.TryDequeue(out up_next); continue; } StartCoroutine(__BlossomDragAndDie(up_next)); FCFs.TryDequeue(out up_next); } yield return null; } #pragma warning disable CS8321 // Die lokale Funktion ist deklariert, wird aber nie verwendet. IEnumerator __BlossomAndDiePerFrame(FunctionCallFact FCF) { float current_time = Time.time - trigger_time; while (current_time <= FCF.Domain.t_n && current_time <= FCF.Domain.t_0 + MaxAnimationDuration) { object[] result = FCF.Call(current_time); List<Fact> factlist = new(); foreach (object i in result) Fact.MakeFact(factlist, i, null, true); foreach (Fact fact in factlist) SpawnFactRepresentation(fact); yield return null; foreach (Fact fact in factlist) { RemoveFactEvent.Invoke(fact); fact.freeAutoLabel(StageStatic.stage.factState); } current_time = Time.time - trigger_time; } } #pragma warning restore CS8321 // Die lokale Funktion ist deklariert, wird aber nie verwendet. IEnumerator __BlossomDragAndDie(FunctionCallFact FCF) { List<Fact> factlist = new(); object[] result = FCF.Call(FCF.Domain.t_0); foreach (object i in result) Fact.MakeFact(factlist, i, null, true); foreach (Fact fact in factlist) SpawnFactRepresentation(fact); float current_time = Time.time - trigger_time; while (current_time <= FCF.Domain.t_n && current_time <= FCF.Domain.t_0 + MaxAnimationDuration) { List<Fact> factlist_media = new(); object[] result_media = FCF.Call(current_time); foreach (object i in result_media) Fact.MakeFact(factlist_media, i, null, true); for (int i = 0; i < math.min(factlist.Count, factlist_media.Count); i++) { //factlist[i].WorldRepresentation.Fact = factlist_media[i]; //TODO? viable? => FactWrapper.FactUpdated() factlist[i].WorldRepresentation.transform.SetPositionAndRotation( factlist_media[i].Position, factlist_media[i].Rotation ); factlist_media[i].freeAutoLabel(StageStatic.stage.factState); } yield return null; current_time = Time.time - trigger_time; } foreach (Fact fact in factlist) { RemoveFactEvent.Invoke(fact); fact.freeAutoLabel(StageStatic.stage.factState); } } } } }