Fix game UI root control to properly raycast over 3D canvases

This commit is contained in:
Wojtek Figat
2024-11-19 00:02:16 +01:00
parent c0a99688f9
commit 36cf859741
2 changed files with 56 additions and 73 deletions

View File

@@ -29,6 +29,33 @@ namespace FlaxEngine.GUI
return ((CanvasRootControl)a).Canvas.Order - ((CanvasRootControl)b).Canvas.Order;
}
private bool RayCast3D(ref Float2 location, out Control hit, out Float2 hitLocation)
{
hit = null;
hitLocation = Float2.Zero;
// Calculate 3D mouse ray
UICanvas.CalculateRay(ref location, out Ray ray);
// Test 3D canvases
var layerMask = MainRenderTask.Instance?.ViewLayersMask ?? LayersMask.Default;
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
{
var child = (CanvasRootControl)_children[i];
if (child.Visible && child.Enabled && child.Is3D && layerMask.HasLayer(child.Canvas.Layer))
{
if (child.Intersects3D(ref ray, out var childLocation))
{
hit = child;
hitLocation = childLocation;
return true;
}
}
}
return false;
}
/// <inheritdoc />
public override void OnChildrenChanged()
{
@@ -63,8 +90,20 @@ namespace FlaxEngine.GUI
/// <inheritdoc />
public override bool RayCast(ref Float2 location, out Control hit)
{
// Ignore self
return RayCastChildren(ref location, out hit);
// Ignore self and only test children
if (RayCastChildren(ref location, out hit))
return true;
// Test 3D
if (RayCast3D(ref location, out hit, out var hitLocation))
{
// Test deeper to hit actual control not the root
hit.RayCast(ref hitLocation, out hit);
if (hit != null)
return true;
}
return false;
}
/// <inheritdoc />
@@ -81,22 +120,10 @@ namespace FlaxEngine.GUI
// 2D GUI first
base.OnMouseEnter(location);
// Calculate 3D mouse ray
UICanvas.CalculateRay(ref location, out Ray ray);
// Test 3D
var layerMask = MainRenderTask.Instance?.ViewLayersMask ?? LayersMask.Default;
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
if (RayCast3D(ref location, out var hit, out var hitLocation))
{
var child = (CanvasRootControl)_children[i];
if (child.Visible && child.Enabled && child.Is3D && layerMask.HasLayer(child.Canvas.Layer))
{
if (child.Intersects3D(ref ray, out var childLocation))
{
child.OnMouseEnter(childLocation);
return;
}
}
hit.OnMouseEnter(hitLocation);
}
}
@@ -170,22 +197,11 @@ namespace FlaxEngine.GUI
if (base.OnMouseWheel(location, delta))
return true;
// Calculate 3D mouse ray
UICanvas.CalculateRay(ref location, out Ray ray);
// Test 3D
var layerMask = MainRenderTask.Instance?.ViewLayersMask ?? LayersMask.Default;
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
if (RayCast3D(ref location, out var hit, out var hitLocation))
{
var child = (CanvasRootControl)_children[i];
if (child.Visible && child.Enabled && child.Is3D && layerMask.HasLayer(child.Canvas.Layer))
{
if (child.Intersects3D(ref ray, out var childLocation))
{
child.OnMouseWheel(childLocation, delta);
return true;
}
}
hit.OnMouseWheel(hitLocation, delta);
return true;
}
return false;
@@ -198,22 +214,11 @@ namespace FlaxEngine.GUI
if (base.OnMouseDown(location, button))
return true;
// Calculate 3D mouse ray
UICanvas.CalculateRay(ref location, out Ray ray);
// Test 3D
var layerMask = MainRenderTask.Instance?.ViewLayersMask ?? LayersMask.Default;
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
if (RayCast3D(ref location, out var hit, out var hitLocation))
{
var child = (CanvasRootControl)_children[i];
if (child.Visible && child.Enabled && child.Is3D && layerMask.HasLayer(child.Canvas.Layer))
{
if (child.Intersects3D(ref ray, out var childLocation))
{
child.OnMouseDown(childLocation, button);
return true;
}
}
hit.OnMouseDown(hitLocation, button);
return true;
}
return false;
@@ -226,22 +231,11 @@ namespace FlaxEngine.GUI
if (base.OnMouseUp(location, button))
return true;
// Calculate 3D mouse ray
UICanvas.CalculateRay(ref location, out Ray ray);
// Test 3D
var layerMask = MainRenderTask.Instance?.ViewLayersMask ?? LayersMask.Default;
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
if (RayCast3D(ref location, out var hit, out var hitLocation))
{
var child = (CanvasRootControl)_children[i];
if (child.Visible && child.Enabled && child.Is3D && layerMask.HasLayer(child.Canvas.Layer))
{
if (child.Intersects3D(ref ray, out var childLocation))
{
child.OnMouseUp(childLocation, button);
return true;
}
}
hit.OnMouseUp(hitLocation, button);
return true;
}
return false;
@@ -254,22 +248,11 @@ namespace FlaxEngine.GUI
if (base.OnMouseDoubleClick(location, button))
return true;
// Calculate 3D mouse ray
UICanvas.CalculateRay(ref location, out Ray ray);
// Test 3D
var layerMask = MainRenderTask.Instance?.ViewLayersMask ?? LayersMask.Default;
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
if (RayCast3D(ref location, out var hit, out var hitLocation))
{
var child = (CanvasRootControl)_children[i];
if (child.Visible && child.Enabled && child.Is3D && layerMask.HasLayer(child.Canvas.Layer))
{
if (child.Intersects3D(ref ray, out var childLocation))
{
child.OnMouseDoubleClick(childLocation, button);
return true;
}
}
hit.OnMouseDoubleClick(hitLocation, button);
return true;
}
return false;

View File

@@ -6,7 +6,7 @@ using System.Collections.Generic;
namespace FlaxEngine.GUI
{
/// <summary>
/// GUI root control that is represented by a window or an canvas and can contain children but has no parent at all. It's a source of the input events.
/// GUI root control that is represented by a window or a canvas and can contain children but has no parent at all. It's a source of the input events.
/// </summary>
public abstract class RootControl : ContainerControl
{