Newer
Older
John Schihada
committed
using System;
John Schihada
committed
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using static GadgetManager;
public class WorldCursor : MonoBehaviour
{
// TODO experimentell for multiple hits
public RaycastHit[] MultipleHits;
Marco Zimmer
committed
public string deactivateSnapKey;
Marco Zimmer
committed
public LayerMask snapLayerMask;
public float MaxRange = 10f;
public bool useCamCurser = false;
private void Awake()
{
this.layerMask = LayerMask.GetMask("Player", "TalkingZone");
//Ignore player and TalkingZone
this.layerMask = ~this.layerMask;
}
void Start()
{
Cam = Camera.main;
John Schihada
committed
//Set MarkPointMode as the default ActiveToolMode
// ActiveToolMode = ToolMode.ExtraMode;//ToolMode.MarkPointMode;
// CommunicationEvents.ToolModeChangedEvent.Invoke(activeGadget.id);
CultureInfo.CurrentCulture = new CultureInfo("en-US");
public void setLayerMask(int layerMask)
{
this.layerMask = layerMask;
}
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//void Update()
//{
// Ray ray = useCamCurser ? new Ray(Cam.transform.position, Cam.transform.forward) : Cam.ScreenPointToRay(Input.mousePosition);
// this.Hit = new RaycastHit();
// transform.up = Cam.transform.forward;
// transform.position = ray.GetPoint(GlobalBehaviour.GadgetPhysicalDistance);
// int rayCastMask;
// if (Input.GetButton(this.deactivateSnapKey))
// rayCastMask = this.layerMask & ~this.snapLayerMask.value;
// else
// rayCastMask = this.layerMask;
// if (Physics.Raycast(ray, out Hit, MaxRange, rayCastMask)
// || (MaxRange <= GlobalBehaviour.GadgetPhysicalDistance
// && Physics.Raycast(transform.position, Vector3.down, out Hit, GlobalBehaviour.GadgetPhysicalDistance, rayCastMask)))
// {
// if ((Hit.collider.transform.CompareTag("SnapZone") || Hit.collider.transform.CompareTag("Selectable"))
// && !Input.GetButton(this.deactivateSnapKey))
// {
// if(Hit.collider.gameObject.layer == LayerMask.NameToLayer("Ray")
// || Hit.collider.gameObject.layer == LayerMask.NameToLayer("Line"))
// {
// var id = Hit.collider.gameObject.GetComponent<FactObject>().URI;
// AbstractLineFact lineFact = StageStatic.stage.factState[id] as AbstractLineFact;
// PointFact p1 = StageStatic.stage.factState[lineFact.Pid1] as PointFact;
// Hit.point = Math3d.ProjectPointOnLine(p1.Point, lineFact.Dir, Hit.point);
// }
// else
// {
// Hit.point = Hit.collider.transform.position;
// Hit.normal = Vector3.up;
// }
// transform.position = Hit.point;
// transform.up = Hit.normal;
// }
// else
// {
// transform.position = Hit.point;
// transform.up = Hit.normal;
// transform.position += .01f * Hit.normal;
// }
// CheckMouseButtons();
// }
//}
// working currently to include multiple hits
// TODO
void Update()
{
Ray ray = useCamCurser ? new Ray(Cam.transform.position, Cam.transform.forward) : Cam.ScreenPointToRay(Input.mousePosition);
this.Hit = new RaycastHit();
transform.up = Cam.transform.forward;
transform.position = ray.GetPoint(GlobalBehaviour.GadgetPhysicalDistance);
Marco Zimmer
committed
int rayCastMask;
if (Input.GetButton(this.deactivateSnapKey))
rayCastMask = this.layerMask & ~this.snapLayerMask.value;
else
rayCastMask = this.layerMask;
// in case we dont hit anything, just return
if (!(Physics.Raycast(ray, out Hit, MaxRange, rayCastMask)
|| (MaxRange <= GlobalBehaviour.GadgetPhysicalDistance
&& Physics.Raycast(transform.position, Vector3.down, out Hit, GlobalBehaviour.GadgetPhysicalDistance, rayCastMask))))
return;
RaycastHit[] multipleHits = Physics.RaycastAll(ray, MaxRange, rayCastMask);
if (multipleHits.Length == 0)
multipleHits = Physics.RaycastAll(transform.position, Vector3.down, GlobalBehaviour.GadgetPhysicalDistance, rayCastMask);
// sort multipleHits, so the first hit is still the closest
for (int i = 0; i < multipleHits.Length; i++)
int minIdx = i;
float minValue = multipleHits[i].distance;
for (int j = i; j < multipleHits.Length; j++)
{
if (multipleHits[j].distance < minValue)
{
minIdx = j;
minValue = multipleHits[j].distance;
}
}
RaycastHit buffer = multipleHits[minIdx];
multipleHits[minIdx] = multipleHits[i];
multipleHits[i] = buffer;
}
for (int i = 0; i < multipleHits.Length; i++)
{
// check whether we actually hit something
if (!((multipleHits[i].collider.transform.CompareTag("SnapZone") || multipleHits[i].collider.transform.CompareTag("Selectable"))
&& !Input.GetButton(this.deactivateSnapKey)))
continue;
if (multipleHits[i].collider.gameObject.layer == LayerMask.NameToLayer("Ray")
|| multipleHits[i].collider.gameObject.layer == LayerMask.NameToLayer("Line"))
{
var id = multipleHits[i].collider.gameObject.GetComponent<FactObject>().URI;
AbstractLineFact lineFact = StageStatic.stage.factState[id] as AbstractLineFact;
PointFact p1 = StageStatic.stage.factState[lineFact.Pid1] as PointFact;
multipleHits[i].point = Math3d.ProjectPointOnLine(p1.Point, lineFact.Dir, multipleHits[i].point);
else if (multipleHits[i].collider.gameObject.layer == LayerMask.NameToLayer("Ring"))
{
#region Ring
var id = multipleHits[i].transform.GetComponent<FactObject>().URI;
CircleFact circleFact = StageStatic.stage.factState[id] as CircleFact;
Vector3 middlePoint = ((PointFact)StageStatic.stage.factState[circleFact.Pid1]).Point;
Vector3 edgePoint = ((PointFact)StageStatic.stage.factState[circleFact.Pid2]).Point;
var normal = circleFact.normal;
// project p on circlePlane
var q = multipleHits[i].point - middlePoint;
var dist = Vector3.Dot(q, normal);
var pPlane = multipleHits[i].point - (normal * dist); // p on circlePlane
// check if projectedPoint and circleCenter are identical
// should never happen in practice due to floating point precision
if (pPlane == middlePoint)
{
// can be set to any point on the ring -> set to edgePoint
multipleHits[i].point = edgePoint;
return;
else
{
var direction = (pPlane - middlePoint).normalized;
multipleHits[i].point = middlePoint + direction * radius;
}
// cursor orientation should match circle orientation; dont face downwards
if (normal.y < 0) // if normal faces downwards use inverted normal instead
multipleHits[i].normal = -normal;
else
multipleHits[i].normal = normal;
multipleHits[i].point = multipleHits[i].collider.transform.position;
multipleHits[i].normal = Vector3.up;
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
// checking for 2 lines intersection point
if (!((Mathf.Abs(multipleHits[i].distance - multipleHits[0].distance) < 0.03)
&& (multipleHits.Length > 1)
&& (Mathf.Abs(multipleHits[1].distance - multipleHits[0].distance) < 0.03)))
continue;
// we probably have two objects intersecting
// check for line x line intersection and if they actually intersect adjust the points coordinates :)
if (multipleHits[i].collider.gameObject.layer == LayerMask.NameToLayer("Ray")
&& multipleHits[0].collider.gameObject.layer == LayerMask.NameToLayer("Ray"))
{
// case for two intersecting rays
var idLine0 = multipleHits[0].collider.gameObject.GetComponent<FactObject>().URI;
var id = multipleHits[i].collider.gameObject.GetComponent<FactObject>().URI;
// get the two corresponding line facts
AbstractLineFact lineFactLine0 = StageStatic.stage.factState[idLine0] as AbstractLineFact;
AbstractLineFact lineFact = StageStatic.stage.factState[id] as AbstractLineFact;
// get a point on the line
PointFact p1Line0 = StageStatic.stage.factState[lineFactLine0.Pid1] as PointFact;
PointFact p1 = StageStatic.stage.factState[lineFact.Pid1] as PointFact;
// get the intersection point and if it actually intersects set it
Vector3 intersectionPoint = Vector3.zero;
if (Math3d.LineLineIntersection(out intersectionPoint, p1Line0.Point, lineFactLine0.Dir, p1.Point, lineFact.Dir))
multipleHits[i].point = intersectionPoint;
}
//check for other types of intersection. Future Work
transform.position = multipleHits[0].point;
transform.up = multipleHits[0].normal;
if (!((multipleHits[0].collider.transform.CompareTag("SnapZone") || multipleHits[0].collider.transform.CompareTag("Selectable"))
&& !Input.GetButton(this.deactivateSnapKey)))
transform.position += .01f * multipleHits[0].normal;
this.MultipleHits = multipleHits;
CheckMouseButtons();
John Schihada
committed
//Check if left Mouse-Button was pressed and handle it
void CheckMouseButtons()
John Schihada
committed
{
//TODO massively edit for the multiple hits. Right now it only checks the first hit
John Schihada
committed
if (Input.GetMouseButtonDown(0))
{
if (EventSystem.current.IsPointerOverGameObject() //this prevents rays from shooting through ui
|| Hit.transform.gameObject.layer == LayerMask.NameToLayer("Water")) // not allowed to meassure on water
return;
CommunicationEvents.TriggerEvent.Invoke(MultipleHits);
John Schihada
committed
}