Skip to content
Snippets Groups Projects
FactManager.cs 21.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • John Schihada's avatar
    John Schihada committed
    using System;
    using System.Collections;
    
    using System.Collections.Generic;
    
    using UnityEngine;
    using static CommunicationEvents;
    public class FactManager : MonoBehaviour
    {
    
        private List<int> NextEmpties = new List<int>();
    
    John Schihada's avatar
    John Schihada committed
        //Variables for LineMode distinction
        public bool lineModeIsFirstPointSelected = false;
        public Fact lineModeFirstPointSelected = null;
    
        //Variables for AngleMode distinction
    
        public bool angleModeIsFirstPointSelected = false;
        public Fact angleModeFirstPointSelected = null;
        public bool angleModeIsSecondPointSelected = false;
        public Fact angleModeSecondPointSelected = null;
    
        // Start is called before the first frame update
        void Start()
        {
            CommunicationEvents.ToolModeChangedEvent.AddListener(OnToolModeChanged);
    
            CommunicationEvents.TriggerEvent.AddListener(OnHit);
    
            //  CommunicationEvents.SnapEvent.AddListener(Rocket);
    
            //We dont want to have this here anymore...
            //CommunicationEvents.RemoveFactEvent.AddListener(DeleteFact);
    
    John Schihada's avatar
    John Schihada committed
        // Update is called once per frame
        void Update()
        {
    
        }
    
    Richard Marcus's avatar
    Richard Marcus committed
        //TODO: change the return find....
    
    John Schihada's avatar
    John Schihada committed
        PointFact AddPointFact(RaycastHit hit, int id)
    
            Facts.Insert(id, new PointFact(id, hit.point, hit.normal));
    
    John Schihada's avatar
    John Schihada committed
            return Facts.Find(x => x.Id == id) as PointFact;
    
    John Schihada's avatar
    John Schihada committed
        LineFact AddLineFact(int pid1, int pid2, int id)
    
            Facts.Insert(id, new LineFact(id, pid1, pid2));
    
    John Schihada's avatar
    John Schihada committed
            return Facts.Find(x => x.Id == id) as LineFact;
    
    John Schihada's avatar
    John Schihada committed
        }
    
        RayFact AddRayFact(int pid1, int pid2, int id)
        {
            Facts.Insert(id, new RayFact(id, pid1, pid2));
    
    
            var oLid = GetFirstEmptyID();
            Facts.Insert(oLid, new OnLineFact(oLid, pid1, id));
            oLid = GetFirstEmptyID();
            Facts.Insert(oLid, new OnLineFact(oLid, pid2, id));
    
    
            var p1 = Facts.Find(x => x.Id == pid1);
            var p2 = Facts.Find(x => x.Id == pid2);
    
    Richard Marcus's avatar
    Richard Marcus committed
    
    
            Vector3 dir = p2.Representation.transform.position - p1.Representation.transform.position;
    
        
    
            // Bit shift the index of the layer Point to get a bit mask
            int layerMask = 1 << LayerMask.NameToLayer("Point");
            // This casts rays only against colliders in layer 8
    
    
            RaycastHit[] hits;
            hits = Physics.RaycastAll(p1.Representation.transform.position - dir * 1000, dir, Mathf.Infinity, layerMask);
    
            Debug.Log(hits.Length + " hits");
            for (int i = 0; i < hits.Length; i++)
            {
                RaycastHit hit = hits[i];
    
                bool exists = false;
    
                foreach (Fact fact in Facts)
                {
                    if (typeof(OnLineFact).IsInstanceOfType(fact))
                    {
                        OnLineFact oLFact = (OnLineFact)fact;
                        if ((oLFact.Lid == id && oLFact.Pid == hit.transform.gameObject.GetComponent<FactObject>().Id))
                        {
                            exists = true;
                            break;
                        }
                    }
                }
    
    
                if (!exists)
                {
                    oLid = GetFirstEmptyID();
                    var olF = new OnLineFact(oLid, hit.transform.gameObject.GetComponent<FactObject>().Id, id);
                    Facts.Insert(oLid, olF);
                }
    
    
            }
            
    
            return Facts.Find(x => x.Id == id) as RayFact;
        }
    
    
    John Schihada's avatar
    John Schihada committed
        AngleFact AddAngleFact(int pid1, int pid2, int pid3, int id)
    
            Facts.Insert(id, new AngleFact(id, pid1, pid2, pid3));
    
    John Schihada's avatar
    John Schihada committed
            return Facts.Find(x => x.Id == id) as AngleFact;
    
                NextEmpties.Add(fact.Id);
    
                //Facts.RemoveAt(fact.Id);
                Facts.Remove(Facts.Find(x => x.Id == fact.Id));
                CommunicationEvents.RemoveFactEvent.Invoke(fact);
            }
    
        public int GetFirstEmptyID()
        {
    
    
            /* for (int i = 0; i < Facts.Length; ++i)
             {
                 if (Facts[i] == "")
                     return i;
             }
             return Facts.Length - 1;*/
    
            int id = NextEmpties[0];
            NextEmpties.RemoveAt(0);
            if (NextEmpties.Count == 0)
                NextEmpties.Add(id + 1);
    
            Debug.Log("place fact at " + id);
    
        public void OnToolModeChanged(ToolMode ActiveToolMode)
        {
    
            //We need to do this somehwere...
            CommunicationEvents.ActiveToolMode = ActiveToolMode;
    
            switch (ActiveToolMode)
            {
                case ToolMode.MarkPointMode:
                    //If MarkPointMode is activated we want to have the ability to mark the point
                    //everywhere, independent of already existing facts
    
                        GameObject gO = fact.Representation;
    
                        if (gO == null) continue;
                        if ((gO.layer == LayerMask.NameToLayer("Ray")))
    
                                gO.GetComponentInChildren<Collider>().enabled = true;
    
    
                case ToolMode.CreateRayMode:
                    //same as for line mode atm
    
    
                case ToolMode.CreateLineMode:
                    //If CreateLineMode is activated we want to have the ability to select points for the Line
                    //but we don't want to have the ability to select Lines or Angles
    
                        GameObject gO = fact.Representation;
    
                        if (gO == null) continue;
                        if (gO.layer == LayerMask.NameToLayer("Line") || gO.layer == LayerMask.NameToLayer("Angle")|| gO.layer == LayerMask.NameToLayer("Ray"))
    
                            gO.GetComponentInChildren<Collider>().enabled = false;
    
                        else if (gO.layer == LayerMask.NameToLayer("Point"))
    
                            gO.GetComponentInChildren<Collider>().enabled = true;
    
                case ToolMode.CreateAngleMode:
    
                    //If CreateAngleMode is activated we want to have the ability to select Points for the Angle
                    //but we don't want to have the ability to select Lines or Angles
    
                        GameObject gO = fact.Representation;
    
                        if (gO == null) continue;
    
                        if (gO.layer == LayerMask.NameToLayer("Line") || gO.layer == LayerMask.NameToLayer("Angle"))
    
                            gO.GetComponentInChildren<Collider>().enabled = false;
    
                        else if (gO.layer == LayerMask.NameToLayer("Point"))
    
                            gO.GetComponentInChildren<Collider>().enabled = true;
    
                case ToolMode.DeleteMode:
                    //If DeleteMode is activated we want to have the ability to delete every Fact
                    //independent of the concrete type of fact
    
                        GameObject gO = fact.Representation;
                        gO.GetComponentInChildren<Collider>().enabled = true;
    
                case ToolMode.ExtraMode:
    
    John Schihada's avatar
    John Schihada committed
                    /*foreach (Fact fact in Facts)
    
    John Schihada's avatar
    John Schihada committed
                    */
    
            //Stop PreviewEvents in ShineThings on ToolModeChange
            CommunicationEvents.StopPreviewsEvent.Invoke(null);
    
        //automatic 90 degree angle construction
        public void Rocket(RaycastHit hit)
        {
    
            int idA, idB, idC;
    
            //usual point
            idA = this.GetFirstEmptyID();
            CommunicationEvents.AddFactEvent.Invoke(this.AddPointFact(hit, idA));
    
            //second point
            idB = this.GetFirstEmptyID();
            var shiftedHit = hit;
            var playerPos = Camera.main.transform.position;
            playerPos.y = hit.point.y;
            shiftedHit.point = playerPos;
            CommunicationEvents.AddFactEvent.Invoke(this.AddPointFact(shiftedHit, idB));
    
            //third point with unknown height
            idC = this.GetFirstEmptyID();
            var skyHit = hit;
            skyHit.point += Vector3.up * 20;
            CommunicationEvents.AddFactEvent.Invoke(this.AddPointFact(skyHit, idC));
    
            //lines
            CommunicationEvents.AddFactEvent.Invoke(this.AddLineFact(idA, idB, this.GetFirstEmptyID()));
            //lines
            CommunicationEvents.AddFactEvent.Invoke(this.AddLineFact(idA, idC, this.GetFirstEmptyID()));
    
            //90degree angle
    
            CommunicationEvents.AddFactEvent.Invoke(this.AddAngleFact(idB, idA, idC, GetFirstEmptyID()));
    
        public void SmallRocket(RaycastHit hit, int idA)
    
            //enable collider to measure angle to the treetop
    
            int idB = this.GetFirstEmptyID();
            CommunicationEvents.AddFactEvent.Invoke(this.AddPointFact(hit, idB));
    
            Facts[idB].Representation.GetComponentInChildren<Collider>().enabled = true;
    
            //third point with unknown height
            int idC = this.GetFirstEmptyID();
            var skyHit = hit;
    
            skyHit.point = (Facts[idA] as PointFact).Point + Vector3.up * 20;
    
            CommunicationEvents.AddFactEvent.Invoke(this.AddPointFact(skyHit, idC));
    
            //lines
            CommunicationEvents.AddFactEvent.Invoke(this.AddLineFact(idA, idB, this.GetFirstEmptyID()));
            //lines
            CommunicationEvents.AddFactEvent.Invoke(this.AddLineFact(idA, idC, this.GetFirstEmptyID()));
    
            //90degree angle
            CommunicationEvents.AddFactEvent.Invoke(this.AddAngleFact(idB, idA, idC, GetFirstEmptyID()));
    
        public Boolean factAlreadyExists(int[] ids) {
            switch (ActiveToolMode) {
                case ToolMode.CreateLineMode:
                    foreach (Fact fact in Facts)
                    {
                        if (typeof(LineFact).IsInstanceOfType(fact))
                        {
                            LineFact line = (LineFact)fact;
                            if (line.Pid1 == ids[0] && line.Pid2 == ids[1])
                            {
                                return true;
                            }
                        }
                    }
                    return false;
                case ToolMode.CreateAngleMode:
                    foreach (Fact fact in Facts)
                    {
                        if (typeof(AngleFact).IsInstanceOfType(fact))
                        {
                            AngleFact angle = (AngleFact)fact;
                            if (angle.Pid1 == ids[0] && angle.Pid2 == ids[1] && angle.Pid3 == ids[2])
                            {
                                return true;
                            }
                        }
                    }
                    return false;
                default:
                    return false;
            }
            return false;
        }
    
        public void OnHit(RaycastHit hit)
        {
    
    John Schihada's avatar
    John Schihada committed
            switch (ActiveToolMode)
    
    John Schihada's avatar
    John Schihada committed
                //If Left-Mouse-Button was pressed in MarkPointMode
                case ToolMode.MarkPointMode:
    
    
                    var pid = this.GetFirstEmptyID();
                    CommunicationEvents.AddFactEvent.Invoke(this.AddPointFact(hit,pid ));
                    if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Ray")){
    
                        var oLid = GetFirstEmptyID();
                        Facts.Insert(oLid, new OnLineFact(oLid, pid, hit.transform.GetComponent<FactObject>().Id));
                    }
    
    
    
    John Schihada's avatar
    John Schihada committed
                    break;
    
    
                //same as for linemode atm
                case ToolMode.CreateRayMode:
    
    John Schihada's avatar
    John Schihada committed
                //If Left-Mouse-Button was pressed in CreateLineMode
                case ToolMode.CreateLineMode:
                    //Check if an existing Point was hit
                    if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Point"))
                    {
                        Fact tempFact = Facts[hit.transform.GetComponent<FactObject>().Id];
    
    John Schihada's avatar
    John Schihada committed
                        if (this.lineModeIsFirstPointSelected)
    
    John Schihada's avatar
    John Schihada committed
                            //Event for end of line-drawing in "ShinyThings"
                            CommunicationEvents.StopLineDrawingEvent.Invoke(null);
    
    John Schihada's avatar
    John Schihada committed
                            //Create LineFact
    
                            //Check if exactle the same line/distance already exists
                            if(!factAlreadyExists(new int[] { this.lineModeFirstPointSelected.Id, tempFact.Id }))
    
                                if(ActiveToolMode==ToolMode.CreateLineMode)
                                    CommunicationEvents.AddFactEvent.Invoke(this.AddLineFact(this.lineModeFirstPointSelected.Id, tempFact.Id, this.GetFirstEmptyID()));
                                else
    
                                    CommunicationEvents.AddFactEvent.Invoke(this.AddRayFact(this.lineModeFirstPointSelected.Id, tempFact.Id, this.GetFirstEmptyID()));
    
    John Schihada's avatar
    John Schihada committed
                            this.lineModeIsFirstPointSelected = false;
                            this.lineModeFirstPointSelected = null;
    
    John Schihada's avatar
    John Schihada committed
                        else
                        {
                            //Activate LineDrawing for preview
                            this.lineModeIsFirstPointSelected = true;
                            this.lineModeFirstPointSelected = tempFact;
                            //Event for start line-drawing in "ShinyThings"
                            CommunicationEvents.StartLineDrawingEvent.Invoke(this.lineModeFirstPointSelected);
    
                    //if we want to spawn a new point
                    else if (Input.GetKey(KeyCode.LeftShift))
    
                    {
                        if (this.lineModeIsFirstPointSelected)
                        {
    
    
                            CommunicationEvents.StopLineDrawingEvent.Invoke(null);
    
                            SmallRocket(hit, this.lineModeFirstPointSelected.Id);
    
                            this.lineModeIsFirstPointSelected = false;
                            this.lineModeFirstPointSelected = null;
                        }
                    }
    
    
                    //if we hit the top snap zone
                    else if (hit.transform.gameObject.tag=="SnapZone")
                    {
                        if (this.lineModeIsFirstPointSelected)
                        {
    
                            RaycastHit downHit;
    
                            if (Physics.Raycast(hit.transform.gameObject.transform.position-Vector3.down*2,Vector3.down, out downHit))
                            {
                                int idA = downHit.transform.gameObject.GetComponent<FactObject>().Id;
                                int idB = this.lineModeFirstPointSelected.Id;
                                int idC = GetFirstEmptyID();
                                CommunicationEvents.AddFactEvent.Invoke(this.AddPointFact(hit, idC));
                                //Event for end of line-drawing in "ShinyThings"
                                CommunicationEvents.StopLineDrawingEvent.Invoke(null);
                                //Create LineFact
                                CommunicationEvents.AddFactEvent.Invoke(this.AddAngleFact(idA, idB, idC, GetFirstEmptyID()));
                                this.lineModeIsFirstPointSelected = false;
                                this.lineModeFirstPointSelected = null;
                            }
                        }
                    }
    
                    //If no Point was hit
    
    John Schihada's avatar
    John Schihada committed
                    else
                    {
                        if (this.lineModeIsFirstPointSelected)
    
    John Schihada's avatar
    John Schihada committed
                            //Deactivate LineDrawing and first point selection
                            this.lineModeIsFirstPointSelected = false;
                            this.lineModeFirstPointSelected = null;
                            //Event for end of line-drawing in "ShinyThings"
                            CommunicationEvents.StopLineDrawingEvent.Invoke(null);
    
    John Schihada's avatar
    John Schihada committed
                        //TODO: Hint that only a line can be drawn between already existing points
                    }
                    break;
                //If Left-Mouse-Button was pressed in CreateAngleMode
                case ToolMode.CreateAngleMode:
    
                    //Check if an existing Point was hit
                    if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Point"))
    
    John Schihada's avatar
    John Schihada committed
                    {
                        Fact tempFact = Facts[hit.transform.GetComponent<FactObject>().Id];
    
    
                        //If two points were already selected and now the third point got selected
                        if (this.angleModeIsFirstPointSelected && this.angleModeIsSecondPointSelected)
    
    John Schihada's avatar
    John Schihada committed
                        {
    
                            //Event for end of curve-drawing in "ShinyThings"
    
    John Schihada's avatar
    John Schihada committed
                            CommunicationEvents.StopCurveDrawingEvent.Invoke(null);
                            //Create AngleFact
    
                            //Check if new Point is equal to one of the previous points -> if true -> cancel
                            if (!(angleModeFirstPointSelected.Id == tempFact.Id || angleModeSecondPointSelected.Id == tempFact.Id))
    
                                //Check if exactly the same angle already exists
                                if (!factAlreadyExists(new int[] { ((PointFact)angleModeFirstPointSelected).Id, ((PointFact)angleModeSecondPointSelected).Id, ((PointFact)tempFact).Id }))
                                    CommunicationEvents.AddFactEvent.Invoke(this.AddAngleFact(((PointFact)angleModeFirstPointSelected).Id, ((PointFact)angleModeSecondPointSelected).Id, ((PointFact)tempFact).Id, GetFirstEmptyID()));
    
                            this.angleModeIsFirstPointSelected = false;
                            this.angleModeFirstPointSelected = null;
                            this.angleModeIsSecondPointSelected = false;
                            this.angleModeSecondPointSelected = null;
    
    John Schihada's avatar
    John Schihada committed
                        }
    
                        //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;
    
                                //Event for start of curve-drawing in "ShinyThings"
                                //Create new LineFact with the 2 points
                                LineFact tempLineFact = new LineFact();
                                tempLineFact.Pid1 = this.angleModeFirstPointSelected.Id;
                                tempLineFact.Pid2 = this.angleModeSecondPointSelected.Id;
                                CommunicationEvents.StartCurveDrawingEvent.Invoke(tempLineFact);
                            }
                            else {
                                this.angleModeFirstPointSelected = null;
                                this.angleModeIsFirstPointSelected = false;
                            }
                        }
                        //If no point was selected before
    
    John Schihada's avatar
    John Schihada committed
                        else
                        {
    
                            //Save the first point selected
                            this.angleModeIsFirstPointSelected = true;
                            this.angleModeFirstPointSelected = tempFact;
    
    John Schihada's avatar
    John Schihada committed
                    else
                    {
    
                        if (this.angleModeIsFirstPointSelected && this.angleModeIsSecondPointSelected)
    
    John Schihada's avatar
    John Schihada committed
                        {
    
                            //Event for end of curve-drawing in "ShinyThings"
    
    John Schihada's avatar
    John Schihada committed
                            CommunicationEvents.StopCurveDrawingEvent.Invoke(null);
                        }
    
    
                        //Reset Angle-Preview-Attributes
                        this.angleModeIsFirstPointSelected = false;
                        this.angleModeFirstPointSelected = null;
                        this.angleModeIsSecondPointSelected = false;
                        this.angleModeSecondPointSelected = null;
    
                        //TODO: Hint that only an angle can be created between 3 already existing points
    
    John Schihada's avatar
    John Schihada committed
                    }
    
    John Schihada's avatar
    John Schihada committed
                    break;
    
              /*  //If Left-Mouse-Button was pressed in DeleteMode
    
    John Schihada's avatar
    John Schihada committed
                case ToolMode.DeleteMode:
                    //Search for the Fact that was hit
                    //If the hit GameObject was a Point/Line/Angle
    
    John Schihada's avatar
    John Schihada committed
                    if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Point") || hit.transform.gameObject.layer == LayerMask.NameToLayer("Line") || hit.transform.gameObject.layer == LayerMask.NameToLayer("Angle"))
                    {
    
    John Schihada's avatar
    John Schihada committed
                        //Search for the suitable fact from the List
    
                        this.DeleteFact(Facts.Find(x => x.Id == hit.transform.GetComponent<FactObject>().Id));
    
    John Schihada's avatar
    John Schihada committed
                //If Left-Mouse-Button was pressed in ExtraMode
                case ToolMode.ExtraMode:
                    if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Point")) {
                        var menu = GameObject.Instantiate(SmartMenu);
    
                        menu.GetComponent<SmartMenu>().FactManager = this;
    
    John Schihada's avatar
    John Schihada committed
                        menu.GetComponent<Canvas>().worldCamera = Camera.main;
                        menu.transform.SetParent(hit.transform);
                        menu.transform.localPosition = Vector3.up - Camera.main.transform.forward;
                    }
                    else
                    {
                        PointFact fact = AddPointFact(hit, GetFirstEmptyID());
                        CommunicationEvents.AddFactEvent.Invoke(fact);
                    }
                    break;