我可能会将这个问题分解为两个部分:
- 确定接口对象的顺序。
- 仅在重叠时触发最顶层对象上的事件。
解决第一部分很简单。在指定对象深度的基类中包含一个“层”字段/属性。在大多数游戏节点类中,我无论如何都会包含它,因为它在绘图中很有用。如果事情变得有点复杂,您可能需要一个单独的分层系统来进行接口排序,而这种方法的缺点是您可能会获得层相同的重叠。
正如@Attila 所建议的那样,您可以管理界面元素的 Z 顺序列表。在这种情况下,排序是由索引管理的,它很容易管理,但是如果不进行一些额外的处理,您也不能使用此信息进行绘图,并且它不会像简单的值比较那样快。
财产
public class InterfaceComponent
{
// Class members...
private float layer;
public float Layer { get { return layer; } set { layer = Math.Abs(value); } }
public bool InFrontOf(InterfaceComponent other) { return this.Layer < other.Layer; }
}
Z-有序列表
public class InterfaceComponent
{
private static List<InterfaceComponent> zOrder = new List<InterfaceComponent>();
// Class Members....
public InterfaceComponent()
{
// Construct class...
zOrder.Add(this);
}
private void SetZOrder(int order)
{
if (order < 0 || order >= zOrder.Count)
return;
zOrder.Remove(this);
zOrder.Insert(order, this);
// There are more efficient ways, but you get the idea.
}
public void SendBack() { SetZOrder(zOrder.indexOf(this) + 1); }
public void SendToFront() { SetZOrder(0); }
// etc...
}
第二部分
有多种方法可以处理第二部分。最明显的是检查所有接口组件的交集和图层属性,或者在 Z 顺序列表的情况下,检查列表中较高的所有组件(在我的示例中接近 0)以进行交集。
即使您使用屏幕使列表更小,这最终也会变得非常昂贵。相反,您可以管理引发事件的列表并在处理输入后处理它们。例如...
public static class InterfaceEvents
{
public static List<EventData> List = new List<EventData>();
public static void Resolve()
{
while (List.Count > 0)
{
for (int i = List.Count - 1; i > 0; i--)
{
if (List[i].EventType == List[0].EventType && List[i].Sender.Intersects(List[0].Sender))
{
if (List[i].Sender.Layer < List[0].Layer) // However you choose to manage it.
{
List[0] = List[i];
List.RemoveAt(i);
}
else
List.RemoveAt(i);
}
}
// Toggle event from List[0]
List.RemoveAt(0);
}
}
}
public struct EventData
{
public InterfaceComponent Sender;
public int EventType;
}
无论如何,这些是我的想法。现在已经很晚了,所以我希望一切都保持理智,没有明显的错误。