Browse Source

Implemented Noise.

master
churchianity 6 years ago
parent
commit
09c75d2d44
  1. 66
      README.md
  2. 91
      hex.lua
  3. 59
      main.lua
  4. 54
      sprites.lua

66
README.md

@ -2,79 +2,79 @@
## INTRODUCTION ## INTRODUCTION
this is a library for using hexagonal grids in amulet/lua. this is a library for using hexagonal grids in amulet/lua.
it is extremely incomplete. the following list of features is
either implemented shoddily, or not at all.
it is extremely incomplete. the following list of features is
either implemented shoddily, or not at all.
if you want an actual good resource, go to TODO LINK.
if you want an actual good resource, go to [amit's guide to hexagonal grids](#RESOURCES USED TO DEVELOP THIS LIBRARY, AND FOR WHICH I AM GRATEFUL).
## GETTING STARTED ## GETTING STARTED
1) initialize a map. 1) initialize a map.
2) iterate over the map and draw some hexagons.
2) iterate over the map and draw some hexagons.
## COORDINATE SYSTEMS ## COORDINATE SYSTEMS
As much coordinate manipulation as possible is done internally. As much coordinate manipulation as possible is done internally.
Depending on the task, uses either Axial, Cube, or Offset coordinates. Depending on the task, uses either Axial, Cube, or Offset coordinates.
## MAPS & MAP STORAGE ## MAPS & MAP STORAGE
Some map shapes: parallelogram, rectangular, hexagonal, triangular. (and more) Some map shapes: parallelogram, rectangular, hexagonal, triangular. (and more)
The storage system used is based on the map shape - see chart: The storage system used is based on the map shape - see chart:
| SHAPE | MAP STORAGE |
| SHAPE | MAP STORAGE |
| ----------------- | --------------------------------------------- | | ----------------- | --------------------------------------------- |
| parallelogram | unordered, hash-like |
| rectangular | unordered, hash-like |
| hexagonal | unordered, hash-like |
| triangular | unordered, hash-like |
| ring | ordered, array-like |
| spiral | ordered, array-like |
| arbitrary | unordered, hash-like |
| parallelogram | unordered, hash-like |
| rectangular | unordered, hash-like |
| hexagonal | unordered, hash-like |
| triangular | unordered, hash-like |
| ring | ordered, array-like |
| spiral | ordered, array-like |
| arbitrary | unordered, hash-like |
* note that a spiral map is just a hexagonal one with a particular order. * note that a spiral map is just a hexagonal one with a particular order.
By default, the unordered, hash-like maps have pseudo-random noise stored
as their values. This can be useful for a whole bunch of things, but if you
wish, you can simply iterate over your map and set every value to 'true'.
By default, the unordered, hash-like maps have pseudo-random noise stored
as their values. This can be useful for a whole bunch of things, but if you
wish, you can simply iterate over your map and set every value to 'true'.
## CONVENTIONS AND TERMINOLOGY ## CONVENTIONS AND TERMINOLOGY
If you have read amit's guide to hexagon grids, (see TODO LINK), a lot of the
If you have read amit's guide to hexagon grids, (see TODO LINK), a lot of the
terminology will be familiar to you - I utilize many conventions he does in terminology will be familiar to you - I utilize many conventions he does in
his guide. That being said... his guide. That being said...
Because so many similar kinds of data structures with different goals are used
in this library it can be hard to remember precisely what they all refer to.
Because so many similar kinds of data structures with different goals are used
in this library it can be hard to remember precisely what they all refer to.
The following table shows what each table/vector/array refers to in the code: The following table shows what each table/vector/array refers to in the code:
| NAME | REFERS TO |
| NAME | REFERS TO |
| ---- | ------------------------------------------------------------ | | ---- | ------------------------------------------------------------ |
| cube | xyz, *vector* used for most maps, with constraint x+y+z=0. | | cube | xyz, *vector* used for most maps, with constraint x+y+z=0. |
| pix | xy, *vector* true screen pixel coordinates | | pix | xy, *vector* true screen pixel coordinates |
| off | xy, 'offset', *vector* used for UI implementations | | off | xy, 'offset', *vector* used for UI implementations |
| map | xy, *table* of unit hexagon centerpoints arranged in a shape | | map | xy, *table* of unit hexagon centerpoints arranged in a shape |
* note that 'axial', vec2() coordinates are a subset of cube coordinates,
where you simply omit the z value. for many algorithms this is done, but
instead of using a seperate reference name 'axial' in these cases, I used
the name 'cube' for both. I found this to be simpler. when an algorithm
* note that 'axial', vec2() coordinates are a subset of cube coordinates,
where you simply omit the z value. for many algorithms this is done, but
instead of using a seperate reference name 'axial' in these cases, I used
the name 'cube' for both. I found this to be simpler. when an algorithm
asks for a cube, give it a cube. if you want to know if it works with axial asks for a cube, give it a cube. if you want to know if it works with axial
as well, look at the code and see if it uses a 'z' value. as well, look at the code and see if it uses a 'z' value.
Other terminology:
Other terminology:
* TODO * TODO
## RESOURCES USED TO DEVELOP THIS LIBRARY, AND FOR WHICH I AM GRATEFUL
## RESOURCES USED TO DEVELOP THIS LIBRARY, AND FOR WHICH I AM GRATEFUL
* [Hex Map 1](https://catlikecoding.com/unity/tutorials/hex-map/) - unity tutorial for hexagon grids with some useful generalized math. * [Hex Map 1](https://catlikecoding.com/unity/tutorials/hex-map/) - unity tutorial for hexagon grids with some useful generalized math.
* [3Blue1Brown - Essence of Linear Algebra](https://youtube.com/watch?v=fNk_zzaMoSs&list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab) - amazing series on linear algebra by 3Blue1Brown * [3Blue1Brown - Essence of Linear Algebra](https://youtube.com/watch?v=fNk_zzaMoSs&list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab) - amazing series on linear algebra by 3Blue1Brown
* [Hexagonal Grids](https://redblobgames.com/grid/hexagons) - THE resource on hexagonal grids on the internet.
* [Hexagonal Grids](https://redblobgames.com/grid/hexagons) - THE resource on hexagonal grids on the internet.
* [Amulet Docs](http://amulet.xyz/doc) - amulet documentation. * [Amulet Docs](http://amulet.xyz/doc) - amulet documentation.

91
hex.lua

@ -13,21 +13,21 @@ end
============================================================================]]-- ============================================================================]]--
-- all possible vector directions from a given hex by edge -- all possible vector directions from a given hex by edge
local CUBE_DIRECTIONS = {vec2( 1 , 0),
local CUBE_DIRECTIONS = {vec2( 0 , 1),
vec2( 1 , 0),
vec2( 1 , -1), vec2( 1 , -1),
vec2( 0 , -1), vec2( 0 , -1),
vec2(-1 , 0), vec2(-1 , 0),
vec2(-1 , 1),
vec2( 0 , 1)}
vec2(-1 , 1)}
-- return hex vector direction via integer index |direction|. -- return hex vector direction via integer index |direction|.
function cube_direction(direction) function cube_direction(direction)
return CUBE_DIRECTIONS[(6 + (direction % 6)) % 6 + 1]
return CUBE_DIRECTIONS[(direction % 6) % 6 + 1]
end end
-- return hexagon adjacent to |hex| in integer index |direction|. -- return hexagon adjacent to |hex| in integer index |direction|.
function cube_neighbour(hex, direction) function cube_neighbour(hex, direction)
return hex + CUBE_DIRECTIONS[(6 + (direction % 6)) % 6 + 1]
return hex + CUBE_DIRECTIONS[(direction % 6) % 6 + 1]
end end
-- return cube coords at location 60deg away to the left; counter-clockwise -- return cube coords at location 60deg away to the left; counter-clockwise
@ -95,7 +95,7 @@ end
function pixel_to_cube(pix, layout) function pixel_to_cube(pix, layout)
local W = layout.orientation.W local W = layout.orientation.W
local pix = (pix - layout.origin) / layout.size
local pix = (pix - layout.origin) / layout.size
local s = W[1][1] * pix[1] + W[1][2] * pix[2] local s = W[1][1] * pix[1] + W[1][2] * pix[2]
local t = W[2][1] * pix[1] + W[2][2] * pix[2] local t = W[2][1] * pix[1] + W[2][2] * pix[2]
@ -126,8 +126,7 @@ function offset_to_cube(off)
end end
--[[============================================================================ --[[============================================================================
----- MAPS & STORAGE -----
----- MAPS & STORAGE -----
MAPS STORE CUBE COORDINATES. MAPS STORE CUBE COORDINATES. MAPS STORE CUBE COOR MAPS STORE CUBE COORDINATES. MAPS STORE CUBE COORDINATES. MAPS STORE CUBE COOR
This means, you are not to draw using the coordinates stored in your map. This means, you are not to draw using the coordinates stored in your map.
@ -135,14 +134,26 @@ end
If you wish to draw a hexagon to the screen, you must first use cube_to_pixel If you wish to draw a hexagon to the screen, you must first use cube_to_pixel
to retrieve the center of the hexagon on each set of cube coordinates stored to retrieve the center of the hexagon on each set of cube coordinates stored
in your map.
in your map. Then, depending on how you are going to draw, either call
am.circle with |sides| = 6, or gather the vertices with hex_corners and
use am.draw - TODO, haven't used am.draw yet.
Information about the maps' dimensions are stored in a metatable, so you can Information about the maps' dimensions are stored in a metatable, so you can
retrieve details about arbitrary maps after they are created.
retrieve details about maps after they are created.
----- NOISE -----
To simplify terrain generation, unordered, hash-like maps automatically
calculate and store perlin noise as their values. You can modify the nature
of the noise by providing different |frequencies| as a tables of values, for
example: {1, 2, 4, 8} or {1, 0.5, 0.25, 0.125}. These just increase the
complexity of the curvature of the noise. The default is {1}.
----- TODO -----
TODO make all functions work regardless of layout. as it stands, they kind TODO make all functions work regardless of layout. as it stands, they kind
of do, just not always nicely. of do, just not always nicely.
============================================================================]]-- ============================================================================]]--
----- ORDERED MAPS -----
-- returns ordered ring-shaped map of |radius| from |center|. -- returns ordered ring-shaped map of |radius| from |center|.
function ring_map(center, radius) function ring_map(center, radius)
@ -163,8 +174,9 @@ function ring_map(center, radius)
end end
-- returns ordered hexagonal map of |radius| rings from |center|. -- returns ordered hexagonal map of |radius| rings from |center|.
-- the only difference between hex_spiral_map and hex_hexagonal_map is that
-- hex_spiral_map is ordered, in a spiral path from the |center|.
-- the only difference between spiral_map and hexagonal_map is that
-- spiral_map is ordered, in a spiral path from the |center|.
function spiral_map(center, radius) function spiral_map(center, radius)
local map = {center} local map = {center}
local mt = {__index={center=center, radius=radius}} local mt = {__index={center=center, radius=radius}}
@ -177,7 +189,9 @@ function spiral_map(center, radius)
return map return map
end end
-- returns unordered parallelogram-shaped map of |width| and |height|.
----- UNORDERED, HASH-LIKE MAPS -----
-- returns unordered parallelogram-shaped map of |width| and |height| with perlin noise
function parallelogram_map(width, height) function parallelogram_map(width, height)
local map = {} local map = {}
local mt = {__index={width=width, height=height}} local mt = {__index={width=width, height=height}}
@ -186,13 +200,13 @@ function parallelogram_map(width, height)
for i = 0, width do for i = 0, width do
for j = 0, height do for j = 0, height do
map[vec2(i, -j)] = true
map[vec2(i, j)] = true
end end
end end
return map return map
end end
-- returns unordered triangular map of |size|.
-- returns unordered triangular map of |size| with perlin noise
function triangular_map(size) function triangular_map(size)
local map = {} local map = {}
local mt = {__index={size=size}} local mt = {__index={size=size}}
@ -207,7 +221,7 @@ function triangular_map(size)
return map return map
end end
-- returns unordered hexagonal map of |radius|.
-- returns unordered hexagonal map of |radius| with perlin noise
function hexagonal_map(radius) function hexagonal_map(radius)
local map = {} local map = {}
local mt = {__index={radius=radius}} local mt = {__index={radius=radius}}
@ -225,21 +239,60 @@ function hexagonal_map(radius)
return map return map
end end
-- returns unordered rectangular map of |width| and |height|.
function rectangular_map(width, height)
-- returns unordered rectangular map of |width| and |height| with perlin noise
function rectangular_map(width, height, frequencies)
local map = {} local map = {}
local mt = {__index={width=width, height=height}} local mt = {__index={width=width, height=height}}
local frequencies = frequencies or {1}
setmetatable(map, mt) setmetatable(map, mt)
for i = 0, width do for i = 0, width do
for j = 0, height do for j = 0, height do
map[vec2(i, -j - math.floor(i/2))] = true
-- calculate noise
local idelta = assert(i / width, "width must be greater than 0")
local jdelta = assert(j / height, "height must be greater than 0")
local noise = 0
for _,freq in pairs(frequencies) do
noise = noise + 1/freq * math.perlin(vec2(freq * idelta,
freq * jdelta))
end
-- this is what makes it a rectangle
local hex = vec2(i, j - math.floor(i/2))
-- store hex in the map paired with its associated noise value
map[hex] = noise
end end
end end
return map return map
end end
--[[============================================================================
----- NOISE -----
============================================================================]]--
function simplex_map(frequency, exponent, width, height)
local map = {}
for i = 0, height do
for j = 0, width do
local idelta = i/width - 0.5
local jdelta = j/height - 0.5
map[vec2(i, j)] = math.simplex(idelta, jdelta)
end
end
end
--[[============================================================================ --[[============================================================================
----- PATHFINDING ----- ----- PATHFINDING -----
============================================================================]]-- ============================================================================]]--

59
main.lua

@ -48,7 +48,7 @@ am.ascii_color_map =
} }
--[[============================================================================ --[[============================================================================
----- WINDOW SETUP -----
----- SETUP -----
============================================================================]]-- ============================================================================]]--
local win = am.window local win = am.window
{ -- base resolution = 3/4 * WXGA standard 16:10 { -- base resolution = 3/4 * WXGA standard 16:10
@ -58,29 +58,26 @@ local win = am.window
clear_color = BASE03 clear_color = BASE03
} }
--[[============================================================================
============================================================================]]--
local map = rectangular_map(45, 31) local map = rectangular_map(45, 31)
local layout = layout(vec2(-268, win.top - 10)) local layout = layout(vec2(-268, win.top - 10))
--[[============================================================================ --[[============================================================================
----- SCENE GRAPH / NODES ----- ----- SCENE GRAPH / NODES -----
============================================================================]]-- ============================================================================]]--
local panel; local world; local game; --[[
local panel; local world; local game --[[
panel panel
| |
#------> game ------> win.scene
+------> game ------> win.scene
| |
world world
--==========================================================================]]--
local backdrop; local menu; local title; --[[
]]--
local backdrop; local menu; local title --[[
backdrop backdrop
| |
#------> title ------> win.scene
+------> title ------> win.scene
| |
menu menu
@ -105,11 +102,12 @@ end
function show_coords() function show_coords()
game:action(function() game:action(function()
game:remove("coords") game:remove("coords")
game:remove("select")
game:remove("selected")
local hex = pixel_to_cube(win:mouse_position(), layout) local hex = pixel_to_cube(win:mouse_position(), layout)
local mouse = cube_to_offset(hex) local mouse = cube_to_offset(hex)
-- check mouse is within bounds of game map
if mouse.x > 0 and mouse.x < map.width and if mouse.x > 0 and mouse.x < map.width and
mouse.y > 0 and mouse.y < map.height then mouse.y > 0 and mouse.y < map.height then
@ -120,9 +118,9 @@ function show_coords()
world:append(coords) world:append(coords)
local color = vec4(1, 1, 1, 0.2)
local color = vec4(1)
local pix = cube_to_pixel(hex, layout) local pix = cube_to_pixel(hex, layout)
world:append(am.circle(pix, layout.size.x, color, 6):tag"select")
world:append(am.circle(pix, layout.size.x, color, 6):tag"selected")
end end
end) end)
end end
@ -135,37 +133,44 @@ end
function game_init() function game_init()
-- setup nodes
world = am.group{}:tag"world" world = am.group{}:tag"world"
panel = am.group{}:tag"panel" panel = am.group{}:tag"panel"
game = am.group{world, panel}:tag"game" game = am.group{world, panel}:tag"game"
local hexes = {}
for cube,_ in pairs(map) do
hexes[math.perlin(cube)] = cube_to_pixel(cube, layout)
end
-- render world
world:action(coroutine.create(function() world:action(coroutine.create(function()
-- background panel for gui elements
panel:append(am.rect(win.left, win.top, -268, win.bottom):tag"bg") panel:append(am.rect(win.left, win.top, -268, win.bottom):tag"bg")
for noise, hex in pairs(hexes) do
local off = cube_to_offset(hex)
local tag = tostring(hex)
-- begin map generation
for hex,noise in pairs(map) do
-- determine cell color based on noise
local color = vec4((noise + 1) / 2)
-- determine cell shading mask based on map position -- determine cell shading mask based on map position
local off = cube_to_offset(hex)
local mask = vec4(0, 0, 0, math.max(((off.x-23)/30)^2, local mask = vec4(0, 0, 0, math.max(((off.x-23)/30)^2,
((off.y-16)/20)^2)) ((off.y-16)/20)^2))
-- determine hexagon center for drawing
local center = cube_to_pixel(hex, layout)
-- determine cell color based on noise
local color = vec4(math.random()) - mask
-- prepend hexagon to screen
world:prepend(am.circle(center, 11, color, 6):tag(tostring(hex)))
am.wait(am.delay(0.01))
-- fade in bg panel
panel"bg".color = BASE03/am.frame_time panel"bg".color = BASE03/am.frame_time
world:prepend(am.circle(hex, 11, color, 6):tag(tag))
am.wait(am.delay(0.01))
end end
show_coords()
keep_time()
show_coords() -- mouse-hover events
keep_time() -- scoring
end)) end))
-- make it so
win.scene = game win.scene = game
end end

54
sprites.lua

@ -1,54 +0,0 @@
grass1 =
[[
......gggggggggg......
.....ggggKggggggg.....
....ggggggKggggggg....
....gggggggggggggg....
...gggggggggggggggg...
...gggggggggggggggg...
..gggggggggggggggggg..
..gggggggggggggggggg..
.ggggggggggkggggggggg.
ggggggggggmmgggggggggg
.gggggggggggggggggggg.
..ggggggggglgggggggg..
..gggggggglggggggggg..
...gggggggLgggggggg...
...gggggggggggggggg...
....ggggggsggggggg....
.....ggggggsgggggg....
.....ggggggSggggg.....
......gggggggggg......
]]
titlebutton =
[[
KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
KwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwK
KwkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK
KwkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK
KwkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK
KwkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK
KwkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK
KwkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK
KwkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK
KwkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK
KkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK
KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
]]
Loading…
Cancel
Save