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.

250 lines
7.4 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
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 SYSTEM 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. in some rare cases, coordinates will be passed individually, usually
  9. because they are only passed internally and should never be adjusted
  10. directly.
  11. in amulet, vector arithmetic already works via: + - * /
  12. additional things such as equality, and distance are implemented here.
  13. +support for parallelogram, triangular, hexagonal and rectangular maps.
  14. +support for arbitrary maps with gaps via hashmaps-like storage
  15. +support for simple irregular hexagons (horizontal and vertical stretching).
  16. classes are used sparsely. maps implement a few constructors for storing
  17. your maps elsewhere, and should be the only field that is necessarily
  18. visible outside the library.
  19. -- RESOURCES USED TO DEVELOP THIS LIBRARY
  20. https://redblobgames.com/grid/hexagons - simply amazing.
  21. http://amulet.xyz/doc - amulet documentation
  22. TODO that place that had the inner circle/outer circle ratio??
  23. ]]
  24. ----- [[ GENERALLY USEFUL FUNCTIONS ]] -----------------------------------------
  25. -- rounds numbers. would've been cool to have math.round in lua.
  26. local function round(n)
  27. return n % 1 >= 0.5 and math.ceil(n) or math.floor(n)
  28. end
  29. ----- [[ HEX CONSTANTS ]] ------------------------------------------------------
  30. -- all possible vector directions from a given hex by edge
  31. local HEX_DIRECTIONS = {vec2( 1 , 0),
  32. vec2( 1 , -1),
  33. vec2( 0 , -1),
  34. vec2(-1 , 0),
  35. vec2(-1 , 1),
  36. vec2( 0 , 1)}
  37. ----- [[ HEX UTILITY FUNCTIONS ]] ----------------------------------------------
  38. function hex_equals(a, b)
  39. return a.s == b.s and a.t == b.t
  40. end
  41. function hex_length(hex)
  42. return round(math.abs(hex.s) + math.abs(hex.r) + math.abs(-hex.s - hex.t)/2)
  43. end
  44. function hex_distance(a, b)
  45. return hex_length(a - b)
  46. end
  47. function hex_round(s, t)
  48. local rs = round(s)
  49. local rt = round(t)
  50. local rz = round(-s - t)
  51. local sdelta = math.abs(rs - s)
  52. local tdelta = math.abs(rt - t)
  53. local zdelta = math.abs(rz - (-s - t))
  54. if sdelta > tdelta and sdelta > zdelta then
  55. rs = -rt - rz
  56. elseif tdelta > zdelta then
  57. rt = -rs - rz
  58. else
  59. rz = -rs - rt
  60. end
  61. return vec2(rs, rt)
  62. end
  63. ----- [[ LAYOUT, ORIENTATION & COORDINATE CONVERSION ]] -----------------------
  64. -- forward & inverse matrices used for the flat orientation.
  65. local FLAT = {3.0/2.0, 0.0, 3.0^0.5/2.0, 3.0^0.5,
  66. 2.0/3.0, 0.0, -1.0/3.0 , 3.0^0.5/3.0}
  67. -- forward & inverse matrices used for the pointy orientation.
  68. local POINTY = {3.0^0.5, 3.0^0.5/2.0, 0.0, 3.0/2.0,
  69. 3.0^0.5/3.0, -1.0/3.0, 0.0, 2.0/3.0}
  70. -- stores layout information that does not pertain to map shape
  71. function layout_init(origin, size, orientation)
  72. return {origin = origin or vec2(0),
  73. size = size or vec2(11),
  74. orientation = orientation or FLAT}
  75. end
  76. -- hex to screen
  77. function hex_to_pixel(hex, layout)
  78. local M = layout.orientation
  79. local x = (M[1] * hex.s + M[2] * hex.t) * layout.size.x
  80. local y = (M[3] * hex.s + M[4] * hex.t) * layout.size.y
  81. return vec2(x + layout.origin.x, y + layout.origin.y)
  82. end
  83. -- screen to hex
  84. function pixel_to_hex(pix, layout)
  85. local M = layout.orientation
  86. local pix = (pix - layout.origin) / layout.size
  87. local s = M[5] * pix.x + M[6] * pix.y
  88. local t = M[7] * pix.x + M[8] * pix.y
  89. return hex_round(s, t)
  90. end
  91. ----- [[ MAP STORAGE & RETRIEVAL ]] --------------------------------------------
  92. --[[ _init functions return a table of tables;
  93. a map of points in a chosen shape and specified layout.
  94. grammap_init - parallelogram map
  95. trimap_init - triangular map
  96. hexmap_init - hexagonal map
  97. rectmap_init - rectangular map
  98. calling .retrieve(pix) on your map will get the hexagon at that pixel.
  99. calling .store(hex) on your map will store that hex as pixel coords.
  100. maps store coordinates like this:
  101. map[hex] = hex_to_pixel(hex)
  102. this means you should be able to get all the information you need about
  103. various coordinates completely within the map 'class', without calling
  104. any internal functions. indeed, *map_init, map.retrieve, and map.store
  105. is all you need.
  106. ]]
  107. -- returns parallelogram-shaped map.
  108. function grammap_init(layout, width, height)
  109. local map = {}
  110. local mt = {__index={layout=layout,
  111. -- get hex in map from pixel coordinate
  112. retrieve=function(pix)
  113. return pixel_to_hex(pix, layout)
  114. end,
  115. -- store pixel in map from hex coordinate
  116. store=function(hex)
  117. map[hex]=hex_to_pixel(hex, layout)
  118. end
  119. }}
  120. setmetatable(map, mt)
  121. for s = 0, width do
  122. for t = 0, height do
  123. table.insert(map, hex_to_pixel(vec2(s, t), layout))
  124. end
  125. end
  126. return map
  127. end
  128. -- returns triangular map.
  129. function trimap_init(layout, size)
  130. local map = {}
  131. local mt = {__index={layout=layout,
  132. -- get hex in map from pixel coordinate
  133. retrieve=function(pix)
  134. return pixel_to_hex(pix, layout)
  135. end,
  136. -- store pixel in map from hex coordinate
  137. store=function(hex)
  138. map[hex]=hex_to_pixel(hex, layout)
  139. end
  140. }}
  141. setmetatable(map, mt)
  142. for s = 0, size do
  143. for t = size - s, size do
  144. map.store(vec2(s, t))
  145. end
  146. end
  147. return map
  148. end
  149. -- returns hexagonal map. length of map is radius * 2 + 1
  150. function hexmap_init(layout, radius)
  151. local map = {}
  152. local mt = {__index={layout=layout,
  153. -- get hex in map from pixel coordinate
  154. retrieve=function(pix)
  155. return pixel_to_hex(pix, layout)
  156. end,
  157. -- store pixel in map from hex coordinate
  158. store=function(hex)
  159. map[hex]=hex_to_pixel(hex, layout)
  160. end
  161. }}
  162. setmetatable(map, mt)
  163. for s = -radius, radius do
  164. local t1 = math.max(-radius, -s - radius)
  165. local t2 = math.min(radius, -s + radius)
  166. for t = t1, t2 do
  167. table.insert(map, hex_to_pixel(vec2(s, t), layout))
  168. end
  169. end
  170. return map
  171. end
  172. -- returns rectangular map.
  173. function rectmap_init(layout, width, height)
  174. local map = {}
  175. local mt = {__index={layout=layout,
  176. -- get hex in map from pixel coordinate
  177. retrieve=function(pix)
  178. return pixel_to_hex(pix, layout)
  179. end,
  180. -- store pixel in map from hex coordinate
  181. store=function(hex)
  182. map[hex]=hex_to_pixel(hex - vec2(0, math.floor(hex.s/2)), layout)
  183. end
  184. }}
  185. setmetatable(map, mt)
  186. for s = 0, width do
  187. for t = 0, height do
  188. map.store(vec2(s, t))
  189. end
  190. end
  191. return map
  192. end