loudixvmuniu/Assets/GCSeries/Core/Scripts/Input/ZPointer.CollisionDetection.cs

176 lines
6.4 KiB
C#
Raw Normal View History

2025-04-01 16:16:45 +08:00
////////////////////////////////////////////////////////////////////////////////
//
// 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;
}
}
}