Selection working.
Assuming every single selectable contain an Area3D at the root with selection collision to handle selection
This commit is contained in:
parent
258ffc4523
commit
58df83ec50
5 changed files with 57 additions and 40 deletions
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=12 format=3 uid="uid://qbceryqqfoum"]
|
[gd_scene load_steps=11 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"]
|
||||||
|
@ -8,7 +8,6 @@
|
||||||
[ext_resource type="ArrayMesh" uid="uid://cvlxxld3w6siv" path="res://packs/Kaykit-Proto/obj/Dummy_Base_Dummy_Body_Dummy_ArmRight.obj" id="5_w4l2r"]
|
[ext_resource type="ArrayMesh" uid="uid://cvlxxld3w6siv" path="res://packs/Kaykit-Proto/obj/Dummy_Base_Dummy_Body_Dummy_ArmRight.obj" id="5_w4l2r"]
|
||||||
[ext_resource type="ArrayMesh" uid="uid://6h2lg4h0y0ea" path="res://packs/Kaykit-Proto/obj/Dummy_Base_Dummy_Body_Dummy_Head.obj" id="6_5dfyn"]
|
[ext_resource type="ArrayMesh" uid="uid://6h2lg4h0y0ea" path="res://packs/Kaykit-Proto/obj/Dummy_Base_Dummy_Body_Dummy_Head.obj" id="6_5dfyn"]
|
||||||
[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"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_w0ui8"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_w0ui8"]
|
||||||
size = Vector3(1, 2, 1)
|
size = Vector3(1, 2, 1)
|
||||||
|
@ -21,10 +20,12 @@ 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="."]
|
[node name="SelectionArea" type="Area3D" parent="."]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0267677, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0267677, 0)
|
||||||
|
collision_layer = 32768
|
||||||
|
collision_mask = 0
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="SelectionArea"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.11408532, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.11408532, 0)
|
||||||
shape = SubResource("BoxShape3D_w0ui8")
|
shape = SubResource("BoxShape3D_w0ui8")
|
||||||
|
|
||||||
|
@ -51,8 +52,3 @@ mesh = ExtResource("6_5dfyn")
|
||||||
[node name="DummyBaseDummyBodyDummyTarget" type="MeshInstance3D" parent="."]
|
[node name="DummyBaseDummyBodyDummyTarget" type="MeshInstance3D" parent="."]
|
||||||
material_override = SubResource("StandardMaterial3D_th4ew")
|
material_override = SubResource("StandardMaterial3D_th4ew")
|
||||||
mesh = ExtResource("7_d3okb")
|
mesh = ExtResource("7_d3okb")
|
||||||
|
|
||||||
[node name="TextureRect" type="TextureRect" parent="."]
|
|
||||||
offset_right = 40.0
|
|
||||||
offset_bottom = 40.0
|
|
||||||
texture = ExtResource("8_15r82")
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ ignore_paths=Array[String]([])
|
||||||
|
|
||||||
[patterns]
|
[patterns]
|
||||||
|
|
||||||
patterns=[["\\bTODO\\b", Color(0.588235, 0.945098, 0.678431, 1), 0], ["\\bHACK\\b", Color(0.835294, 0.737255, 0.439216, 1), 0], ["\\bFIXME\\b", Color(0.835294, 0.439216, 0.439216, 1), 0]]
|
patterns=[["\\bTODO\\b", Color(0.588235, 0.945098, 0.678431, 1), 0], ["\\bHACK\\b", Color(0.835294, 0.737255, 0.439216, 1), 0], ["\\bFIXME\\b", Color(0.835294, 0.439216, 0.439216, 1), 0], ["\\bBUG\\b", Color(0.9607843, 0.48682597, 0.4509804, 1), 0]]
|
||||||
|
|
||||||
[config]
|
[config]
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@icon('uid://br8ndde8qty32')
|
@icon('uid://br8ndde8qty32')
|
||||||
extends Node
|
extends Node3D
|
||||||
class_name Entity
|
class_name Entity
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ class_name Entity
|
||||||
## Is a node, because we want to deactivate rendering when out of camera and only simulating the world.
|
## Is a node, because we want to deactivate rendering when out of camera and only simulating the world.
|
||||||
## Plus, only the entity is replicated in multiplayer
|
## Plus, only the entity is replicated in multiplayer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
add_to_group('entity')
|
|
||||||
add_to_group('selectable-entity')
|
add_to_group('selectable-entity')
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,17 +26,8 @@ func is_in_selection(selection_box:Rect2,player_cam:Camera3D) -> bool:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
||||||
## Check if the entity is under the raycast (usually made by [method SelectionManager.check_raycast])
|
|
||||||
## and colliding with entity bouding box
|
|
||||||
func is_under_mouse(raycast:Dictionary) -> bool:
|
|
||||||
if raycast:
|
|
||||||
var aabb:AABB = get_entity_aabb()
|
|
||||||
return aabb.has_point(raycast.position)
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
|
|
||||||
## Calculate the node bouding box
|
## Calculate the node bouding box
|
||||||
|
## @deprecated
|
||||||
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
|
||||||
|
|
|
@ -11,6 +11,7 @@ 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 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()
|
||||||
|
@onready var hovercontrol:Button = $"../Button"
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
@ -48,6 +49,8 @@ func _unhandled_input(e: InputEvent) -> void:
|
||||||
max(drag_start.y, e.position.y) - y_min)
|
max(drag_start.y, e.position.y) - y_min)
|
||||||
|
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
if !draw_selection and e is InputEventMouseMotion:
|
||||||
|
check_hover()
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(_delta: float) -> void:
|
func _physics_process(_delta: float) -> void:
|
||||||
|
@ -56,38 +59,60 @@ func _physics_process(_delta: float) -> void:
|
||||||
perform_selection = false
|
perform_selection = false
|
||||||
|
|
||||||
|
|
||||||
func check_raycast(mouse_pos: Vector2, collision_mask: int = 4294967295) -> Dictionary:
|
func check_hover():
|
||||||
|
# TODO: Hovering and display names
|
||||||
|
var selected = get_selected()
|
||||||
|
if selected.size() > 0:
|
||||||
|
hovercontrol.text = selected[0].name
|
||||||
|
else:
|
||||||
|
hovercontrol.text = ""
|
||||||
|
|
||||||
|
hovercontrol.queue_redraw()
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func get_selected() -> Array[Entity]:
|
||||||
|
var selected: Array[Node] = get_tree().get_nodes_in_group('selected-by-'+str(get_tree().get_multiplayer().get_unique_id()))
|
||||||
|
var selected_entity: Array[Entity]
|
||||||
|
selected_entity.assign(selected)
|
||||||
|
return selected_entity
|
||||||
|
|
||||||
|
|
||||||
|
## [param collision_mask] is 32768 by default, so the collision channel 16
|
||||||
|
func check_raycast(mouse_pos: Vector2, collision_mask: int = 32768) -> 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.create(from,to,collision_mask)
|
||||||
query.from = from
|
query.collide_with_areas = true
|
||||||
query.to = to
|
query.collide_with_bodies = false
|
||||||
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)
|
#DebugTools.DrawLine(from,to,25.0)
|
||||||
return space_state.intersect_ray(query)
|
return space_state.intersect_ray(query)
|
||||||
|
|
||||||
|
|
||||||
|
func deselect_all() -> void:
|
||||||
|
var selected = get_selected()
|
||||||
|
for entity:Entity in selected:
|
||||||
|
entity.deselect()
|
||||||
|
|
||||||
|
|
||||||
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 = {}
|
var raycast = {}
|
||||||
# Only perform raycast if it's a single click (zero-sized select_box)
|
# Only perform raycast if it's a single click (zero-sized select_box)
|
||||||
if select_box.size == Vector2.ZERO:
|
if select_box.size == Vector2.ZERO:
|
||||||
raycast = check_raycast(select_box.position)
|
raycast = check_raycast(select_box.position,)
|
||||||
if raycast:
|
if raycast and raycast.collider:
|
||||||
print("found ",raycast.collider.name)
|
# select entity under mouse
|
||||||
#breakpoint
|
# maybe can be extracted from hover instead?
|
||||||
|
var entity = raycast.collider.get_parent()
|
||||||
|
deselect_all()
|
||||||
|
entity.select()
|
||||||
|
# BUG: Deselect previous selection
|
||||||
|
return
|
||||||
for entity: Entity in units_array:
|
for entity: Entity in units_array:
|
||||||
# TODO: Optimize by searching only in spawned chunks
|
# TODO: Optimize by searching only in spawned chunks
|
||||||
if select_box.size == Vector2.ZERO:
|
# select entities within the selection/draggin box
|
||||||
# Single click: select entity under mouse via raycast
|
|
||||||
if raycast and entity.is_under_mouse(raycast):
|
|
||||||
entity.select()
|
|
||||||
else:
|
|
||||||
entity.deselect()
|
|
||||||
else:
|
|
||||||
# Drag: select entities within the selection box
|
|
||||||
if entity.is_in_selection(select_box, cam):
|
if entity.is_in_selection(select_box, cam):
|
||||||
entity.select()
|
entity.select()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -109,6 +109,11 @@ locale/locale_filter_mode=1
|
||||||
locale/language_filter=["en", "fr"]
|
locale/language_filter=["en", "fr"]
|
||||||
locale/country_filter=["FR"]
|
locale/country_filter=["FR"]
|
||||||
|
|
||||||
|
[layer_names]
|
||||||
|
|
||||||
|
3d_physics/layer_1="Static"
|
||||||
|
3d_physics/layer_16="Selection"
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
3d/run_on_separate_thread=true
|
3d/run_on_separate_thread=true
|
||||||
|
|
Loading…
Reference in a new issue