代码拉取完成,页面将自动刷新
class_name RTSSelectionNode extends Node2D
#region 信号
## 选择单位的信号
signal units_selected(selected_units: Array[Node])
#endregion 信号
#region 枚举
#endregion 枚举
#region 导出属性
#region 选择框属性设置
@export_group("选择框属性设置")
## 选择框的边框宽度
@export_range(0.0, 10.0, 1.0) var selection_box_border_width: float = 3.0
## 选择框的边框颜色
@export_color_no_alpha var selection_box_border_color: Color = Color.BLUE
## 选择框边框颜色的Alpha分量。在 0 到 1 的范围内。0 表示该颜色完全透明。1 表示该颜色完全不透明。
@export_range(0.0, 1.0, 0.1) var selection_box_border_color_alpha: float = 0.5
## 是否用填充色填充选择框。如果选择框的宽度或者高度小于边框宽度的两倍,不会绘制填充色。
@export var selection_box_filled: bool = true
## 选择框的填充色
@export_color_no_alpha var selection_box_fill_color: Color = Color.SKY_BLUE
## 选择框填充色的Alpha分量。在 0 到 1 的范围内。0 表示该颜色完全透明。1 表示该颜色完全不透明。
@export_range(0.0, 1.0, 0.1) var selection_box_fill_color_alpha: float = 0.5
#endregion 选择框属性设置
#region 单位分组名称设置
@export_group("单位分组名称设置")
## 己方单位的分组名称
@export var own_units_group_names: Array[String] = [ "own_unit" ]
## 己方建筑的分组名称[br]
## (注意:建筑属于特殊类型的单位,只有点击才能选中建筑)
@export var own_buildings_group_names: Array[String] = [ "own_building" ]
## 盟友单位的分组名称
@export var allied_units_group_names: Array[String] = [ "allied_unit" ]
## 盟友建筑的分组名称
@export var allied_buildings_group_names: Array[String] = [ "allied_building" ]
## 敌方单位的分组名称
@export var enemy_units_group_names: Array[String] = [ "enemy_unit" ]
## 敌方建筑的分组名称
@export var enemy_buildings_group_names: Array[String] = [ "enemy_building" ]
#endregion 单位分组名称设置
#region 选择设置
@export_group("选择设置")
## 最大选择数量,0表示无限制
@export_range(0, 99999, 1) var max_selection_count: int = 0
#endregion 选择设置
#endregion 导出属性
# 选择框的起点
var _selection_start_point: Vector2 = Vector2.ZERO
# 双击
var _double_click: bool = false
# 处理输入
func _input(event: InputEvent) -> void:
# 处理鼠标输入
var input_event_mouse_button: InputEventMouseButton = event as InputEventMouseButton
if input_event_mouse_button and input_event_mouse_button.button_index == MOUSE_BUTTON_LEFT:
if input_event_mouse_button.pressed:
_double_click = input_event_mouse_button.double_click
if _selection_start_point == Vector2.ZERO:
_selection_start_point = get_global_mouse_position()
elif (_selection_start_point != Vector2.ZERO and not input_event_mouse_button.pressed):
var mouse_position: Vector2 = get_global_mouse_position()
var ctrl_pressed: bool = input_event_mouse_button.ctrl_pressed or input_event_mouse_button.meta_pressed
var shift_pressed: bool = input_event_mouse_button.shift_pressed
if _double_click:
# 双击
_handle_double_click(mouse_position, ctrl_pressed, shift_pressed)
else:
if mouse_position.is_equal_approx(_selection_start_point):
# 单击
_handle_click(mouse_position, ctrl_pressed, shift_pressed)
else:
# 框选
_handle_range_select(mouse_position, ctrl_pressed, shift_pressed)
_selection_start_point = Vector2.ZERO
# 处理键盘输入
var input_event_key: InputEventKey = event as InputEventKey
if input_event_key and not input_event_key.pressed:
var keycode: Key = input_event_key.keycode
var ctrl_pressed: bool = input_event_key.ctrl_pressed or input_event_key.meta_pressed
var shift_pressed: bool = input_event_key.shift_pressed
_handle_key_press(keycode, ctrl_pressed, shift_pressed)
func _process(_delta: float) -> void:
queue_redraw()
## 绘制
func _draw() -> void:
_draw_selection_box()
## 绘制选择框
func _draw_selection_box() -> void:
if _selection_start_point == Vector2.ZERO:
return
var mouse_position: Vector2 = get_global_mouse_position()
#绘制边框
var rect: Rect2 = Utility2D.get_rect_from_two_points(_selection_start_point, mouse_position)
var border_color: Color = Color(selection_box_border_color, selection_box_border_color_alpha)
draw_rect(rect, border_color, false, selection_box_border_width)
#绘制填充色
if (not selection_box_filled or rect.size.x <= selection_box_border_width * 2 or
rect.size.y <= selection_box_border_width * 2):
return
var fill_rect: Rect2 = rect.grow(-1.0 * selection_box_border_width)
var fill_color: Color = Color(selection_box_fill_color, selection_box_fill_color_alpha)
draw_rect(fill_rect, fill_color, true, -1.0, false)
## 选择单位,并发出信号
func _select_units() -> void:
if units_selected.get_connections().is_empty():
return
var mouse_position: Vector2 = get_global_mouse_position()
var rect: Rect2 = Utility2D.get_rect_from_two_points(_selection_start_point, mouse_position)
var units_in_group: Array[Node] = get_tree().get_nodes_in_group("unit_group_name")
var selected_units: Array[Node] = []
if not units_in_group.is_empty():
for unit: Node in units_in_group:
selected_units.append(unit)
units_selected.emit(selected_units)
# 选择单位事件处理
func _on_units_selected(selected_units: Array[Node]) -> void:
if selected_units != null and not selected_units.is_empty():
for selected_unit: Node in selected_units:
var unit: Unit = selected_unit as Unit
if is_instance_valid(unit):
unit.selected = true
# 处理双击
func _handle_double_click(mouse_position: Vector2, ctrl_pressed: bool, shift_pressed: bool) -> void:
print("double click", mouse_position, ctrl_pressed,shift_pressed)
pass
# 处理单击
func _handle_click(mouse_position: Vector2, ctrl_pressed: bool, shift_pressed: bool) -> void:
print("click", mouse_position, ctrl_pressed,shift_pressed)
pass
# 处理框选
func _handle_range_select(mouse_position: Vector2, ctrl_pressed: bool, shift_pressed: bool) -> void:
print("range select", mouse_position, ctrl_pressed,shift_pressed)
pass
# 处理按键
func _handle_key_press(keycode: int, ctrl_pressed: bool, shift_pressed: bool) -> void:
print("key press", keycode, ctrl_pressed,shift_pressed)
pass
# 获取所有的单位、建筑分组名称数组
func _get_all_group_names() -> Array[String]:
var names: Array[String] = []
if own_units_group_names and not own_units_group_names.is_empty():
names.append_array(own_units_group_names)
if own_buildings_group_names and not own_buildings_group_names.is_empty():
names.append_array(own_buildings_group_names)
if allied_units_group_names and not allied_units_group_names.is_empty():
names.append_array(allied_units_group_names)
if allied_buildings_group_names and not allied_buildings_group_names.is_empty():
names.append_array(allied_buildings_group_names)
if enemy_units_group_names and not enemy_units_group_names.is_empty():
names.append_array(enemy_units_group_names)
if enemy_buildings_group_names and not enemy_buildings_group_names.is_empty():
names.append_array(enemy_buildings_group_names)
return names
# 获取特定位置第一个匹配的单位
func _get_first_unit_at_point(pos: Vector2) -> Node:
var scene_tree: SceneTree = get_tree()
var unit: Node
unit = Utility2D.get_first_unit_in_groups_at_point(scene_tree, own_units_group_names, pos)
if unit:
return unit
unit = Utility2D.get_first_unit_in_groups_at_point(scene_tree, own_buildings_group_names, pos)
if unit:
return unit
unit = Utility2D.get_first_unit_in_groups_at_point(scene_tree, allied_units_group_names, pos)
if unit:
return unit
unit = Utility2D.get_first_unit_in_groups_at_point(scene_tree, allied_buildings_group_names, pos)
if unit:
return unit
unit = Utility2D.get_first_unit_in_groups_at_point(scene_tree, enemy_units_group_names, pos)
if unit:
return unit
unit = Utility2D.get_first_unit_in_groups_at_point(scene_tree, enemy_buildings_group_names, pos)
if unit:
return unit
return null
# 获取当前视口中相同的单位
func _get_same_units_in_viewport(groups: Array[String], unit: Node) -> Array[Node]:
var scene_tree: SceneTree = get_tree()
if not scene_tree:
return []
var canvas_item: CanvasItem = unit as CanvasItem
if not canvas_item:
return []
var range: Rect2 = Utility2D.get_viewport_rect(canvas_item)
var dict: Dictionary = Utility2D.get_units_in_groups_in_range(scene_tree, groups, range)
var class_and_script_name: String = Utility2D.get_object_class_and_script_name(unit)
var units: Dictionary = Utility2D.get_units_in_class(dict, class_and_script_name)
if not units or units.is_empty():
return []
return units.values()
func _ready() -> void:
pass
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。