Binary file not shown.
@@ -265,6 +265,54 @@ do -- INIT UTIL
|
|||||||
return hull
|
return hull
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Splits points into clusters with at least minSeparation between clusters, returns convex hull for each cluster
|
||||||
|
---@param points Array<Vec2>
|
||||||
|
---@param minSeparation number
|
||||||
|
---@return Array<Array<Vec2>> hulls
|
||||||
|
function UTIL.getSeparatedConvexHulls(points, minSeparation)
|
||||||
|
if #points == 0 then return {} end
|
||||||
|
|
||||||
|
-- Simple clustering: group points that are within minSeparation of each other
|
||||||
|
local clusters = {}
|
||||||
|
local assigned = {}
|
||||||
|
|
||||||
|
for i, p in ipairs(points) do
|
||||||
|
if not assigned[i] then
|
||||||
|
local cluster = { p }
|
||||||
|
assigned[i] = true
|
||||||
|
-- Find all points close to p (BFS)
|
||||||
|
local queue = { i }
|
||||||
|
while #queue > 0 do
|
||||||
|
local idx = table.remove(queue)
|
||||||
|
local base = points[idx]
|
||||||
|
for j, q in ipairs(points) do
|
||||||
|
if not assigned[j] then
|
||||||
|
local dx = base.x - q.x
|
||||||
|
local dy = base.y - q.y
|
||||||
|
if (dx * dx + dy * dy) <= (minSeparation * minSeparation) then
|
||||||
|
table.insert(cluster, q)
|
||||||
|
assigned[j] = true
|
||||||
|
table.insert(queue, j)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(clusters, cluster)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Compute convex hull for each cluster
|
||||||
|
local hulls = {}
|
||||||
|
for _, cluster in ipairs(clusters) do
|
||||||
|
local hull = UTIL.getConvexHull(cluster)
|
||||||
|
if #hull > 0 then
|
||||||
|
table.insert(hulls, hull)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return hulls
|
||||||
|
end
|
||||||
|
|
||||||
---@param points Array<Vec2>
|
---@param points Array<Vec2>
|
||||||
function UTIL.enlargeConvexHull(points, meters)
|
function UTIL.enlargeConvexHull(points, meters)
|
||||||
---@type Array<Vec2>
|
---@type Array<Vec2>
|
||||||
@@ -329,6 +377,44 @@ function UTIL.GetVisibleHullPointsFromOrigin(hull, origin)
|
|||||||
return visible
|
return visible
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Returns the two tangent points ("scratch points") from origin to the convex hull
|
||||||
|
---@param hull Array<Vec2>
|
||||||
|
---@param origin Vec2
|
||||||
|
---@return Array<Vec2>
|
||||||
|
function UTIL.GetTangentHullPointsFromOrigin(hull, origin)
|
||||||
|
local function cross(o, a, b)
|
||||||
|
return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x)
|
||||||
|
end
|
||||||
|
|
||||||
|
local n = #hull
|
||||||
|
if n == 0 then return {} end
|
||||||
|
if n == 1 then return { hull[1] } end
|
||||||
|
|
||||||
|
local left, right = nil, nil
|
||||||
|
for i = 1, n do
|
||||||
|
local prev = hull[(i - 2 + n) % n + 1]
|
||||||
|
local curr = hull[i]
|
||||||
|
local next = hull[(i % n) + 1]
|
||||||
|
|
||||||
|
local cp1 = cross(origin, curr, prev)
|
||||||
|
local cp2 = cross(origin, curr, next)
|
||||||
|
|
||||||
|
-- Tangent if the cross products have different signs or one is zero
|
||||||
|
if cp1 * cp2 <= 0 then
|
||||||
|
if not left then
|
||||||
|
left = curr
|
||||||
|
else
|
||||||
|
right = curr
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = {}
|
||||||
|
if left then table.insert(result, left) end
|
||||||
|
if right and right ~= left then table.insert(result, right) end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
Spearhead.Util = UTIL
|
Spearhead.Util = UTIL
|
||||||
|
|
||||||
|
|||||||
@@ -92,48 +92,6 @@ function BattleManager:Update()
|
|||||||
return math.random(4, 10) -- Return a random interval between 5 and 10 seconds for the next update
|
return math.random(4, 10) -- Return a random interval between 5 and 10 seconds for the next update
|
||||||
end
|
end
|
||||||
|
|
||||||
---@private
|
|
||||||
---@param fromGroups Array<SpearheadGroup>
|
|
||||||
---@param targetGroups Array<SpearheadGroup>
|
|
||||||
---@return Array<Vec2>
|
|
||||||
function BattleManager:CalculateShootAtPoints(fromGroups, targetGroups)
|
|
||||||
|
|
||||||
---@type Array<Vec2>
|
|
||||||
local result = {}
|
|
||||||
|
|
||||||
for _, group in pairs(targetGroups) do
|
|
||||||
---@type Array<Vec2>
|
|
||||||
local points = {}
|
|
||||||
|
|
||||||
self._logger:debug("Processing red group: " .. group.groupName)
|
|
||||||
local groupUnits = group:GetAsUnits()
|
|
||||||
for _, unit in pairs(group:GetAsUnits()) do
|
|
||||||
local pos = unit:getPoint()
|
|
||||||
table.insert(points, {x = pos.x, y = pos.z})
|
|
||||||
end
|
|
||||||
|
|
||||||
local hull = Spearhead.Util.getConvexHull(points)
|
|
||||||
local enlargedHull = Spearhead.Util.enlargeConvexHull(hull, 30) -- Enlarge the hull by 50 meters
|
|
||||||
|
|
||||||
local randomGroup = Spearhead.Util.randomFromList(fromGroups) --[[@as SpearheadGroup]]
|
|
||||||
if randomGroup then
|
|
||||||
|
|
||||||
local randomUnit = Spearhead.Util.randomFromList(randomGroup:GetObjects()) --[[@as Object]]
|
|
||||||
local pos = randomUnit:getPoint()
|
|
||||||
|
|
||||||
---@type Vec2
|
|
||||||
local vec2 = {x = pos.x, y = pos.z}
|
|
||||||
|
|
||||||
local shootPoints = Spearhead.Util.GetVisibleHullPointsFromOrigin(enlargedHull, vec2)
|
|
||||||
for _, point in pairs(shootPoints) do
|
|
||||||
table.insert(result, point)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
---@param groups Array<SpearheadGroup>
|
---@param groups Array<SpearheadGroup>
|
||||||
---@param targetGroups Array<SpearheadGroup>
|
---@param targetGroups Array<SpearheadGroup>
|
||||||
@@ -244,15 +202,16 @@ function BattleManager:GetRandomPoint(origin, groups)
|
|||||||
if not group then return nil end
|
if not group then return nil end
|
||||||
|
|
||||||
local points = {}
|
local points = {}
|
||||||
local groupUnits = group:GetAsUnits()
|
|
||||||
for _, unit in pairs(group:GetAsUnits()) do
|
for _, unit in pairs(group:GetAsUnits()) do
|
||||||
local pos = unit:getPoint()
|
local pos = unit:getPoint()
|
||||||
table.insert(points, {x = pos.x, y = pos.z})
|
table.insert(points, {x = pos.x, y = pos.z})
|
||||||
end
|
end
|
||||||
|
|
||||||
local hull = Spearhead.Util.getConvexHull(points)
|
local hulls = Spearhead.Util.getSeparatedConvexHulls(points, 50)
|
||||||
local enlargedHull = Spearhead.Util.enlargeConvexHull(hull, 30)
|
local hull = Spearhead.Util.randomFromList(hulls) --[[@as Array<Vec2>]]
|
||||||
local shootPoints = Spearhead.Util.GetVisibleHullPointsFromOrigin(enlargedHull, origin)
|
local enlargedHull = Spearhead.Util.enlargeConvexHull(hull, 25)
|
||||||
|
local shootPoints = Spearhead.Util.GetTangentHullPointsFromOrigin(enlargedHull, origin)
|
||||||
|
|
||||||
return Spearhead.Util.randomFromList(shootPoints) --[[@as Vec2]]
|
return Spearhead.Util.randomFromList(shootPoints) --[[@as Vec2]]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ SpearheadConfig = {
|
|||||||
maxMissionStage = 10,
|
maxMissionStage = 10,
|
||||||
|
|
||||||
--Stage starting number
|
--Stage starting number
|
||||||
startingStage = 2,
|
startingStage = 1,
|
||||||
|
|
||||||
---DEBUG logging. Consider keeping this disabled
|
---DEBUG logging. Consider keeping this disabled
|
||||||
debugEnabled = true
|
debugEnabled = true
|
||||||
|
|||||||
Reference in New Issue
Block a user