WIP selection rect work, but not clicking

This commit is contained in:
Lucas 2025-07-23 13:05:53 +02:00
parent f7a801ba20
commit 90b1737fb2
No known key found for this signature in database
5 changed files with 183 additions and 34 deletions

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=11 format=3 uid="uid://qbceryqqfoum"]
[gd_scene load_steps=12 format=3 uid="uid://qbceryqqfoum"]
[ext_resource type="Texture2D" uid="uid://bsnc11pwypbny" path="res://packs/Kaykit-Proto/obj/prototypebits_texture.png" id="1_6oykk"]
[ext_resource type="Script" uid="uid://b8p60y4eo8w2n" path="res://core/scripts/entity.gd" id="1_w0ui8"]
@ -10,6 +10,9 @@
[ext_resource type="ArrayMesh" uid="uid://b7cky6rmvhxl8" path="res://packs/Kaykit-Proto/obj/Dummy_Base_Dummy_Body_Dummy_Target.obj" id="7_d3okb"]
[ext_resource type="Texture2D" uid="uid://cg3hn4l231fws" path="res://packs/Kenney-BoardGamesIcon/chess_rook_red.svg" id="8_15r82"]
[sub_resource type="BoxShape3D" id="BoxShape3D_w0ui8"]
size = Vector3(1, 2, 1)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_th4ew"]
albedo_texture = ExtResource("1_6oykk")
@ -18,6 +21,13 @@ transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, 0, 0, 0)
script = ExtResource("1_w0ui8")
metadata/_custom_type_script = "uid://b8p60y4eo8w2n"
[node name="StaticBody3D" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0267677, 0)
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.11408532, 0)
shape = SubResource("BoxShape3D_w0ui8")
[node name="DummyBase" type="MeshInstance3D" parent="."]
material_override = SubResource("StandardMaterial3D_th4ew")
mesh = ExtResource("2_4axxu")

View file

@ -37,20 +37,20 @@ func is_under_mouse(raycast:Dictionary) -> bool:
func get_entity_aabb(node: Node3D = self, ignore_top_level: bool = true, bounds_transform: Transform3D = Transform3D()) -> AABB:
if node == null: return AABB()
var box: AABB
var transform: Transform3D
var node_transform: Transform3D
# we are going down the child chain, we want the aabb of each subsequent node to be on the same axis as the parent
if bounds_transform.is_equal_approx(Transform3D()):
transform = node.global_transform
node_transform = node.global_transform
else:
transform = bounds_transform
node_transform = bounds_transform
# no more nodes. return default aabb
if node == null:
return AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4))
# makes sure the transform we get isn't distorted
var top_xform : Transform3D = transform.affine_inverse() * node.global_transform
var top_xform : Transform3D = node_transform.affine_inverse() * node.global_transform
# convert the node into visualinstance3D to access get_aabb() function.
var visual_result : VisualInstance3D = node as VisualInstance3D

View file

@ -7,5 +7,5 @@ func _ready() -> void:
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
func _process(_delta: float) -> void:
pass

View file

@ -1,13 +1,14 @@
extends Control
class_name SelectionManager
var selecting:=false
var draw_selection := false
var drag_start: Vector2
var select_box: Rect2
@onready var box_color: Color = ProjectSettings.get_setting("game/interface/selection_rectangle_color",Color("#00ff0066"))
@onready var box_color_outline: Color = ProjectSettings.get_setting("game/interface/selection_rectangle_color_outline",Color("#00ff00"))
var perform_selection := false # Flag to trigger selection in _physics_process
@onready var optimized_rect:bool = ProjectSettings.get_setting("game/interface/optimized_rectangle",false)
@onready var box_color: Color = ProjectSettings.get_setting("game/interface/selection_rectangle_color", Color("#00ff0066"))
@onready var box_color_outline: Color = ProjectSettings.get_setting("game/interface/selection_rectangle_color_outline", Color("#00ff00"))
@onready var optimized_rect: bool = ProjectSettings.get_setting("game/interface/optimized_rectangle", false)
@export var rect_style: StyleBoxFlat
@onready var cam = get_viewport().get_camera_3d()
@ -19,53 +20,82 @@ func _ready() -> void:
func _unhandled_input(e: InputEvent) -> void:
if e is InputEventMouseButton and e.button_index == MOUSE_BUTTON_LEFT:
if e.pressed:
selecting = true
draw_selection = true
drag_start = e.position
else: # when button is released
selecting = false
else:
# When button is released
draw_selection = false
if drag_start.is_equal_approx(e.position):
select_box = Rect2(e.position, Vector2.ZERO) # when just clicked
# Single click: set a zero-sized selection box
select_box = Rect2(e.position, Vector2.ZERO)
print("one click")
else:
# Drag: calculate the final selection box
var x_min = min(drag_start.x, e.position.x)
var y_min = min(drag_start.y, e.position.y)
select_box = Rect2(x_min, y_min,
max(drag_start.x, e.position.x) - x_min,
max(drag_start.y, e.position.y) - y_min)
perform_selection = true # Trigger selection in _physics_process
queue_redraw()
update_selected_units()
elif selecting and e is InputEventMouseMotion:
elif draw_selection and e is InputEventMouseMotion:
# Update selection box for drawing during drag
var x_min = min(drag_start.x, e.position.x)
var y_min = min(drag_start.y, e.position.y)
select_box = Rect2(x_min,y_min,
max(drag_start.x,e.position.x) - x_min,
max(drag_start.y,e.position.y) - y_min)
select_box = Rect2(x_min, y_min,
max(drag_start.x, e.position.x) - x_min,
max(drag_start.y, e.position.y) - y_min)
update_selected_units()
queue_redraw()
func check_raycast(mouse_pos:Vector2,collision_mask:int=4294967295) -> Dictionary:
func _physics_process(_delta: float) -> void:
if perform_selection:
update_selected_units()
perform_selection = false
func check_raycast(mouse_pos: Vector2, collision_mask: int = 4294967295) -> Dictionary:
var from = cam.project_ray_origin(mouse_pos)
var to = from + cam.project_ray_normal(mouse_pos) * 1000 #Magic number
var to = from + cam.project_ray_normal(mouse_pos) * 1000 # Magic number
var query = PhysicsRayQueryParameters3D.new()
query.from = from ; query.to = to
query.from = from
query.to = to
query.collision_mask = collision_mask
var space_state = cam.get_world_3d().direct_space_state
#DebugTools.DrawLine(from,to,25.0)
return space_state.intersect_ray(query)
#HACK :https://www.youtube.com/watch?v=NxW9t-YgJkM
func update_selected_units() -> void:
var units_array = get_tree().get_nodes_in_group('selectable-entity')
var raycast = check_raycast(get_local_mouse_position(),2)
for entity: Entity in units_array: #TODO: currently searching in all unit in the world. Should search in spawned in the chunk
if entity.is_in_selection(select_box, cam):
entity.select()
elif entity.is_under_mouse(raycast):
entity.select()
var units_array = get_tree().get_nodes_in_group("selectable-entity")
var raycast = {}
# Only perform raycast if it's a single click (zero-sized select_box)
if select_box.size == Vector2.ZERO:
raycast = check_raycast(select_box.position)
if raycast:
print("found ",raycast.collider.name)
#breakpoint
for entity: Entity in units_array:
# TODO: Optimize by searching only in spawned chunks
if select_box.size == Vector2.ZERO:
# Single click: select entity under mouse via raycast
if raycast and entity.is_under_mouse(raycast):
entity.select()
else:
entity.deselect()
else:
entity.deselect()
# Drag: select entities within the selection box
if entity.is_in_selection(select_box, cam):
entity.select()
else:
entity.deselect()
func _draw() -> void:
if not selecting:return
if not (draw_selection or perform_selection):return
if select_box and rect_style:
if optimized_rect:
draw_rect(select_box,box_color)

View file

@ -1,8 +1,117 @@
extends Control
@export var MouseOverlay: Node
@onready var Cam = get_viewport().get_camera_3d()
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
if !OS.is_debug_build():
self.queue_free()
class Line:
var Start:Vector3
var End:Vector3
var LineColor:Color
var time
func _init(Start:Vector3, End:Vector3, LineColor, time):
self.Start = Start
self.End = End
self.LineColor = LineColor
self.time = time
var Lines = []
var RemovedLine = false
func _process(delta):
for i in range(len(Lines)):
Lines[i].time -= delta
if (len(Lines) > 0 || RemovedLine):
queue_redraw() #Calls _draw
RemovedLine = false
func _draw():
for i in range(len(Lines)):
if Lines[i].Start.length() == 0:return
var ScreenPointStart = Cam.unproject_position(Lines[i].Start)
var ScreenPointEnd = Cam.unproject_position(Lines[i].End)
#Dont draw line if either start or end is considered behind the camera
#this causes the line to not be drawn sometimes but avoids a bug where the
#line is drawn incorrectly
if (Cam.is_position_behind(Lines[i].Start) ||
Cam.is_position_behind(Lines[i].End)):
continue
draw_line(ScreenPointStart, ScreenPointEnd, Lines[i].LineColor)
#Remove lines that have timed out
var i = Lines.size() - 1
while (i >= 0):
if (Lines[i].time < 0.0):
Lines.remove_at(i)
RemovedLine = true
i -= 1
## start point, end point, color, time (optional)
func DrawLine(Start, End, time = 0.0, LineColor = Color(1.0, 0.0, 0.0, 1.0)):
Lines.append(Line.new(Start, End, LineColor, time))
## start point, velocity (direction and magnitude), color, time (optional)
func DrawRay(Start, Ray, time = 0.0, LineColor = Color(1.0, 0.0, 0.0, 1.0)):
Lines.append(Line.new(Start, Start + Ray, LineColor, time))
## start point, half extents (float), color, time (optional)
func DrawCube(Center, HalfExtents, time = 0.0, LineColor = Color(1.0, 0.0, 0.0, 1.0)):
#Start at the 'top left'
var LinePointStart = Center
LinePointStart.x -= HalfExtents
LinePointStart.y += HalfExtents
LinePointStart.z -= HalfExtents
#Draw top square
var LinePointEnd = LinePointStart + Vector3(0, 0, HalfExtents * 2.0)
DrawLine(LinePointStart, LinePointEnd, LineColor, time);
LinePointStart = LinePointEnd
LinePointEnd = LinePointStart + Vector3(HalfExtents * 2.0, 0, 0)
DrawLine(LinePointStart, LinePointEnd, LineColor, time);
LinePointStart = LinePointEnd
LinePointEnd = LinePointStart + Vector3(0, 0, -HalfExtents * 2.0)
DrawLine(LinePointStart, LinePointEnd, LineColor, time);
LinePointStart = LinePointEnd
LinePointEnd = LinePointStart + Vector3(-HalfExtents * 2.0, 0, 0)
DrawLine(LinePointStart, LinePointEnd, LineColor, time);
#Draw bottom square
LinePointStart = LinePointEnd + Vector3(0, -HalfExtents * 2.0, 0)
LinePointEnd = LinePointStart + Vector3(0, 0, HalfExtents * 2.0)
DrawLine(LinePointStart, LinePointEnd, LineColor, time);
LinePointStart = LinePointEnd
LinePointEnd = LinePointStart + Vector3(HalfExtents * 2.0, 0, 0)
DrawLine(LinePointStart, LinePointEnd, LineColor, time);
LinePointStart = LinePointEnd
LinePointEnd = LinePointStart + Vector3(0, 0, -HalfExtents * 2.0)
DrawLine(LinePointStart, LinePointEnd, LineColor, time);
LinePointStart = LinePointEnd
LinePointEnd = LinePointStart + Vector3(-HalfExtents * 2.0, 0, 0)
DrawLine(LinePointStart, LinePointEnd, LineColor, time);
#Draw vertical lines
LinePointStart = LinePointEnd
DrawRay(LinePointStart, Vector3(0, HalfExtents * 2.0, 0), LineColor, time)
LinePointStart += Vector3(0, 0, HalfExtents * 2.0)
DrawRay(LinePointStart, Vector3(0, HalfExtents * 2.0, 0), LineColor, time)
LinePointStart += Vector3(HalfExtents * 2.0, 0, 0)
DrawRay(LinePointStart, Vector3(0, HalfExtents * 2.0, 0), LineColor, time)
LinePointStart += Vector3(0, 0, -HalfExtents * 2.0)
DrawRay(LinePointStart, Vector3(0, HalfExtents * 2.0, 0), LineColor, time)