using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; using TMPro; using Unity.Mathematics; using UnityEngine; using UnityEngine.ProBuilder.Shapes; using static CommunicationEvents; public class FactSpawner : MonoBehaviour { public GameObject TestPoint, Line, Ray, Angle, Ring, Prism, Cone, Rectangle, Circle, SimpleCircle, Triangle, Sphere, ActualSphere, Cuboid, TriangularPrism, Cylinder, Pyramid ; 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 RectangleFact rectangleFact: SpawnRectangle(rectangleFact); break; case SimpleCircleFact simpleCircleFact: SpawnSimpleCircle(simpleCircleFact); break; case TriangleFact2 triangleFact: SpawnTriangle(triangleFact); break; case SphereFact sphereFact: SpawnSphere(sphereFact); break; case CuboidFact cuboidFact: SpawnCuboid(cuboidFact); break; case PrismFact prismFact: SpawnTriangularPrism(prismFact); break; case CylinderFact cylinderFact: SpawnCylinderFact(cylinderFact); break; case PyramidFact pyramidFact: SpawnPyramid(pyramidFact); break; default: break; }; } public void SpawnCuboid(CuboidFact fact){ GameObject cuboid = GameObject.Instantiate(Cuboid); fact.WorldRepresentation = cuboid.GetComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; cuboid.transform.SetPositionAndRotation(fact.Position, fact.Rotation); cuboid.transform.localScale = Vector3.Scale(cuboid.transform.localScale, fact.LocalScale); cuboid.GetComponentInChildren<TextMeshPro>().text = fact.GetLabel(StageStatic.stage.factState) + " = " + System.Math.Round(fact.Volume, 2) + "m³"; } public void SpawnCylinderFact(CylinderFact fact){ GameObject cylinder = GameObject.Instantiate(Cylinder); fact.WorldRepresentation = cylinder.GetComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; cylinder.transform.SetPositionAndRotation(fact.Position, fact.Rotation); cylinder.transform.localScale = Vector3.Scale(cylinder.transform.localScale, fact.LocalScale); cylinder.GetComponentInChildren<TextMeshPro>().text = fact.GetLabel(StageStatic.stage.factState) + " = " + System.Math.Round(fact.Volume, 2) + "m³"; } public void SpawnSphere(SphereFact fact){ GameObject sphere = GameObject.Instantiate(ActualSphere); fact.WorldRepresentation = sphere.GetComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; sphere.transform.SetPositionAndRotation(fact.Position, Quaternion.identity); sphere.transform.localScale = Vector3.Scale(sphere.transform.localScale, fact.LocalScale); sphere.GetComponentInChildren<TextMeshPro>().text = fact.GetLabel(StageStatic.stage.factState) + " = " + System.Math.Round(fact.Volume, 2) + "m³"; } public void SpawnRectangle(RectangleFact fact){ GameObject rectangle = GameObject.Instantiate(Rectangle); fact.WorldRepresentation = rectangle.GetComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; rectangle.transform.SetPositionAndRotation(fact.Position, fact.Rotation); rectangle.transform.localScale = Vector3.Scale(rectangle.transform.localScale, fact.LocalScale); rectangle.GetComponentInChildren<TextMeshPro>().text = fact.GetLabel(StageStatic.stage.factState) + " = " + System.Math.Round(fact.Area, 2) + "m²"; } public void SpawnSimpleCircle(SimpleCircleFact fact){ GameObject simpleCircle = GameObject.Instantiate(SimpleCircle); simpleCircle.transform.SetPositionAndRotation(fact.Position, fact.Rotation); simpleCircle.transform.localScale = Vector3.Scale(simpleCircle.transform.localScale, fact.LocalScale); } public void SpawnTriangle(TriangleFact2 fact) { GameObject triangle = GameObject.Instantiate(Triangle); fact.WorldRepresentation = triangle.GetComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; triangle.transform.SetPositionAndRotation(fact.Position, fact.Rotation); // triangle.transform.localScale = Vector3.Scale(triangle.transform.localScale, fact.LocalScale); triangle.GetComponentInChildren<TextMeshPro>().text = fact.GetLabel(StageStatic.stage.factState) + " = " + System.Math.Round(fact.Area, 2) + "m²"; TriangleGenerator[] triangelGenerators = triangle.GetComponentsInChildren<TriangleGenerator>(); foreach (var gen in triangelGenerators) { gen.ab = Vector3.Distance(fact.A, fact.B); gen.height = Vector3.Distance(fact.c, fact.C); gen.c = fact.cPosition; } } public void SpawnTriangularPrism(PrismFact fact) { GameObject prism = GameObject.Instantiate(TriangularPrism); fact.WorldRepresentation = prism.GetComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; prism.transform.SetPositionAndRotation(fact.Position, fact.Rotation); // triangle.transform.localScale = Vector3.Scale(triangle.transform.localScale, fact.LocalScale); prism.GetComponentInChildren<TextMeshPro>().text = fact.GetLabel(StageStatic.stage.factState) + " = " + System.Math.Round(fact.Volume, 2) + "m³"; TriangluarPrismGenerator[] triangelGenerators = prism.GetComponentsInChildren<TriangluarPrismGenerator>(); foreach (var gen in triangelGenerators) { gen.triangle_ab = Vector3.Distance(fact.A, fact.B); gen.triangle_height = Vector3.Distance(fact.c, fact.C); gen.triangle_c = fact.cPosition; gen.prism_height = Vector3.Distance(fact.A, fact.D); } } public void SpawnPyramid(PyramidFact fact) { GameObject pyramid = GameObject.Instantiate(Pyramid); fact.WorldRepresentation = pyramid.GetComponent<FactObject3D>(); fact.WorldRepresentation.Fact = fact; pyramid.transform.SetPositionAndRotation(fact.Position, fact.Rotation); // triangle.transform.localScale = Vector3.Scale(triangle.transform.localScale, fact.LocalScale); pyramid.GetComponentInChildren<TextMeshPro>().text = fact.GetLabel(StageStatic.stage.factState) + " = " + System.Math.Round(fact.Volume, 2) + "m³"; PyramidGenerator[] pyramidGenerators = pyramid.GetComponentsInChildren<PyramidGenerator>(); foreach (var gen in pyramidGenerators) { gen.ab = fact.ab; gen.bc = fact.bc; gen.d_offset = fact.D_offset; } } 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); } } } } }