GFramework/GFramework.Core.Godot/component/AbstractDragDropArea2DComponent.cs
GwWuYou 8188ebbe73 refactor(core): 优化架构实例访问方式并增强拖拽组件功能
- 将MArchitecture属性重构为IArchitecture类型的Instance属性
- 移除冗余的Interface属性,统一通过Instance访问架构实例
- 为AbstractDragDrop2DComponentBase组件添加可配置的输入操作名称
- 新增CancelDragInputActionName和SelectInputActionName属性
- 使用属性名替代硬编码字符串来处理拖拽相关输入事件
- 清理代码格式,移除多余空行和调整代码间距
- 更新XML文档注释以反映最新的代码结构和功能说明
2025-12-13 20:05:13 +08:00

127 lines
4.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using GFramework.Core.Godot.extensions;
using Godot;
namespace GFramework.Core.Godot.component;
/// <summary>
/// 抽象拖拽组件类,用于处理节点的拖放逻辑。
/// 实现了 IController 接口以支持架构通信,并通过信号通知拖拽事件的发生。
/// </summary>
public abstract partial class AbstractDragDropArea2DComponent : AbstractDragDrop2DComponentBase
{
/// <summary>
/// 目标区域,通常是可交互的游戏对象(如单位或物品)所在的碰撞区域。
/// </summary>
public required Area2D Target { get; set; }
/// <summary>
/// 节点准备就绪时的回调方法。
/// 在节点添加到场景树后调用,绑定目标区域的输入事件处理器。
/// </summary>
public override void _Ready()
{
Target = GetParent() as Area2D ?? throw new InvalidOperationException("Target must be an Area2D node.");
Target.InputEvent += OnTargetInputEvent;
}
/// <summary>
/// 处理输入事件的回调方法。
/// 根据当前拖拽状态和输入事件类型,执行相应的拖拽操作。
/// </summary>
/// <param name="event">输入事件对象</param>
public override void _Input(InputEvent @event)
{
switch (IsDragging)
{
// 处理取消拖拽操作:当正在拖拽且按下取消拖拽按键时,执行取消拖拽逻辑
case true when Target.IsValidNode() && @event.IsActionPressed(CancelDragInputActionName):
CancelDragging();
// 设置输入为处理,防止输入穿透
this.SetInputAsHandled();
break;
case true when @event.IsActionReleased(SelectInputActionName):
Drop();
break;
}
}
/// <summary>
/// 目标区域的输入事件处理器。
/// 当目标区域接收到输入事件时被调用,用于控制拖拽的开始和结束。
/// </summary>
/// <param name="viewport">事件发生的视口节点</param>
/// <param name="event">输入事件对象</param>
/// <param name="_">事件触点ID未使用</param>
private void OnTargetInputEvent(Node viewport, InputEvent @event, long _)
{
if (!Enable) return;
// 获取当前正在拖拽的对象
var draggingObj = GetTree().GetFirstNodeInGroup(GroupName);
switch (IsDragging)
{
// 处理开始拖拽操作:当未在拖拽状态且按下选择按键时,开始拖拽
case false when
// 如果当前没有拖拽操作且已有其他对象正在拖拽,则直接返回
draggingObj is not null:
return;
case false when @event.IsActionPressed(SelectInputActionName):
StartDragging();
break;
}
}
/// <summary>
/// 每帧更新逻辑,在拖拽过程中持续更新目标的位置。
/// </summary>
/// <param name="delta">与上一帧的时间间隔(秒)。</param>
public override void _Process(double delta)
{
if (IsDragging && Target.IsValidNode()) Target.GlobalPosition = Target.GetGlobalMousePosition() + Offset;
}
/// <summary>
/// 结束拖拽流程的基础方法。
/// 清除拖拽标志位并将目标从拖拽组中移除,恢复其层级顺序。
/// </summary>
private void EndDragging()
{
IsDragging = false;
Target.RemoveFromGroup(GroupName);
Target.ZIndex = ZIndexMin;
}
/// <summary>
/// 执行取消拖拽的操作。
/// 调用 EndDragging 并发出 DragCanceled 信号。
/// </summary>
private void CancelDragging()
{
EndDragging();
EmitSignalDragCanceled(StartingPosition);
}
/// <summary>
/// 开始拖拽操作。
/// 设置初始位置和偏移量,将目标加入拖拽组并提升显示层级,最后发出 DragStarted 信号。
/// </summary>
private void StartDragging()
{
IsDragging = true;
StartingPosition = Target.GlobalPosition;
Target.AddToGroup(GroupName);
Target.ZIndex = ZIndexMax;
Offset = Target.GlobalPosition - Target.GetGlobalMousePosition();
EmitSignalDragStarted();
}
/// <summary>
/// 完成一次拖拽操作。
/// 调用 EndDragging 方法并发出 Dropped 信号。
/// </summary>
private void Drop()
{
EndDragging();
EmitSignalDropped(StartingPosition);
}
}