diff --git a/Packs/Kaykit-Proto/obj/dummy.tscn b/Packs/Kaykit-Proto/obj/dummy.tscn index e4851bd..4b5d8a4 100644 --- a/Packs/Kaykit-Proto/obj/dummy.tscn +++ b/Packs/Kaykit-Proto/obj/dummy.tscn @@ -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") diff --git a/core/scripts/entity.gd b/core/scripts/entity.gd index 3e7bc93..d69e400 100644 --- a/core/scripts/entity.gd +++ b/core/scripts/entity.gd @@ -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 diff --git a/core/scripts/player_interface.gd b/core/scripts/player_interface.gd index a1d4176..eeae500 100644 --- a/core/scripts/player_interface.gd +++ b/core/scripts/player_interface.gd @@ -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 diff --git a/core/scripts/player_selection_manager.gd b/core/scripts/player_selection_manager.gd index 8472325..f8fb9f9 100644 --- a/core/scripts/player_selection_manager.gd +++ b/core/scripts/player_selection_manager.gd @@ -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) diff --git a/dev/debug_tools.gd b/dev/debug_tools.gd index f2de210..bcc9c84 100644 --- a/dev/debug_tools.gd +++ b/dev/debug_tools.gd @@ -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)