WIP selection rect work, but not clicking
This commit is contained in:
parent
f7a801ba20
commit
90b1737fb2
5 changed files with 183 additions and 34 deletions
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
extends Control
|
||||
class_name SelectionManager
|
||||
|
||||
var selecting:=false
|
||||
var draw_selection := false
|
||||
var drag_start: Vector2
|
||||
var select_box: Rect2
|
||||
var perform_selection := false # Flag to trigger selection in _physics_process
|
||||
|
||||
@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")
|
||||
|
||||
queue_redraw()
|
||||
|
||||
update_selected_units()
|
||||
elif selecting and e is InputEventMouseMotion:
|
||||
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)
|
||||
|
||||
update_selected_units()
|
||||
perform_selection = true # Trigger selection in _physics_process
|
||||
queue_redraw()
|
||||
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)
|
||||
|
||||
queue_redraw()
|
||||
|
||||
|
||||
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 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):
|
||||
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()
|
||||
elif entity.is_under_mouse(raycast):
|
||||
else:
|
||||
entity.deselect()
|
||||
else:
|
||||
# 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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue