-
Richard Marcus authoredRichard Marcus authored
FactManager.cs 21.48 KiB
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using static CommunicationEvents;
public class FactManager : MonoBehaviour
{
public GameObject SmartMenu;
private List<int> NextEmpties = new List<int>();
//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);
NextEmpties.Add(0);
}
// Update is called once per frame
void Update()
{
}
//TODO: change the return find....
PointFact AddPointFact(RaycastHit hit, int id)
{
Facts.Insert(id, new PointFact(id, hit.point, hit.normal));
return Facts.Find(x => x.Id == id) as PointFact;
}
LineFact AddLineFact(int pid1, int pid2, int id)
{
Facts.Insert(id, new LineFact(id, pid1, pid2));
return Facts.Find(x => x.Id == id) as LineFact;
}
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);
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;
}
AngleFact AddAngleFact(int pid1, int pid2, int pid3, int id)
{
Facts.Insert(id, new AngleFact(id, pid1, pid2, pid3));
return Facts.Find(x => x.Id == id) as AngleFact;
}
public void DeleteFact(Fact fact)
{
if (Facts.Contains(fact)) {
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;*/
NextEmpties.Sort();
int id = NextEmpties[0];
NextEmpties.RemoveAt(0);
if (NextEmpties.Count == 0)
NextEmpties.Add(id + 1);
Debug.Log("place fact at " + id);
return 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
foreach (Fact fact in Facts)
{
GameObject gO = fact.Representation;
if (gO == null) continue;
if ((gO.layer == LayerMask.NameToLayer("Ray")))
gO.GetComponentInChildren<Collider>().enabled = true;
}
break;
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
foreach (Fact fact in Facts)
{
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;
}
}
break;
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
foreach (Fact fact in Facts)
{
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;
}
}
break;
/*
case ToolMode.DeleteMode:
//If DeleteMode is activated we want to have the ability to delete every Fact
//independent of the concrete type of fact
foreach (Fact fact in Facts)
{
GameObject gO = fact.Representation;
gO.GetComponentInChildren<Collider>().enabled = true;
}
break;*/
case ToolMode.ExtraMode:
/*foreach (Fact fact in Facts)
{
}
*/
break;
}
//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()));
}
//Creating 90-degree Angles
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)
{
switch (ActiveToolMode)
{
//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));
}
break;
//same as for linemode atm
case ToolMode.CreateRayMode:
//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];
if (this.lineModeIsFirstPointSelected)
{
//Event for end of line-drawing in "ShinyThings"
CommunicationEvents.StopLineDrawingEvent.Invoke(null);
//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()));
}
this.lineModeIsFirstPointSelected = false;
this.lineModeFirstPointSelected = null;
}
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
else
{
if (this.lineModeIsFirstPointSelected)
{
//Deactivate LineDrawing and first point selection
this.lineModeIsFirstPointSelected = false;
this.lineModeFirstPointSelected = null;
//Event for end of line-drawing in "ShinyThings"
CommunicationEvents.StopLineDrawingEvent.Invoke(null);
}
//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"))
{
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)
{
//Event for end of curve-drawing in "ShinyThings"
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;
}
//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
else
{
//Save the first point selected
this.angleModeIsFirstPointSelected = true;
this.angleModeFirstPointSelected = tempFact;
}
}
//No point was hit
else
{
if (this.angleModeIsFirstPointSelected && this.angleModeIsSecondPointSelected)
{
//Event for end of curve-drawing in "ShinyThings"
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
}
break;
/* //If Left-Mouse-Button was pressed in DeleteMode
case ToolMode.DeleteMode:
//Search for the Fact that was hit
//If the hit GameObject was a Point/Line/Angle
if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Point") || hit.transform.gameObject.layer == LayerMask.NameToLayer("Line") || hit.transform.gameObject.layer == LayerMask.NameToLayer("Angle"))
{
//Search for the suitable fact from the List
this.DeleteFact(Facts.Find(x => x.Id == hit.transform.GetComponent<FactObject>().Id));
}
break;*/
//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;
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;
}
}
}