using System.Collections; using System.Collections.Generic; using UnityEngine; using static CommunicationEvents; public class AngleTool : Gadget { //Variables for AngleMode distinction private bool angleModeIsFirstPointSelected = false; private PointFact angleModeFirstPointSelected = null; private bool angleModeIsSecondPointSelected = false; private PointFact angleModeSecondPointSelected = null; //Attributes for simulating the drawing of a curve private bool curveDrawingActivated; public WorldCursor Cursor; public LineRenderer lineRenderer; private List<Vector3> linePositions = new List<Vector3>(); public Material anglePreviewMaterial; //Vertices for the Curve private int curveDrawingVertexCount = 36; private Vector3 curveEndPoint; private Vector3 angleMiddlePoint; private float curveRadius; void Awake() { if (FactManager == null) FactManager = GameObject.FindObjectOfType<FactManager>(); CommunicationEvents.TriggerEvent.AddListener(OnHit); if (this.Cursor == null) this.Cursor = GameObject.FindObjectOfType<WorldCursor>(); this.UiName = "Angle Mode"; } //Initialize Gadget when enabled AND activated void OnEnable() { this.Cursor.setLayerMask(~this.ignoreLayerMask.value); this.ResetGadget(); } public override void OnHit(RaycastHit hit) { if (!this.isActiveAndEnabled) return; if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Point")) { PointFact tempFact = (PointFact)Facts[hit.transform.GetComponent<FactObject>().Id]; //If two points were already selected and now the third point got selected if (this.angleModeIsFirstPointSelected && this.angleModeIsSecondPointSelected) { //Create AngleFact //Check if new Point is equal to one of the previous points -> if true -> cancel if (!(this.angleModeFirstPointSelected.Id == tempFact.Id || this.angleModeSecondPointSelected.Id == tempFact.Id)) { //Check if exactly the same angle already exists if (!FactManager.factAlreadyExists(new int[] { ((PointFact)this.angleModeFirstPointSelected).Id, ((PointFact)this.angleModeSecondPointSelected).Id, ((PointFact)tempFact).Id })) CommunicationEvents.AddFactEvent.Invoke(FactManager.AddAngleFact(((PointFact)this.angleModeFirstPointSelected).Id, ((PointFact)this.angleModeSecondPointSelected).Id, ((PointFact)tempFact).Id, FactManager.GetFirstEmptyID())); } ResetGadget(); } //If only one point was already selected else if (this.angleModeIsFirstPointSelected && !this.angleModeIsSecondPointSelected) { //Check if the 2 selected points are the same: If not if (this.angleModeFirstPointSelected.Id != tempFact.Id) { this.angleModeIsSecondPointSelected = true; this.angleModeSecondPointSelected = tempFact; ActivateCurveDrawing(); } else { this.angleModeFirstPointSelected = null; this.angleModeIsFirstPointSelected = false; } } //If no point was selected before else { //Save the first point selected this.angleModeIsFirstPointSelected = true; this.angleModeFirstPointSelected = tempFact; } } //No point was hit else { ResetGadget(); //TODO: Hint that only an angle can be created between 3 already existing points } } void Update() { if (!this.isActiveAndEnabled) return; if (this.curveDrawingActivated) UpdateCurveDrawing(this.Cursor.transform.position); } private void ResetGadget() { this.angleModeIsFirstPointSelected = false; this.angleModeFirstPointSelected = null; this.angleModeIsSecondPointSelected = false; this.angleModeSecondPointSelected = null; DeactivateCurveDrawing(); } //Expect a LineFact here, where Line.Pid2 will be the Basis-Point of the angle public void ActivateCurveDrawing() { //In AngleMode with 3 Points we want to draw nearly a rectangle so we add a startPoint and an Endpoint to this preview this.lineRenderer.positionCount = curveDrawingVertexCount + 2; this.lineRenderer.material = this.anglePreviewMaterial; lineRenderer.startWidth = 0.05f; lineRenderer.endWidth = 0.05f; //Set CurveDrawing activated this.curveDrawingActivated = true; //curveEndPoint is a point on the Line selected, with some distance from point2 curveEndPoint = angleModeSecondPointSelected.Point + 0.3f * (angleModeFirstPointSelected.Point - angleModeSecondPointSelected.Point).magnitude * (angleModeFirstPointSelected.Point - angleModeSecondPointSelected.Point).normalized; angleMiddlePoint = angleModeSecondPointSelected.Point; curveRadius = (curveEndPoint - angleModeSecondPointSelected.Point).magnitude; } public void UpdateCurveDrawing(Vector3 currentPosition) { //Find the nearest of all potential third points PointFact nearestPoint = null; foreach (Fact fact in Facts) { if (fact is PointFact && fact.Id != angleModeFirstPointSelected.Id && fact.Id != angleModeSecondPointSelected.Id && nearestPoint == null) nearestPoint = (PointFact)fact; else if (fact is PointFact && fact.Id != angleModeFirstPointSelected.Id && fact.Id != angleModeSecondPointSelected.Id && (nearestPoint.Point - currentPosition).magnitude > (((PointFact)fact).Point - currentPosition).magnitude) nearestPoint = (PointFact)fact; } Vector3 startPoint = new Vector3(0, 0, 0); if (nearestPoint != null) { Vector3 planePoint = Vector3.ProjectOnPlane(currentPosition, Vector3.Cross((nearestPoint.Point - angleMiddlePoint), (curveEndPoint - angleMiddlePoint))); //Determine the Start-Point for the nearest third-point startPoint = angleMiddlePoint + curveRadius * (planePoint - angleMiddlePoint).normalized; } else { //Determine the Start-Point startPoint = angleMiddlePoint + curveRadius * (currentPosition - angleMiddlePoint).normalized; } //Determine the Center of Start-Point and End-Point Vector3 tempCenterPoint = Vector3.Lerp(startPoint, curveEndPoint, 0.5f); Vector3 curveMiddlePoint = angleMiddlePoint + curveRadius * (tempCenterPoint - angleMiddlePoint).normalized; linePositions = new List<Vector3>(); //Start: AngleMiddlePoint -> FirstPoint of Curve linePositions.Add(angleModeSecondPointSelected.Point); for (float ratio = 0; ratio <= 1; ratio += 1.0f / this.curveDrawingVertexCount) { var tangentLineVertex1 = Vector3.Lerp(startPoint, curveMiddlePoint, ratio); var tangentLineVertex2 = Vector3.Lerp(curveMiddlePoint, curveEndPoint, ratio); var bezierPoint = Vector3.Lerp(tangentLineVertex1, tangentLineVertex2, ratio); linePositions.Add(bezierPoint); } //End: LastPoint of Curve -> AngleMiddlePoint linePositions.Add(angleModeSecondPointSelected.Point); lineRenderer.positionCount = linePositions.Count; lineRenderer.SetPositions(linePositions.ToArray()); } public void DeactivateCurveDrawing() { this.lineRenderer.positionCount = 0; this.linePositions = new List<Vector3>(); this.curveDrawingActivated = false; } }