|
@ -75,27 +75,12 @@ function tile_is_medium_elevation(tile) |
|
|
return tile.elevation >= -0.5 and tile.elevation < 0.5 |
|
|
return tile.elevation >= -0.5 and tile.elevation < 0.5 |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
function color_at(elevation) |
|
|
|
|
|
if elevation < -0.5 then -- lowest elevation |
|
|
|
|
|
return COLORS.WATER{ a = (elevation + 1.4) / 2 + 0.2 } |
|
|
|
|
|
|
|
|
|
|
|
elseif elevation < 0 then -- med-low elevation |
|
|
|
|
|
return math.lerp(COLORS.DIRT, COLORS.GRASS, elevation + 0.5){ a = (elevation + 1.8) / 2 + 0.3 } |
|
|
|
|
|
|
|
|
|
|
|
elseif elevation < 0.5 then -- med-high elevation |
|
|
|
|
|
return math.lerp(COLORS.DIRT, COLORS.GRASS, elevation + 0.5){ a = (elevation + 1.6) / 2 + 0.3 } |
|
|
|
|
|
|
|
|
|
|
|
elseif elevation < 1 then -- high elevation |
|
|
|
|
|
return COLORS.MOUNTAIN{ ra = elevation } |
|
|
|
|
|
end |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function grid_heuristic(source, target) |
|
|
function grid_heuristic(source, target) |
|
|
return math.distance(source, target) |
|
|
return math.distance(source, target) |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
function grid_cost(map, from, to) |
|
|
function grid_cost(map, from, to) |
|
|
local t1, t2 = map.get(from.x, from.y), map.get(to.x, to.y) |
|
|
|
|
|
|
|
|
local t1, t2 = map_get(map, from), map_get(map, to) |
|
|
|
|
|
|
|
|
-- i have no fucking clue why, but adding +0.2 to the end of this fixes a bug where sometimes two (or more) |
|
|
-- i have no fucking clue why, but adding +0.2 to the end of this fixes a bug where sometimes two (or more) |
|
|
-- equivalent paths are found and mobs backpedal trying to decide between them |
|
|
-- equivalent paths are found and mobs backpedal trying to decide between them |
|
@ -107,11 +92,18 @@ function grid_cost(map, from, to) |
|
|
local epsilon = elevation_epsilon |
|
|
local epsilon = elevation_epsilon |
|
|
local cost = elevation_cost |
|
|
local cost = elevation_cost |
|
|
|
|
|
|
|
|
return epsilon - cost |
|
|
|
|
|
|
|
|
return 1 |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function grid_neighbours(map, hex) |
|
|
|
|
|
return table.filter(hex_neighbours(hex), function(_hex) |
|
|
|
|
|
local tile = map_get(map, _hex) |
|
|
|
|
|
return tile and tile_is_medium_elevation(tile) |
|
|
|
|
|
end) |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
function generate_flow_field(map, start) |
|
|
function generate_flow_field(map, start) |
|
|
return dijkstra(map, start, nil, grid_cost) |
|
|
|
|
|
|
|
|
return dijkstra(map, start, nil, grid_cost, grid_neighbours) |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
function apply_flow_field(map, flow_field, world) |
|
|
function apply_flow_field(map, flow_field, world) |
|
@ -123,7 +115,7 @@ function apply_flow_field(map, flow_field, world) |
|
|
local overlay_group = am.group():tag"flow_field" |
|
|
local overlay_group = am.group():tag"flow_field" |
|
|
for i,_ in pairs(map) do |
|
|
for i,_ in pairs(map) do |
|
|
for j,f in pairs(map[i]) do |
|
|
for j,f in pairs(map[i]) do |
|
|
local flow = hex_map_get(flow_field, i, j) |
|
|
|
|
|
|
|
|
local flow = map_get(flow_field, i, j) |
|
|
|
|
|
|
|
|
if flow then |
|
|
if flow then |
|
|
map[i][j].priority = flow.priority |
|
|
map[i][j].priority = flow.priority |
|
@ -142,12 +134,38 @@ function apply_flow_field(map, flow_field, world) |
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
-- some convenience functions for setting and retrieving values from a 2d sparse array |
|
|
|
|
|
-- where the first index might return a nil value, causing the second second to crash the game |
|
|
|
|
|
-- and where it's often the case that the indexer is a vec2 |
|
|
|
|
|
function map_get(map, hex, y) |
|
|
|
|
|
if y then return map[hex] and map[hex][y] end |
|
|
|
|
|
return map[hex.x] and map[hex.x][hex.y] |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function map_set(map, hex, y, v) |
|
|
|
|
|
if v then |
|
|
|
|
|
if map[hex] then |
|
|
|
|
|
map[hex][y] = v |
|
|
|
|
|
else |
|
|
|
|
|
map[hex] = {} |
|
|
|
|
|
map[hex][y] = v |
|
|
|
|
|
end |
|
|
|
|
|
else |
|
|
|
|
|
if map[hex.x] then |
|
|
|
|
|
map[hex.x][hex.y] = y |
|
|
|
|
|
else |
|
|
|
|
|
map[hex.x] = {} |
|
|
|
|
|
map[hex.x][hex.y] = y |
|
|
|
|
|
end |
|
|
|
|
|
end |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
function building_tower_breaks_flow_field(tower_type, hex) |
|
|
function building_tower_breaks_flow_field(tower_type, hex) |
|
|
local original_elevations = {} |
|
|
local original_elevations = {} |
|
|
local all_impassable = true |
|
|
local all_impassable = true |
|
|
local hexes = spiral_map(hex, get_tower_size(tower_type)) |
|
|
local hexes = spiral_map(hex, get_tower_size(tower_type)) |
|
|
for _,h in pairs(hexes) do |
|
|
for _,h in pairs(hexes) do |
|
|
local tile = state.map.get(h.x, h.y) |
|
|
|
|
|
|
|
|
local tile = map_get(state.map, h) |
|
|
|
|
|
|
|
|
if all_impassable and mob_can_pass_through(nil, h) then |
|
|
if all_impassable and mob_can_pass_through(nil, h) then |
|
|
all_impassable = false |
|
|
all_impassable = false |
|
@ -164,25 +182,41 @@ function building_tower_breaks_flow_field(tower_type, hex) |
|
|
-- (besides return all the tile's elevations back to their original state) |
|
|
-- (besides return all the tile's elevations back to their original state) |
|
|
if all_impassable then |
|
|
if all_impassable then |
|
|
for i,h in pairs(hexes) do |
|
|
for i,h in pairs(hexes) do |
|
|
state.map.get(h.x, h.y).elevation = original_elevations[i] |
|
|
|
|
|
|
|
|
map_get(state.map, h).elevation = original_elevations[i] |
|
|
end |
|
|
end |
|
|
return false |
|
|
return false |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
local flow_field = generate_flow_field(state.map, HEX_GRID_CENTER) |
|
|
local flow_field = generate_flow_field(state.map, HEX_GRID_CENTER) |
|
|
local result = not hex_map_get(flow_field, 0, 0) |
|
|
|
|
|
|
|
|
local result = not map_get(flow_field, 0, 0) |
|
|
|
|
|
|
|
|
for i,h in pairs(hexes) do |
|
|
for i,h in pairs(hexes) do |
|
|
state.map.get(h.x, h.y).elevation = original_elevations[i] |
|
|
|
|
|
|
|
|
map_get(state.map, h).elevation = original_elevations[i] |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
return result, flow_field |
|
|
return result, flow_field |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
function random_map(seed) |
|
|
|
|
|
local map = rectangular_map(HEX_GRID_DIMENSIONS.x, HEX_GRID_DIMENSIONS.y, seed) |
|
|
|
|
|
math.randomseed(map.seed) |
|
|
|
|
|
|
|
|
function make_hex_grid_scene(map) |
|
|
|
|
|
local function color_at(elevation) |
|
|
|
|
|
if elevation < -0.5 then -- lowest elevation |
|
|
|
|
|
return COLORS.WATER{ a = (elevation + 1.4) / 2 + 0.2 } |
|
|
|
|
|
|
|
|
|
|
|
elseif elevation < 0 then -- med-low elevation |
|
|
|
|
|
return math.lerp(COLORS.DIRT, COLORS.GRASS, elevation + 0.5){ a = (elevation + 1.8) / 2 + 0.3 } |
|
|
|
|
|
|
|
|
|
|
|
elseif elevation < 0.5 then -- med-high elevation |
|
|
|
|
|
return math.lerp(COLORS.DIRT, COLORS.GRASS, elevation + 0.5){ a = (elevation + 1.6) / 2 + 0.3 } |
|
|
|
|
|
|
|
|
|
|
|
elseif elevation < 1 then -- high elevation |
|
|
|
|
|
return COLORS.MOUNTAIN{ ra = elevation } |
|
|
|
|
|
|
|
|
|
|
|
else |
|
|
|
|
|
-- @TODO probably fix... this only happens when loading a save, and the tile has an elevation that's |
|
|
|
|
|
-- higher that anything here |
|
|
|
|
|
return vec4(0.1) |
|
|
|
|
|
end |
|
|
|
|
|
end |
|
|
-- the world's appearance relies largely on a backdrop which can be scaled in |
|
|
-- the world's appearance relies largely on a backdrop which can be scaled in |
|
|
-- tone to give the appearance of light or darkness |
|
|
-- tone to give the appearance of light or darkness |
|
|
-- @NOTE replace this with a shader program |
|
|
-- @NOTE replace this with a shader program |
|
@ -197,6 +231,38 @@ function random_map(seed) |
|
|
:tag"negative_mask" |
|
|
:tag"negative_mask" |
|
|
|
|
|
|
|
|
local world = am.group(neg_mask):tag"world" |
|
|
local world = am.group(neg_mask):tag"world" |
|
|
|
|
|
for i,_ in pairs(map) do |
|
|
|
|
|
for j,tile in pairs(map[i]) do |
|
|
|
|
|
local evenq = hex_to_evenq(vec2(i, j)) |
|
|
|
|
|
|
|
|
|
|
|
-- light shading on edge cells |
|
|
|
|
|
local mask = vec4(0, 0, 0, math.max(((evenq.x - HEX_GRID_WIDTH/2) / HEX_GRID_WIDTH) ^ 2 |
|
|
|
|
|
, ((-evenq.y - HEX_GRID_HEIGHT/2) / HEX_GRID_HEIGHT) ^ 2)) |
|
|
|
|
|
|
|
|
|
|
|
local color = color_at(tile.elevation) - mask |
|
|
|
|
|
|
|
|
|
|
|
local node = am.translate(hex_to_pixel(vec2(i, j), vec2(HEX_SIZE))) |
|
|
|
|
|
^ am.circle(vec2(0), HEX_SIZE, color, 6) |
|
|
|
|
|
|
|
|
|
|
|
map_set(map, i, j, { |
|
|
|
|
|
elevation = tile.elevation, |
|
|
|
|
|
node = node |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
world:append(node) |
|
|
|
|
|
end |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
apply_flow_field(map, generate_flow_field(map, HEX_GRID_CENTER), world) |
|
|
|
|
|
|
|
|
|
|
|
return am.translate(WORLDSPACE_COORDINATE_OFFSET) ^ world |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function random_map(seed) |
|
|
|
|
|
local map = rectangular_map(HEX_GRID_DIMENSIONS.x, HEX_GRID_DIMENSIONS.y, seed) |
|
|
|
|
|
math.randomseed(map.seed) |
|
|
|
|
|
|
|
|
|
|
|
-- there are some things about the generated map we'd like to change... |
|
|
for i,_ in pairs(map) do |
|
|
for i,_ in pairs(map) do |
|
|
for j,noise in pairs(map[i]) do |
|
|
for j,noise in pairs(map[i]) do |
|
|
local evenq = hex_to_evenq(vec2(i, j)) |
|
|
local evenq = hex_to_evenq(vec2(i, j)) |
|
@ -220,33 +286,12 @@ function random_map(seed) |
|
|
noise = noise * d^0.125 -- arbitrary, seems to work good |
|
|
noise = noise * d^0.125 -- arbitrary, seems to work good |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
-- light shading on edge cells |
|
|
|
|
|
local mask = vec4(0, 0, 0, math.max(((evenq.x - HEX_GRID_WIDTH/2) / HEX_GRID_WIDTH) ^ 2 |
|
|
|
|
|
, ((-evenq.y - HEX_GRID_HEIGHT/2) / HEX_GRID_HEIGHT) ^ 2)) |
|
|
|
|
|
local color = color_at(noise) - mask |
|
|
|
|
|
|
|
|
|
|
|
local node = am.translate(hex_to_pixel(vec2(i, j), vec2(HEX_SIZE))) |
|
|
|
|
|
^ am.circle(vec2(0), HEX_SIZE, color, 6) |
|
|
|
|
|
|
|
|
|
|
|
map.set(i, j, { |
|
|
|
|
|
|
|
|
map_set(map, i, j, { |
|
|
elevation = noise, |
|
|
elevation = noise, |
|
|
node = node |
|
|
|
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
world:append(node) |
|
|
|
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
getmetatable(map).__index.neighbours = function(hex) |
|
|
|
|
|
return table.filter(hex_neighbours(hex), function(_hex) |
|
|
|
|
|
--local interactable = evenq_is_in_interactable_region(hex_to_evenq(_hex)) |
|
|
|
|
|
local tile = map.get(_hex.x, _hex.y) |
|
|
|
|
|
return tile and tile_is_medium_elevation(tile) |
|
|
|
|
|
end) |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
apply_flow_field(map, generate_flow_field(map, HEX_GRID_CENTER), world) |
|
|
|
|
|
|
|
|
|
|
|
return map, am.translate(WORLDSPACE_COORDINATE_OFFSET) ^ world |
|
|
|
|
|
|
|
|
return map, make_hex_grid_scene(map) |
|
|
end |
|
|
end |
|
|
|
|
|
|