This commit is contained in:
2026-05-19 17:39:03 +07:00
parent bf0ebe447d
commit 5da832bb57
559 changed files with 69543 additions and 1 deletions

View File

@@ -0,0 +1,33 @@
using System;
namespace Rive.Components
{
/// <summary>
/// The hit test behavior of a RiveWidget in relation to other elements.
/// </summary>
public enum HitTestBehavior
{
/// <summary>
/// The bounds of the RiveWidget will consume all hits, even if there is no listener (hit area) at the target point. Content behind the RiveWidget will not receive hits.
/// </summary>
Opaque = 0,
/// <summary>
/// The RiveWidget will only consume hits where there is a listener (hit area) at the target point. Content behind the RiveWidget will only receive hits if no listener was hit.
/// </summary>
Translucent = 1,
/// <summary>
/// All hits will pass through the RiveWidget, regardless of whether a Rive listener was hit. Rive listeners will still receive hits.
/// </summary>
[Obsolete("Transparent hit testing is deprecated, please use Translucent instead.")]
Transparent = 2,
/// <summary>
/// No hit testing will be performed on the RiveWidget.
/// </summary>
None = 3
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 70f512ba226594a9da0ac89681b3070a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/HitTestBehavior.cs
uploadId: 896810

View File

@@ -0,0 +1,42 @@
using System;
using UnityEngine;
namespace Rive.Components
{
/// <summary>
/// Interface for providing input events to a RivePanel.
/// </summary>
public interface IPanelInputProvider
{
/// <summary>
/// Event fired when a pointer is pressed. The Vector2 parameter represents the normalized local point in the panel,
/// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right.
/// </summary>
event Action<PanelPointerEvent> PointerPressed;
/// <summary>
/// Event fired when a pointer is released. The Vector2 parameter represents the normalized local point in the panel,
/// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right.
/// </summary>
event Action<PanelPointerEvent> PointerReleased;
/// <summary>
/// Event fired when a pointer is moved. The Vector2 parameter represents the normalized local point in the panel,
/// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right.
/// </summary>
event Action<PanelPointerEvent> PointerMoved;
/// <summary>
/// Event fired when a pointer exits the panel. The Vector2 parameter represents the normalized local point in the panel,
/// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right.
/// </summary>
event Action<PanelPointerEvent> PointerExited;
/// <summary>
/// Event fired when a pointer enters the panel. The Vector2 parameter represents the normalized local point in the panel,
/// where coordinates are in the range [0,1] with (0,0) at bottom-left and (1,1) at top-right.
/// </summary>
event Action<PanelPointerEvent> PointerEntered;
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 7db5fdfddda6b4de1afcb3f3f7437ea1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/IPanelInputProvider.cs
uploadId: 896810

View File

@@ -0,0 +1,27 @@
using UnityEngine;
namespace Rive.Components
{
/// <summary>
/// Pointer data delivered by input providers and propagated through the panel/widget pipeline.
/// </summary>
public readonly struct PanelPointerEvent
{
public readonly Vector2 Position;
public readonly int PointerId;
/// <summary>
/// Creates a new pointer event for panel input propagation.
/// </summary>
/// <param name="position">
/// The normalized point in panel space [0,1] where (0,0) is bottom-left and (1,1) is top-right.
/// </param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
public PanelPointerEvent(Vector2 position, int pointerId)
{
Position = position;
PointerId = pointerId;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: bfb74b0293d1b4c07922c10574a0abd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelPointerEvent.cs
uploadId: 896810

View File

@@ -0,0 +1,140 @@
using System.Collections.Generic;
using Rive.Utils;
using UnityEngine;
namespace Rive.Components
{
/// <summary>
/// Utility class for performing hit testing (raycasting) on RivePanels to detect which widgets are under a given point.
/// This is used to handle input events and determine which widgets should receive pointer interactions.
/// </summary>
public class PanelRaycaster
{
/// <summary>
/// Populates the raycastResults list with the widgets in a RivePanel that are hit by the given normalized local point in the panel.
/// </summary>
/// <param name="rivePanel"> The RivePanel to check for hit widgets. </param>
/// <param name="normalizedPointInPanel"> The normalized local point in the panel to check for hit widgets. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. </param>
/// <param name="eventCamera"> The camera used by the event system or canvas </param>
/// <param name="raycastResults"> The list to populate with hit widgets. </param>
public static void RaycastAll(IRivePanel rivePanel, Vector2 normalizedPointInPanel, List<IRiveWidget> raycastResults)
{
RectTransform panelRectTransform = rivePanel.WidgetContainer;
if (panelRectTransform == null)
{
DebugLogger.Instance.LogError("Panel RectTransform is null.");
return;
}
for (int i = rivePanel.Widgets.Count - 1; i >= 0; i--)
{
var widget = rivePanel.Widgets[i];
if (widget == null || !widget.Enabled || widget.RenderObject == null || widget.HitTestBehavior == HitTestBehavior.None)
continue;
Vector2 normalizedWidgetPoint;
bool isWithinWidgetBounds = TryGetNormalizedPointInWidget(rivePanel, normalizedPointInPanel, widget, out normalizedWidgetPoint);
if (ProcessHitTestBehavior(widget, normalizedWidgetPoint, raycastResults, isWithinWidgetBounds))
{
return;
}
}
}
/// <summary>
/// Processes the hit test behavior of a widget and adds it to the raycastResults list if it should be hit.
/// </summary>
/// <param name="widget"> The widget to process. </param>
/// <param name="normalizedPointInWidgetRect"> The normalized point in the widget's rect to check for a hit. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner. </param>
/// <param name="raycastResults"> The list to populate with hit widgets. </param>
/// <returns> True if should should block other widgets from being hit, false otherwise. </returns>
private static bool ProcessHitTestBehavior(IRiveWidget widget, Vector2 normalizedPointInWidgetRect, List<IRiveWidget> raycastResults, bool isWithinWidgetBounds)
{
switch (widget.HitTestBehavior)
{
case HitTestBehavior.Opaque:
raycastResults.Add(widget);
// Block other widgets from being hit if the pointer is within the widget
return isWithinWidgetBounds;
case HitTestBehavior.Translucent:
bool foundHit = widget.HitTest(normalizedPointInWidgetRect);
if (foundHit)
{
raycastResults.Add(widget);
return isWithinWidgetBounds;
}
break;
#pragma warning disable CS0618 // Transparent hit testing is deprecated but kept for backward compatibility
case HitTestBehavior.Transparent:
raycastResults.Add(widget);
// Continue checking other widgets
return false;
#pragma warning restore CS0618
case HitTestBehavior.None:
// Do not add to raycastResults
return false;
}
return false;
}
/// <summary>
/// Tries to get the normalized local point in the widget from the normalized local point in the panel.
/// </summary>
/// <param name="rivePanel"> The RivePanel that contains the widget. </param>
/// <param name="normalizedPointInPanel"> The normalized local point in the panel. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="widget"> The widget to get the normalized local point in. </param>
/// <param name="normalizedWidgetPoint"> The normalized point in the widget's rect. </param>
/// <returns> True if the normalized local point is within the widget's bounds, false otherwise. </returns>
public static bool TryGetNormalizedPointInWidget(IRivePanel rivePanel, Vector2 normalizedPointInPanel, IRiveWidget widget, out Vector2 normalizedWidgetPoint)
{
normalizedWidgetPoint = Vector2.zero;
RectTransform panelRectTransform = rivePanel.WidgetContainer;
if (panelRectTransform == null)
{
DebugLogger.Instance.LogError("Panel RectTransform is null.");
return false;
}
var panelRect = panelRectTransform.rect;
if (panelRect.width <= 0f || panelRect.height <= 0f)
{
return false;
}
// We need to turn the normalized point (0..1) into a local point on the panel.
// Unitys RectTransform coordinates are based on the pivot, not always the center.
// So when the pivot changes, the rects xMin/yMin shift too. If we ignore that, input gets offset.
// Using xMin/yMin + (normalized * size) lets us rebuild the original local point again, so everything stays lined up.
Vector2 panelLocalPoint = new Vector2(
panelRect.xMin + (normalizedPointInPanel.x * panelRect.width),
panelRect.yMin + (normalizedPointInPanel.y * panelRect.height)
);
Vector3 worldPoint = panelRectTransform.TransformPoint(panelLocalPoint);
Vector3 widgetLocalPoint = widget.RectTransform.InverseTransformPoint(worldPoint);
normalizedWidgetPoint = new Vector2(
(widgetLocalPoint.x - widget.RectTransform.rect.xMin) / widget.RectTransform.rect.width,
(widgetLocalPoint.y - widget.RectTransform.rect.yMin) / widget.RectTransform.rect.height
);
if (widget.RectTransform.rect.Contains(widgetLocalPoint))
{
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: cc94d7864e5db458e990e4d9fdd933d3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/HitTesting/PanelRaycaster.cs
uploadId: 896810