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.

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