176 lines
6.4 KiB
C#
176 lines
6.4 KiB
C#
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2007-2020 , Inc. All Rights Reserved.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
|
|
using GCSeries.Core.UI;
|
|
|
|
namespace GCSeries.Core.Input
|
|
{
|
|
public abstract partial class ZPointer
|
|
{
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Private Methods
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
private RaycastResult Raycast(Ray ray)
|
|
{
|
|
// Perform a raycast against all high priority objects.
|
|
if (this.PriorityMask != 0)
|
|
{
|
|
RaycastResult highPriorityResult = this.Raycast(
|
|
ray, ~this.IgnoreMask & this.PriorityMask);
|
|
|
|
if (highPriorityResult.gameObject != null)
|
|
{
|
|
return highPriorityResult;
|
|
}
|
|
}
|
|
|
|
// Perform a raycast against all low priority objects.
|
|
RaycastResult lowPriorityResult = this.Raycast(
|
|
ray, ~this.IgnoreMask & ~this.PriorityMask);
|
|
|
|
return lowPriorityResult;
|
|
}
|
|
|
|
private RaycastResult Raycast(Ray ray, int layerMask)
|
|
{
|
|
// Initialize the raycast result.
|
|
RaycastResult result = default(RaycastResult);
|
|
result.distance = this.DefaultHitDistance;
|
|
result.worldNormal = -ray.direction;
|
|
result.worldPosition = ray.GetPoint(result.distance);
|
|
result.screenPosition = this.EventCamera.Camera.WorldToScreenPoint(
|
|
result.worldPosition);
|
|
|
|
// Perform a physics raycast to determine if any physics objects
|
|
// are hit.
|
|
RaycastHit physicsResult;
|
|
if (Physics.Raycast(
|
|
ray, out physicsResult, result.distance, layerMask))
|
|
{
|
|
result.distance = physicsResult.distance;
|
|
result.worldPosition = physicsResult.point;
|
|
result.worldNormal = physicsResult.normal;
|
|
result.gameObject = physicsResult.collider.gameObject;
|
|
result.screenPosition =
|
|
this.EventCamera.Camera.WorldToScreenPoint(
|
|
physicsResult.point);
|
|
}
|
|
|
|
// Perform a graphics raycast to determine if any UI objects
|
|
// are hit.
|
|
RaycastResult graphicResult;
|
|
if (ZGraphicRaycaster.Raycast(
|
|
ray, out graphicResult, result.distance, layerMask))
|
|
{
|
|
result = graphicResult;
|
|
}
|
|
|
|
// Perform a physics spherecast if the hit radius is greater
|
|
// than zero to determine if any physics objects are within the
|
|
// hit radius.
|
|
float radius = this.DefaultHitRadius;
|
|
if (radius > 0)
|
|
{
|
|
// Increase the hit radius by 10% when an object is intersected
|
|
// to eliminate instability issues in collision detection results
|
|
// when the pointer is straddling intersection boundaries.
|
|
if (this.HitInfo.gameObject != null)
|
|
{
|
|
radius *= 1.1f;
|
|
}
|
|
|
|
if (this.SphereCast(
|
|
ray, radius, out physicsResult, result.distance, layerMask))
|
|
{
|
|
if (result.gameObject == null ||
|
|
result.gameObject == physicsResult.collider.gameObject)
|
|
{
|
|
result.distance = physicsResult.distance;
|
|
result.worldPosition = physicsResult.point;
|
|
result.worldNormal = physicsResult.normal;
|
|
result.gameObject = physicsResult.collider.gameObject;
|
|
result.screenPosition =
|
|
this.EventCamera.Camera.WorldToScreenPoint(
|
|
physicsResult.point);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If neither the physics nor graphics raycast succeeded,
|
|
// perform a raycast against the default collision plane.
|
|
if (result.gameObject == null &&
|
|
this.DefaultCollisionPlane == CollisionPlane.Screen)
|
|
{
|
|
result = this.Raycast(
|
|
ray, this.EventCamera.ZeroParallaxPlane, false);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private RaycastResult Raycast(Ray ray, Plane plane, bool lockToPlane)
|
|
{
|
|
RaycastResult result = default(RaycastResult);
|
|
|
|
float distance = 0.0f;
|
|
if (plane.Raycast(ray, out distance))
|
|
{
|
|
distance = lockToPlane ?
|
|
distance : Mathf.Min(distance, this.DefaultHitDistance);
|
|
|
|
result.worldNormal = plane.normal;
|
|
}
|
|
else
|
|
{
|
|
distance = lockToPlane ?
|
|
this._hitInfo.distance : this.DefaultHitDistance;
|
|
|
|
result.worldNormal = -ray.direction.normalized;
|
|
}
|
|
|
|
result.distance = distance;
|
|
result.worldPosition = ray.origin + (ray.direction * distance);
|
|
result.screenPosition =
|
|
this.EventCamera.Camera.WorldToScreenPoint(
|
|
result.worldPosition);
|
|
|
|
return result;
|
|
}
|
|
|
|
private bool SphereCast(
|
|
Ray ray, float radius, out RaycastHit hitInfo, float maxDistance, int layerMask)
|
|
{
|
|
hitInfo = default(RaycastHit);
|
|
RaycastHit[] hitInfos = Physics.SphereCastAll(
|
|
ray, radius, maxDistance, layerMask);
|
|
|
|
bool success = false;
|
|
float distance = float.MaxValue;
|
|
|
|
// Prioritize spherecast results based on their distance from the
|
|
// ray's line as opposed to the ray's origin.
|
|
for (int i = 0; i < hitInfos.Length; ++i)
|
|
{
|
|
float distanceFromRay = Vector3.Cross(
|
|
ray.direction, hitInfos[i].point - ray.origin).magnitude;
|
|
|
|
if (distanceFromRay < distance)
|
|
{
|
|
hitInfo = hitInfos[i];
|
|
distance = distanceFromRay;
|
|
success = true;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
}
|
|
}
|