hexyz is tower defense game, and a lua library for dealing with hexagonal grids
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
5.8 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. ----- [[ AXIAL/CUBE COORDINATE HEXAGON LIBRARY FOR AMULET/LUA]] ----------------
  2. --[[ author@churchianity.ca
  3. -- INTRODUCTION
  4. this is a hexagonal grid library for amulet/lua.
  5. it uses axial coordinates or cube/hex coordinates when necessary.
  6. by amulet convention, hexes are either vec2(s, t) or vec3(s, t, z)
  7. but nearly always the former.
  8. -- RESOURCES USED TO DEVELOP THIS LIBRARY, AND FOR WHICH I AM GRATEFUL
  9. https://redblobgames.com/grid/hexagons - simply amazing.
  10. http://amulet.xyz/doc - amulet documentation
  11. ]]
  12. ----- [[ GENERALLY USEFUL FUNCTIONS ]] -----------------------------------------
  13. -- rounds numbers. would've been cool to have math.round in lua.
  14. local function round(n)
  15. return n % 1 >= 0.5 and math.ceil(n) or math.floor(n)
  16. end
  17. ----- [[ HEX CONSTANTS & UTILITY FUNCTIONS ]] ----------------------------------
  18. -- all possible vector directions from a given hex by edge
  19. local HEX_DIRECTIONS = {vec2( 1 , 0),
  20. vec2( 1 , -1),
  21. vec2( 0 , -1),
  22. vec2(-1 , 0),
  23. vec2(-1 , 1),
  24. vec2( 0 , 1)}
  25. -- return hex vector direction via integer index |direction|.
  26. function hex_direction(direction)
  27. return HEX_DIRECTIONS[(6 + (direction % 6)) % 6 + 1]
  28. end
  29. -- return hexagon adjacent to |hex| in integer index |direction|.
  30. function hex_neighbour(hex, direction)
  31. return hex + HEX_DIRECTIONS[(6 + (direction % 6)) % 6 + 1]
  32. end
  33. -- rounds hexes. without this, pixel_to_hex returns fractional coordinates.
  34. function hex_round(s, t)
  35. local rs = round(s)
  36. local rt = round(t)
  37. local rz = round(-s - t)
  38. local sdelta = math.abs(rs - s)
  39. local tdelta = math.abs(rt - t)
  40. local zdelta = math.abs(rz - (-s - t))
  41. if sdelta > tdelta and sdelta > zdelta then
  42. rs = -rt - rz
  43. elseif tdelta > zdelta then
  44. rt = -rs - rz
  45. else
  46. rz = -rs - rt
  47. end
  48. return vec2(rs, rt)
  49. end
  50. ----- [[ LAYOUT, ORIENTATION & COORDINATE CONVERSION ]] -----------------------
  51. -- forward & inverse matrices used for the flat orientation.
  52. local FLAT = {M = mat2(3.0/2.0, 0.0, 3.0^0.5/2.0, 3.0^0.5 ),
  53. W = mat2(2.0/3.0, 0.0, -1.0/3.0 , 3.0^0.5/3.0),
  54. start_angle = 0.0}
  55. -- forward & inverse matrices used for the pointy orientation.
  56. local POINTY = {M = mat2(3.0^0.5, 3.0^0.5/2.0, 0.0, 3.0/2.0),
  57. W = mat2(3.0^0.5/3.0, -1.0/3.0, 0.0, 2.0/3.0),
  58. start_angle = 0.5}
  59. -- TODO encapsulate hex_to_pixel and pixel_to_hex in layout table.
  60. -- stores layout information that does not pertain to map shape
  61. function hex_layout(origin, size, orientation)
  62. return {origin = origin or vec2(0),
  63. size = size or vec2(11),
  64. orientation = orientation or FLAT}
  65. end
  66. -- hex to screen
  67. function hex_to_pixel(hex, layout)
  68. local M = layout.orientation.M
  69. local x = (M[1][1] * hex.s + M[1][2] * hex.t) * layout.size.x
  70. local y = (M[2][1] * hex.s + M[2][2] * hex.t) * layout.size.y
  71. return vec2(x + layout.origin.x, y + layout.origin.y)
  72. end
  73. -- screen to hex
  74. function pixel_to_hex(pix, layout)
  75. local W = layout.orientation.W
  76. local pix = (pix - layout.origin) / layout.size
  77. local s = W[1][1] * pix.x + W[1][2] * pix.y
  78. local t = W[2][1] * pix.x + W[2][2] * pix.y
  79. return hex_round(s, t)
  80. end
  81. -- TODO test
  82. function hex_corner_offset(layout, corner)
  83. local angle = 2.0 * math.pi * layout.orientation.start_angle + corner / 6
  84. return vec2(layout.size.x * math.cos(angle), layout.size.y * math.sin(angle))
  85. end
  86. -- TODO make do stuff
  87. function hex_corners(layout, hex)
  88. local corners = {}
  89. end
  90. ----- [[ MAP STORAGE & RETRIEVAL ]] --------------------------------------------
  91. --[[
  92. ]]
  93. -- TODO make all functions work regardless of layout.
  94. -- returns ordered ring-shaped map of |radius| from |center|.
  95. function hex_ring_map(center, radius)
  96. local map = {}
  97. local walk = center + HEX_DIRECTIONS[6] * radius
  98. for i = 1, 6 do
  99. for j = 1, radius do
  100. table.insert(map, walk)
  101. walk = hex_neighbour(walk, i)
  102. end
  103. end
  104. return map
  105. end
  106. -- returns ordered hexagonal map of |radius| rings from |center|.
  107. function hex_spiral_map(center, radius)
  108. local map = {center}
  109. for i = 1, radius do
  110. table.append(map, hex_ring_map(center, i))
  111. end
  112. return map
  113. end
  114. -- returns unordered parallelogram-shaped map of |width| and |height|.
  115. function hex_parallelogram_map(width, height)
  116. local map = {}
  117. local mt = {__index={width=width, height=height}}
  118. setmetatable(map, mt)
  119. for s = 0, width do
  120. for t = 0, height do
  121. map[vec2(s, t)] = true
  122. end
  123. end
  124. return map
  125. end
  126. -- returns unordered triangular map of |size|.
  127. function hex_triangular_map(size)
  128. local map = {}
  129. local mt = {__index={size=size}}
  130. setmetatable(map, mt)
  131. for s = 0, size do
  132. for t = size - s, size do
  133. map[vec2(s, t)] = true
  134. end
  135. end
  136. return map
  137. end
  138. -- returns unordered hexagonal map of |radius|.
  139. function hex_hexagonal_map(radius)
  140. local map = {}
  141. local mt = {__index={radius=radius}}
  142. setmetatable(map, mt)
  143. for s = -radius, radius do
  144. local t1 = math.max(-radius, -s - radius)
  145. local t2 = math.min(radius, -s + radius)
  146. for t = t1, t2 do
  147. map[vec2(s, t)] = true
  148. end
  149. end
  150. return map
  151. end
  152. -- returns unordered rectangular map of |width| and |height|.
  153. function hex_rectangular_map(width, height)
  154. local map = {}
  155. local mt = {__index={width=width, height=height}}
  156. setmetatable(map, mt)
  157. for s = 0, width do
  158. for t = 0, height do
  159. map[vec2(s, t - math.floor(s/2))] = true
  160. end
  161. end
  162. return map
  163. end