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="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"]
|
[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="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"]
|
[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"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_th4ew"]
|
||||||
albedo_texture = ExtResource("1_6oykk")
|
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")
|
script = ExtResource("1_w0ui8")
|
||||||
metadata/_custom_type_script = "uid://b8p60y4eo8w2n"
|
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="."]
|
[node name="DummyBase" type="MeshInstance3D" parent="."]
|
||||||
material_override = SubResource("StandardMaterial3D_th4ew")
|
material_override = SubResource("StandardMaterial3D_th4ew")
|
||||||
mesh = ExtResource("2_4axxu")
|
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:
|
func get_entity_aabb(node: Node3D = self, ignore_top_level: bool = true, bounds_transform: Transform3D = Transform3D()) -> AABB:
|
||||||
if node == null: return AABB()
|
if node == null: return AABB()
|
||||||
var box: 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
|
# 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()):
|
if bounds_transform.is_equal_approx(Transform3D()):
|
||||||
transform = node.global_transform
|
node_transform = node.global_transform
|
||||||
else:
|
else:
|
||||||
transform = bounds_transform
|
node_transform = bounds_transform
|
||||||
|
|
||||||
# no more nodes. return default aabb
|
# no more nodes. return default aabb
|
||||||
if node == null:
|
if node == null:
|
||||||
return AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4))
|
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
|
# 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.
|
# convert the node into visualinstance3D to access get_aabb() function.
|
||||||
var visual_result : VisualInstance3D = node as VisualInstance3D
|
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.
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
func _process(delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
extends Control
|
extends Control
|
||||||
class_name SelectionManager
|
class_name SelectionManager
|
||||||
|
|
||||||
var selecting:=false
|
var draw_selection := false
|
||||||
var drag_start: Vector2
|
var drag_start: Vector2
|
||||||
var select_box: Rect2
|
var select_box: Rect2
|
||||||
@onready var box_color: Color = ProjectSettings.get_setting("game/interface/selection_rectangle_color",Color("#00ff0066"))
|
var perform_selection := false # Flag to trigger selection in _physics_process
|
||||||
@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)
|
@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
|
@export var rect_style: StyleBoxFlat
|
||||||
@onready var cam = get_viewport().get_camera_3d()
|
@onready var cam = get_viewport().get_camera_3d()
|
||||||
|
|
||||||
|
@ -19,53 +20,82 @@ func _ready() -> void:
|
||||||
func _unhandled_input(e: InputEvent) -> void:
|
func _unhandled_input(e: InputEvent) -> void:
|
||||||
if e is InputEventMouseButton and e.button_index == MOUSE_BUTTON_LEFT:
|
if e is InputEventMouseButton and e.button_index == MOUSE_BUTTON_LEFT:
|
||||||
if e.pressed:
|
if e.pressed:
|
||||||
selecting = true
|
draw_selection = true
|
||||||
drag_start = e.position
|
drag_start = e.position
|
||||||
else: # when button is released
|
else:
|
||||||
selecting = false
|
# When button is released
|
||||||
|
draw_selection = false
|
||||||
if drag_start.is_equal_approx(e.position):
|
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")
|
print("one click")
|
||||||
|
else:
|
||||||
queue_redraw()
|
# Drag: calculate the final selection box
|
||||||
|
|
||||||
update_selected_units()
|
|
||||||
elif selecting and e is InputEventMouseMotion:
|
|
||||||
var x_min = min(drag_start.x, e.position.x)
|
var x_min = min(drag_start.x, e.position.x)
|
||||||
var y_min = min(drag_start.y, e.position.y)
|
var y_min = min(drag_start.y, e.position.y)
|
||||||
select_box = Rect2(x_min,y_min,
|
select_box = Rect2(x_min, y_min,
|
||||||
max(drag_start.x,e.position.x) - x_min,
|
max(drag_start.x, e.position.x) - x_min,
|
||||||
max(drag_start.y,e.position.y) - y_min)
|
max(drag_start.y, e.position.y) - y_min)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
update_selected_units()
|
|
||||||
queue_redraw()
|
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 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()
|
var query = PhysicsRayQueryParameters3D.new()
|
||||||
query.from = from ; query.to = to
|
query.from = from
|
||||||
|
query.to = to
|
||||||
query.collision_mask = collision_mask
|
query.collision_mask = collision_mask
|
||||||
var space_state = cam.get_world_3d().direct_space_state
|
var space_state = cam.get_world_3d().direct_space_state
|
||||||
|
#DebugTools.DrawLine(from,to,25.0)
|
||||||
return space_state.intersect_ray(query)
|
return space_state.intersect_ray(query)
|
||||||
|
|
||||||
|
|
||||||
#HACK :https://www.youtube.com/watch?v=NxW9t-YgJkM
|
|
||||||
func update_selected_units() -> void:
|
func update_selected_units() -> void:
|
||||||
var units_array = get_tree().get_nodes_in_group('selectable-entity')
|
var units_array = get_tree().get_nodes_in_group("selectable-entity")
|
||||||
var raycast = check_raycast(get_local_mouse_position(),2)
|
var raycast = {}
|
||||||
for entity: Entity in units_array: #TODO: currently searching in all unit in the world. Should search in spawned in the chunk
|
# Only perform raycast if it's a single click (zero-sized select_box)
|
||||||
if entity.is_in_selection(select_box, cam):
|
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()
|
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()
|
entity.select()
|
||||||
else:
|
else:
|
||||||
entity.deselect()
|
entity.deselect()
|
||||||
|
|
||||||
|
|
||||||
func _draw() -> void:
|
func _draw() -> void:
|
||||||
if not selecting:return
|
if not (draw_selection or perform_selection):return
|
||||||
if select_box and rect_style:
|
if select_box and rect_style:
|
||||||
if optimized_rect:
|
if optimized_rect:
|
||||||
draw_rect(select_box,box_color)
|
draw_rect(select_box,box_color)
|
||||||
|
|
|
@ -1,8 +1,117 @@
|
||||||
extends Control
|
extends Control
|
||||||
@export var MouseOverlay: Node
|
@export var MouseOverlay: Node
|
||||||
|
@onready var Cam = get_viewport().get_camera_3d()
|
||||||
|
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if !OS.is_debug_build():
|
if !OS.is_debug_build():
|
||||||
self.queue_free()
|
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