123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- #if UNITY_EDITOR
- using UnityEngine;
- using System;
- using System.Collections.Generic;
- namespace O3DWB
- {
- [Serializable]
- public abstract class ObjectInteraction3DShape
- {
- #region Private Constant Variables
- private const float _allowedObjectBoxDistanceFromSurfacePlaneForOverlapDetection = 0.12f;
- #endregion
- #region Protected Variables
- protected List<Vector3> _renderPoints = new List<Vector3>();
- protected bool _renderPointsMustBeCalculated = true;
- protected Vector3 _furthestRenderPointInFrontOfShapePlane;
- protected Vector3 _furthestRenderPointBehindShapePlane;
- protected MouseCursorRayHit _cursorRayHit;
- #endregion
- #region Public Properties
- public Plane Plane { get { return new Plane(Normal, Center); } }
- public Vector3 FurthestRenderPointInFrontOfShapePlane
- {
- get
- {
- if (_renderPointsMustBeCalculated) CalculateRenderPoints();
- return _furthestRenderPointInFrontOfShapePlane;
- }
- }
- public Vector3 FurthestRenderPointBehindShapePlane
- {
- get
- {
- if (_renderPointsMustBeCalculated) CalculateRenderPoints();
- return _furthestRenderPointBehindShapePlane;
- }
- }
- public MouseCursorRayHit CursorRayHit { get { return _cursorRayHit; } }
- #endregion
- #region Public Abstract Properties
- public abstract Vector3 Center { get; set; }
- public abstract Vector3 Normal { get; set; }
- #endregion
- #region Public Methods
- public List<Vector3> GetRenderPoints()
- {
- if (_renderPointsMustBeCalculated) CalculateRenderPoints();
- return new List<Vector3>(_renderPoints);
- }
- public void AcquireCursorRayHit(ObjectMask objectMask, MouseCursorObjectPickFlags cursorPickMaskFlags)
- {
- MouseCursor.Instance.PushObjectMask(objectMask);
- MouseCursor.Instance.PushObjectPickMaskFlags(cursorPickMaskFlags);
- _cursorRayHit = MouseCursor.Instance.GetRayHit();
- MouseCursor.Instance.PopObjectMask();
- MouseCursor.Instance.PopObjectPickMaskFlags();
- }
- public void AcquireCursorRayHitForTerrainObject(GameObject terrainObject)
- {
- _cursorRayHit = MouseCursor.Instance.GetCursorRayHitForTerrainObject(terrainObject);
- }
- public void AdjustShapeCenterAndNormalBasedOnCursorRayHit()
- {
- if (HasCursorPickedObject())
- {
- GameObjectRayHit objectRayHit = _cursorRayHit.ClosestObjectRayHit;
- if (objectRayHit.WasTerrainHit) AdjustShapeWhenSittingOnTerrain(objectRayHit);
- else if (objectRayHit.WasMeshHit) AdjustShapeWhenSittingOnMesh(objectRayHit);
- else if (objectRayHit.WasSpriteHit) AdjustShapeWhenSittingOnSprite(objectRayHit);
- }
- else
- if (HasCursorPickedGridCell()) AdjustShapeWhenSittingOnGridCell();
- }
- public List<GameObject> GetPotentialyOverlappedGameObjects()
- {
- Sphere overlapSphere = new Sphere(Center, CalculateObjectOverlapSphereRadius());
- return Octave3DScene.Get().OverlapSphere(overlapSphere);
- }
- public List<GameObject> GetOverlappedGameObjects(bool allowPartialOverlap)
- {
- if (!HasCursorPickedAnything()) return new List<GameObject>();
-
- List<GameObject> potentialyOverlappedObjects = GetPotentialyOverlappedGameObjects();
- if (allowPartialOverlap) return GetOverlappedGameObjectsForPartialOverlap(potentialyOverlappedObjects);
- else return GetOverlappedGameObjectsForFullOverlap(potentialyOverlappedObjects);
- }
- public bool HasCursorPickedAnything()
- {
- return IsCursorRayHitAvailable() && _cursorRayHit.WasAnythingHit;
- }
- public bool HasCursorPickedSprite()
- {
- return HasCursorPickedObject() && _cursorRayHit.ClosestObjectRayHit.WasSpriteHit;
- }
- public bool HasCursorPickedGridCell()
- {
- return IsCursorRayHitAvailable() && _cursorRayHit.WasACellHit;
- }
- public bool HasCursorPickedObject()
- {
- return IsCursorRayHitAvailable() && _cursorRayHit.WasAnObjectHit;
- }
- public bool HasCursorPickedTerrainObject()
- {
- return HasCursorPickedObject() && _cursorRayHit.ClosestObjectRayHit.WasTerrainHit;
- }
- public bool HasCursorPickedMeshObject()
- {
- return HasCursorPickedObject() && _cursorRayHit.ClosestObjectRayHit.WasMeshHit;
- }
- public bool IsCursorRayHitAvailable()
- {
- return _cursorRayHit != null;
- }
- public GameObject GetGameObjectPickedByCursor()
- {
- if (HasCursorPickedObject()) return _cursorRayHit.ClosestObjectRayHit.HitObject;
- return null;
- }
- #endregion
- #region Public Abstract Methods
- public abstract void RenderGizmos();
- public abstract bool OverlapsPolygon(Polygon3D polygon);
- public abstract bool ContainsPoint(Vector3 point);
- public abstract bool ContainsAllPoints(List<Vector3> points);
- public abstract bool ContainsAnyPoint(List<Vector3> points);
- #endregion
- #region Protected Methods
- protected void CalculateRenderPoints()
- {
- if (_renderPointsMustBeCalculated)
- {
- _renderPoints = GenerateRenderPoints();
- _renderPointsMustBeCalculated = false;
- if (HasCursorPickedObject()) ProjectRenderPointsOnHoveredObject();
- CalculateRenderPointsFurthestFromShapePlane();
- }
- }
- #endregion
- #region Protected Methods
- protected abstract List<Vector3> GenerateRenderPoints();
- #endregion
- #region Private Methods
- private void CalculateRenderPointsFurthestFromShapePlane()
- {
- if (!Plane.GetFurthestPointInFront(_renderPoints, out _furthestRenderPointInFrontOfShapePlane)) _furthestRenderPointInFrontOfShapePlane = _renderPoints[0];
- if (!Plane.GetFurthestPointBehind(_renderPoints, out _furthestRenderPointBehindShapePlane)) _furthestRenderPointBehindShapePlane = _renderPoints[0];
- }
- private float CalculateObjectOverlapSphereRadius()
- {
- float distanceFromCenterToFurthestPointInFrontOfPlane = (Center - FurthestRenderPointInFrontOfShapePlane).magnitude;
- float distanceFromCenterToFurthestPointBehindPlane = (Center - FurthestRenderPointBehindShapePlane).magnitude;
- float sphereRadius = distanceFromCenterToFurthestPointInFrontOfPlane;
- if (sphereRadius < distanceFromCenterToFurthestPointBehindPlane) sphereRadius = distanceFromCenterToFurthestPointBehindPlane;
-
- return sphereRadius;
- }
- private void AdjustShapeWhenSittingOnTerrain(GameObjectRayHit objectRayHit)
- {
- Normal = Vector3.up;
- Center = objectRayHit.HitPoint;
- }
- private void AdjustShapeWhenSittingOnMesh(GameObjectRayHit objectRayHit)
- {
- Normal = objectRayHit.HitNormal;
- Center = objectRayHit.HitPoint;
- }
- private void AdjustShapeWhenSittingOnSprite(GameObjectRayHit objectRayHit)
- {
- Normal = objectRayHit.HitNormal;
- Center = objectRayHit.HitPoint;
- }
- private void AdjustShapeWhenSittingOnGridCell()
- {
- Normal = _cursorRayHit.GridCellRayHit.HitCell.ParentGrid.TransformMatrix.GetNormalizedUpAxis();
- Center = _cursorRayHit.GridCellRayHit.HitPoint;
- }
- private List<GameObject> GetOverlappedGameObjectsForPartialOverlap(List<GameObject> potentialyOverlappedObjects)
- {
- var overlappedGameObjects = new List<GameObject>(potentialyOverlappedObjects.Count);
- foreach (GameObject gameObject in potentialyOverlappedObjects)
- {
- if (ShouldGameObjectBeIgnoredForOverlapDetection(gameObject)) continue;
- if (IsGameObjectPartiallyOverlapped(gameObject)) overlappedGameObjects.Add(gameObject);
- }
- return overlappedGameObjects;
- }
- private bool ShouldGameObjectBeIgnoredForOverlapDetection(GameObject gameObject)
- {
- if (gameObject == GetGameObjectPickedByCursor()) return true;
- if (ObjectQueries.IsGameObjectEmpty(gameObject)) return true;
- return false;
- }
- private bool IsGameObjectPartiallyOverlapped(GameObject gameObject)
- {
- OrientedBox worldOrientedBox = gameObject.GetWorldOrientedBox();
- if (worldOrientedBox.IsValid())
- {
- Polygon3D projectedBoxCornerPointsPoly = worldOrientedBox.Get3DPolygonFromCornerPointsProjectedOnPlane(Plane);
- if (OverlapsPolygon(projectedBoxCornerPointsPoly) &&
- DoesWorldOrientedBoxIntersectOrResideOnShapeSurface(worldOrientedBox)) return true;
- }
- return false;
- }
- private bool DoesWorldOrientedBoxIntersectOrResideOnShapeSurface(OrientedBox worldOrientedBox)
- {
- return worldOrientedBox.IsSpanningOrIsCloseInFrontOrOnAnyPlane(GetPlanesOnWhichOrientedBoxResides(worldOrientedBox), _allowedObjectBoxDistanceFromSurfacePlaneForOverlapDetection);
- }
- private List<Plane> GetPlanesOnWhichOrientedBoxResides(OrientedBox worldOrientedBox)
- {
- if (HasCursorPickedTerrainObject())
- {
- List<Vector3> boxCenterAndCornerPoints = worldOrientedBox.GetCenterAndCornerPoints();
- var planes = new List<Plane>(boxCenterAndCornerPoints.Count);
- Octave3DColliderRayHit colliderRayHit;
- Octave3DCollider hitCollider = _cursorRayHit.ClosestObjectRayHit.HitCollider;
- foreach (Vector3 boxPoint in boxCenterAndCornerPoints)
- {
- Ray ray = new Ray(boxPoint, Normal);
- if (hitCollider.RaycastBothDirections(ray, out colliderRayHit)) planes.Add(new Plane(colliderRayHit.HitNormal, colliderRayHit.HitPoint));
- else planes.Add(Plane);
- }
- return planes;
- }
- return new List<Plane> { Plane };
- }
- private List<GameObject> GetOverlappedGameObjectsForFullOverlap(List<GameObject> potentialyOverlappedObjects)
- {
- var overlappedGameObjects = new List<GameObject>(potentialyOverlappedObjects.Count);
- foreach (GameObject gameObject in potentialyOverlappedObjects)
- {
- if (ShouldGameObjectBeIgnoredForOverlapDetection(gameObject)) continue;
- if (IsGameObjectFullyOverlappedByCircle(gameObject)) overlappedGameObjects.Add(gameObject);
- }
- return overlappedGameObjects;
- }
- private bool IsGameObjectFullyOverlappedByCircle(GameObject gameObject)
- {
- OrientedBox worldOrientedBox = gameObject.GetWorldOrientedBox();
- return IsWorldOrientedBoxFullyOverlappedByCircle(worldOrientedBox);
- }
- private bool IsWorldOrientedBoxFullyOverlappedByCircle(OrientedBox worldOrientedBox)
- {
- if (worldOrientedBox.IsValid())
- {
- if (ContainsAllPoints(worldOrientedBox.GetCornerPointsProjectedOnPlane(Plane)) &&
- DoesWorldOrientedBoxIntersectOrResideOnShapeSurface(worldOrientedBox)) return true;
- }
- return false;
- }
- private void ProjectRenderPointsOnHoveredObject()
- {
- if(HasCursorPickedMeshObject() || HasCursorPickedTerrainObject())
- {
- var pointsProjector = new PointsOnColliderProjector(_cursorRayHit.ClosestObjectRayHit.HitCollider, Plane);
- _renderPoints = pointsProjector.ProjectPoints(_renderPoints);
- }
- }
- #endregion
- }
- }
- #endif
|