Get selection box working and stuff

This commit is contained in:
Joseph Ferano 2025-10-30 09:54:40 +07:00
parent ca7e43a249
commit f1208d5d88
9 changed files with 349 additions and 155 deletions

View File

@ -14,12 +14,12 @@ components {
embedded_components {
id: "collisionobject"
type: "collisionobject"
data: "type: COLLISION_OBJECT_TYPE_KINEMATIC\n"
data: "type: COLLISION_OBJECT_TYPE_TRIGGER\n"
"mass: 0.0\n"
"friction: 0.1\n"
"restitution: 0.5\n"
"group: \"default\"\n"
"mask: \"default\"\n"
"group: \"unit\"\n"
"mask: \"selection\"\n"
"embedded_collision_shape {\n"
" shapes {\n"
" shape_type: TYPE_BOX\n"

View File

@ -2,100 +2,280 @@ tile_set: "/main/terrain.tilesource"
layers {
id: "layer1"
z: 0.0
cell {
x: 1
y: 0
tile: 136
}
cell {
x: 2
y: 0
tile: 137
}
cell {
x: 3
y: 0
tile: 138
}
cell {
x: 4
y: 0
tile: 139
}
cell {
x: 5
y: 0
tile: 140
}
cell {
x: 6
y: 0
tile: 137
}
cell {
x: 7
y: 0
tile: 138
}
cell {
x: 8
y: 0
tile: 139
}
cell {
x: 9
y: 0
tile: 140
}
cell {
x: 10
y: 0
tile: 137
}
cell {
x: 11
y: 0
tile: 138
}
cell {
x: 12
y: 0
tile: 139
}
cell {
x: 13
y: 0
tile: 140
}
cell {
x: 14
y: 0
tile: 137
}
cell {
x: 15
y: 0
tile: 138
}
cell {
x: 16
y: 0
tile: 139
}
cell {
x: 17
y: 0
tile: 140
}
cell {
x: 18
y: 0
tile: 141
}
cell {
x: 1
y: 1
tile: 190
}
cell {
x: 2
y: 1
tile: 119
}
cell {
x: 3
y: 1
tile: 120
}
cell {
x: 4
y: 1
tile: 121
}
cell {
x: 5
y: 1
tile: 122
}
cell {
x: 6
y: 1
tile: 119
}
cell {
x: 7
y: 1
tile: 120
}
cell {
x: 8
y: 1
tile: 121
}
cell {
x: 9
y: 1
tile: 122
}
cell {
x: 10
y: 1
tile: 119
}
cell {
x: 11
y: 1
tile: 120
}
cell {
x: 12
y: 1
tile: 121
}
cell {
x: 13
y: 1
tile: 122
}
cell {
x: 14
y: 1
tile: 119
}
cell {
x: 15
y: 1
tile: 120
}
cell {
x: 16
y: 1
tile: 121
}
cell {
x: 17
y: 1
tile: 122
}
cell {
x: 18
y: 1
tile: 123
}
cell {
x: 1
y: 2
tile: 90
tile: 100
}
cell {
x: 2
y: 2
tile: 91
tile: 101
}
cell {
x: 3
y: 2
tile: 92
tile: 102
}
cell {
x: 4
y: 2
tile: 93
tile: 103
}
cell {
x: 5
y: 2
tile: 94
tile: 104
}
cell {
x: 6
y: 2
tile: 91
tile: 101
}
cell {
x: 7
y: 2
tile: 92
tile: 102
}
cell {
x: 8
y: 2
tile: 93
tile: 103
}
cell {
x: 9
y: 2
tile: 94
tile: 104
}
cell {
x: 10
y: 2
tile: 91
tile: 101
}
cell {
x: 11
y: 2
tile: 92
tile: 102
}
cell {
x: 12
y: 2
tile: 93
tile: 103
}
cell {
x: 13
y: 2
tile: 94
tile: 104
}
cell {
x: 14
y: 2
tile: 91
tile: 101
}
cell {
x: 15
y: 2
tile: 92
tile: 102
}
cell {
x: 16
y: 2
tile: 93
tile: 103
}
cell {
x: 17
y: 2
tile: 94
tile: 104
}
cell {
x: 18
y: 2
tile: 95
tile: 105
}
cell {
x: 1
y: 3
tile: 72
tile: 82
}
cell {
x: 2
@ -180,12 +360,12 @@ layers {
cell {
x: 18
y: 3
tile: 77
tile: 87
}
cell {
x: 1
y: 4
tile: 54
tile: 64
}
cell {
x: 2
@ -270,12 +450,12 @@ layers {
cell {
x: 18
y: 4
tile: 59
tile: 69
}
cell {
x: 1
y: 5
tile: 36
tile: 46
}
cell {
x: 2
@ -360,12 +540,12 @@ layers {
cell {
x: 18
y: 5
tile: 41
tile: 51
}
cell {
x: 1
y: 6
tile: 18
tile: 28
}
cell {
x: 2
@ -450,12 +630,12 @@ layers {
cell {
x: 18
y: 6
tile: 23
tile: 33
}
cell {
x: 1
y: 7
tile: 72
tile: 82
}
cell {
x: 2
@ -540,12 +720,12 @@ layers {
cell {
x: 18
y: 7
tile: 77
tile: 87
}
cell {
x: 1
y: 8
tile: 54
tile: 64
}
cell {
x: 2
@ -630,12 +810,12 @@ layers {
cell {
x: 18
y: 8
tile: 59
tile: 69
}
cell {
x: 1
y: 9
tile: 36
tile: 46
}
cell {
x: 2
@ -720,12 +900,12 @@ layers {
cell {
x: 18
y: 9
tile: 41
tile: 51
}
cell {
x: 1
y: 10
tile: 18
tile: 28
}
cell {
x: 2
@ -810,12 +990,12 @@ layers {
cell {
x: 18
y: 10
tile: 23
tile: 33
}
cell {
x: 1
y: 11
tile: 72
tile: 82
}
cell {
x: 2
@ -900,12 +1080,12 @@ layers {
cell {
x: 18
y: 11
tile: 77
tile: 87
}
cell {
x: 1
y: 12
tile: 54
tile: 64
}
cell {
x: 2
@ -990,12 +1170,12 @@ layers {
cell {
x: 18
y: 12
tile: 59
tile: 69
}
cell {
x: 1
y: 13
tile: 36
tile: 46
}
cell {
x: 2
@ -1080,12 +1260,12 @@ layers {
cell {
x: 18
y: 13
tile: 41
tile: 51
}
cell {
x: 1
y: 14
tile: 18
tile: 28
}
cell {
x: 2
@ -1170,97 +1350,97 @@ layers {
cell {
x: 18
y: 14
tile: 23
tile: 33
}
cell {
x: 1
y: 15
tile: 0
tile: 10
}
cell {
x: 2
y: 15
tile: 1
tile: 11
}
cell {
x: 3
y: 15
tile: 2
tile: 12
}
cell {
x: 4
y: 15
tile: 3
tile: 13
}
cell {
x: 5
y: 15
tile: 4
tile: 14
}
cell {
x: 6
y: 15
tile: 1
tile: 11
}
cell {
x: 7
y: 15
tile: 2
tile: 12
}
cell {
x: 8
y: 15
tile: 3
tile: 13
}
cell {
x: 9
y: 15
tile: 4
tile: 14
}
cell {
x: 10
y: 15
tile: 1
tile: 11
}
cell {
x: 11
y: 15
tile: 2
tile: 12
}
cell {
x: 12
y: 15
tile: 3
tile: 13
}
cell {
x: 13
y: 15
tile: 4
tile: 14
}
cell {
x: 14
y: 15
tile: 1
tile: 11
}
cell {
x: 15
y: 15
tile: 2
tile: 12
}
cell {
x: 16
y: 15
tile: 3
tile: 13
}
cell {
x: 17
y: 15
tile: 4
tile: 14
}
cell {
x: 18
y: 15
tile: 7
tile: 15
}
}
material: "/builtins/materials/tile_map.material"

View File

@ -16,11 +16,11 @@ instances {
}
}
instances {
id: "knight-blue1"
id: "knight-blue-hello"
prototype: "/main/knight-blue.go"
position {
x: 488.0
y: 162.0
x: 511.0
y: 256.0
}
component_properties {
id: "knight"
@ -67,8 +67,8 @@ instances {
id: "knight-blue4"
prototype: "/main/knight-blue.go"
position {
x: 232.0
y: 414.0
x: 144.0
y: 424.0
}
component_properties {
id: "knight"
@ -97,10 +97,11 @@ instances {
}
instances {
id: "selection_box"
prototype: "/scripts/selection_box.go"
position {
z: 1.0
}
prototype: "/main/selection_box.go"
}
instances {
id: "-Game"
prototype: "/main/Game.go"
}
scale_along_z: 0
embedded_instances {

35
main/selection_box.go Normal file
View File

@ -0,0 +1,35 @@
components {
id: "selection_box"
component: "/main/selection_box.sprite"
}
components {
id: "ControllerManager"
component: "/scripts/ControllerManager.script"
}
embedded_components {
id: "collisionobject"
type: "collisionobject"
data: "type: COLLISION_OBJECT_TYPE_TRIGGER\n"
"mass: 0.0\n"
"friction: 0.1\n"
"restitution: 0.5\n"
"group: \"selection\"\n"
"mask: \"unit\"\n"
"embedded_collision_shape {\n"
" shapes {\n"
" shape_type: TYPE_BOX\n"
" position {\n"
" }\n"
" rotation {\n"
" }\n"
" index: 0\n"
" count: 3\n"
" id: \"box\"\n"
" }\n"
" data: 3.0\n"
" data: 3.0\n"
" data: 0.5\n"
"}\n"
"locked_rotation: true\n"
""
}

View File

@ -1,2 +0,0 @@
default_animation: ""
material: "/builtins/materials/sprite.material"

View File

@ -1,62 +1,60 @@
-- Control_Manager.script
local utils = require "scripts.utils"
-- Input Variables
local dragging = false
local selection_box
-- Camera Variables
local rts_camera
local rts_camera_size
local inv_matrix -- inverse matrix cached on drag start
-- Position Variables
local start_pos = vmath.vector3()
local prev_pos = vmath.vector3()
function on_reload(self)
-- TODO: Investigate why using `local` wasn't working on reload
-- msg.post(".", "acquire_input_focus")
-- -- NOTE: For some reason I need to also call this on_reload, or else it gets niled out
-- self.rts_camera = msg.url("CameraParent#camera")
-- local DISPLAY_WIDTH = sys.get_config_int("display.width")
-- local DISPLAY_HEIGHT = sys.get_config_int("display.height")
-- self.rts_camera_size = vmath.vector3(DISPLAY_WIDTH, DISPLAY_HEIGHT, 0)
self.selection_collider = msg.url("/selection_box#collisionobject")
end
function init(self)
msg.post(".", "acquire_input_focus") -- Activates to get inputs
selection_box = msg.url("#selection_box") -- Selection Box - Sprite Component
msg.post(selection_box, "disable") -- Sprite Hidden
rts_camera = msg.url("CameraParent#camera") -- Camera Component2
-- Gets Display Properties from System
self.selection_box = msg.url("#selection_box") -- Selection Box - Sprite Component
msg.post(self.selection_box, "disable") -- Sprite Hidden
self.rts_camera = msg.url("CameraParent#camera") -- Camera Component2
self.selection_collider = msg.url("#selection_box/collisionobject")
-- Gets Display Properties from System
local DISPLAY_WIDTH = sys.get_config_int("display.width")
local DISPLAY_HEIGHT = sys.get_config_int("display.height")
-- Get Screen To World Properties
rts_camera_size = vmath.vector3(DISPLAY_WIDTH, DISPLAY_HEIGHT, 0)
self.rts_camera_size = vmath.vector3(DISPLAY_WIDTH, DISPLAY_HEIGHT, 0)
end
local function screen_to_world(x, y)
-- Convert screen coordinates to the [-1, 1] range (Normalized Device Coordinates)
local ndc_x = (x / rts_camera_size.x) * 2 - 1 -- X Ranges From [-1 (left) to 1 (right)]
local ndc_y = (y / rts_camera_size.y) * 2 - 1 -- Y Ranges From [-1 (bottom) to 1 (top)]
-- Applies the inverse camera transformation to convert NDC to world coordinates.
local world = inv_matrix * vmath.vector4(ndc_x, ndc_y, 0, 1) -- NDC position as a 4D vector
-- Converts homogeneous coordinates (x, y, z, w) to 3D world coordinates
-- No effect for orthographic(2D). Depth Scaling For perspective cameras.
return world.x / world.w, world.y / world.w -- Return X, Y
end
local function selection_update_start(action) -- Runs once when pressed
local function selection_update_start(self, action) -- Runs once when pressed
-- Updates Screen_to_World Variables
local projection = camera.get_projection(rts_camera) -- Gets the Projection Size
local view = camera.get_view(rts_camera) -- Gets the View Size
local projection = camera.get_projection(self.rts_camera) -- Gets the Projection Size
local view = camera.get_view(self.rts_camera) -- Gets the View Size
inv_matrix = vmath.inv(projection * view) -- Gets the Inversion
-- Initialize positions
local x, y = screen_to_world(action.x, action.y) -- Gets Global Position
local x, y, _ = utils.screen_to_world(action.x, action.y, 0, "/CameraParent#camera") -- Gets Global Position
start_pos.x, start_pos.y = x, y -- Sets start_pos
prev_pos.x, prev_pos.y = x, y -- Updates prev_pos
-- Update Sprite Properties
go.set_position(start_pos, selection_box) -- Set Position
go.set(selection_box, "size", vmath.vector3(0.1, 0.1, 0)) -- Set Size(0.1) in X, Y
msg.post(selection_box, "enable") -- Sprite Visable
go.set_position(start_pos, self.selection_box) -- Set Position
go.set(self.selection_box, "size", vmath.vector3(0.1, 0.1, -1)) -- Set Size(0.1) in X, Y
msg.post(self.selection_box, "enable") -- Sprite Visable
msg.post("/selection_box#collisionobject", "enable")
dragging = true -- Dragging True
end
local function selection_update_dragging(x, y) -- Runs when Dragging
local function selection_update_dragging(self, x, y) -- Runs when Dragging
-- Calculate bounding box
local min_x = math.min(start_pos.x, x) -- Min X
local min_y = math.min(start_pos.y, y) -- Min Y
@ -64,41 +62,38 @@ local function selection_update_dragging(x, y) -- Runs when Dragging
local max_y = math.max(start_pos.y, y) -- Max Y
-- Calculates the center of the selection box
local center = vmath.vector3(
(min_x + max_x) * 0.5, -- X Direction
(min_y + max_y) * 0.5, -- Y Direction
0 -- Z Direction
)
local center = vmath.vector3((min_x + max_x) * 0.5, (min_y + max_y) * 0.5, 0)
-- Calculate width/height of the selection box from drag distance
-- Ensures a minimum size of 0.1 to prevent the sprite from collapsing
local size = vmath.vector3(
math.max(max_x - min_x, 0.1), -- Width
math.max(max_y - min_y, 0.1), -- Height
0 -- Z Direction
)
-- Calculate width/height of the selection box from drag distance
-- Ensures a minimum size of 0.1 to prevent the sprite from collapsing
local size = vmath.vector3(math.max(max_x - min_x, 0.1),math.max(max_y - min_y, 0.1),0)
-- Set sprite properties
go.set_position(center, selection_box) -- Sets Position
go.set(selection_box, "size", size) -- Sets Size
-- Set sprite properties
go.set_position(center, self.selection_box) -- Sets Position
go.set(self.selection_box, "size", size) -- Sets Size
-- go.set(self.selection_collider, "size", size)
local box = physics.get_shape("/selection_box#collisionobject", "box")
box.dimensions = size
physics.set_shape("/selection_box#collisionobject", "box", box)
end
function on_input(self, action_id, action)
if action_id ~= hash("touch") then return end
if action.pressed and not dragging then
selection_update_start(action) -- Applies Sprite Properties at Start
selection_update_start(self, action) -- Applies Sprite Properties at Start
elseif action.released and dragging then
dragging = false -- Dragging False
msg.post(selection_box, "disable") -- Sprite Hidden
msg.post(self.selection_box, "disable") -- Sprite Hidden
msg.post("/selection_box#collisionobject", "disable")
elseif dragging then
local x, y = screen_to_world(action.x, action.y) -- Gets Global Position
local x, y = utils.screen_to_world(action.x, action.y, 0, "/CameraParent#camera") -- Gets Global Position
-- Only update if position changed
if math.abs(x - prev_pos.x) > 0.001 or math.abs(y - prev_pos.y) > 0.001 then
prev_pos.x, prev_pos.y = x, y -- Updates prev_pos
selection_update_dragging(x, y) -- Applies Sprite Properties during dragging
selection_update_dragging(self, x, y) -- Applies Sprite Properties during dragging
end
end
end

View File

@ -1,7 +1,7 @@
local utils = require "scripts.utils"
function init(self)
-- Add initialization code here
-- Learn more: https://defold.com/manuals/script/
-- Remove this function if not needed
msg.post(".", "acquire_input_focus")
end
function final(self)
@ -31,33 +31,18 @@ function on_message(self, message_id, message, sender)
-- Remove this function if not needed
end
local function screen_to_world(x, y, z, camera_id)
local projection = camera.get_projection(camera_id)
local view = camera.get_view(camera_id)
local w, h = window.get_size()
-- https://defold.com/manuals/camera/#converting-mouse-to-world-coordinates
local inv = vmath.inv(projection * view)
x = (2 * x / w) - 1
y = (2 * y / h) - 1
z = (2 * z) - 1
local x1 = x * inv.m00 + y * inv.m01 + z * inv.m02 + inv.m03
local y1 = x * inv.m10 + y * inv.m11 + z * inv.m12 + inv.m13
local z1 = x * inv.m20 + y * inv.m21 + z * inv.m22 + inv.m23
return x1, y1, z1
end
function on_input(self, action_id, action)
if action_id == hash("left-click") and action.pressed then
if action_id == hash("touch") and action.pressed then
self.next_state = "moving"
local tx, ty, _ = screen_to_world(action.screen_x, action.screen_y, 0, "/CameraParent#camera")
local tx, ty, _ = utils.screen_to_world(action.screen_x, action.screen_y, 0, "/CameraParent#camera")
self.target_pos = vmath.vector3(tx, ty, 0)
elseif action_id == hash("right-click") then
-- msg.post(receiver, message_id, message)
end
end
function on_reload(self)
msg.post(".", "acquire_input_focus")
-- Add reload-handling code here
-- Learn more: https://defold.com/manuals/hot-reload/
-- Remove this function if not needed

View File

@ -5,6 +5,7 @@ function init(self)
self.target_pos = vmath.vector3()
self.state = "idling"
self.next_state = "idling"
self.selected = false
end
local function move_to_target(self, target, dt)
@ -31,9 +32,16 @@ function update(self, dt)
end
function on_message(self, message_id, message, sender)
-- Add message-handling code here
-- Learn more: https://defold.com/manuals/message-passing/
-- Remove this function if not needed
if message_id == hash("collision_response") then
print(go.get_id())
end
if message_id == hash("trigger_response") then
if message.enter then
self.selected = true
else
self.selected = false
end
end
end
function final(self)

View File

@ -1,8 +0,0 @@
components {
id: "selection_box"
component: "/main/selection_box.sprite"
}
components {
id: "ControllerManager"
component: "/scripts/ControllerManager.script"
}