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.

240 lines
6.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
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. --[[============================================================================
  2. ----- GENERALLY USEFUL FUNCTIONS -----
  3. ==============================================================================]]
  4. -- rounds numbers. would've been cool to have math.round in lua.
  5. local function round(n)
  6. return n % 1 >= 0.5 and math.ceil(n) or math.floor(n)
  7. end
  8. --[[============================================================================
  9. ----- HEX CONSTANTS AND UTILITY FUNCTIONS -----
  10. ==============================================================================]]
  11. -- all possible vector directions from a given hex by edge
  12. local CUBE_DIRECTIONS = {vec2( 1 , 0),
  13. vec2( 1 , -1),
  14. vec2( 0 , -1),
  15. vec2(-1 , 0),
  16. vec2(-1 , 1),
  17. vec2( 0 , 1)}
  18. -- return hex vector direction via integer index |direction|.
  19. function cube_direction(direction)
  20. return CUBE_DIRECTIONS[(6 + (direction % 6)) % 6 + 1]
  21. end
  22. -- return hexagon adjacent to |hex| in integer index |direction|.
  23. function cube_neighbour(hex, direction)
  24. return hex + CUBE_DIRECTIONS[(6 + (direction % 6)) % 6 + 1]
  25. end
  26. -- TODO cube rotations
  27. function cube_rotate_left(hex)
  28. end
  29. function cube_rotate_right(hex)
  30. end
  31. -- rounds a float coordinate trio |x, y, z| to nearest integer coordinate trio
  32. -- only ever used internally; no need to use a vector.
  33. local function cube_round(x, y, z)
  34. local rx = round(x)
  35. local ry = round(y)
  36. local rz = round(z) or round(-x - y)
  37. local xdelta = math.abs(rx - x)
  38. local ydelta = math.abs(ry - y)
  39. local zdelta = math.abs(rz - z)
  40. if xdelta > ydelta and xdelta > zdelta then
  41. rx = -ry - rz
  42. elseif ydelta > zdelta then
  43. ry = -rx - rz
  44. else
  45. rz = -rx - ry
  46. end
  47. return vec2(rx, ry)
  48. end
  49. --[[============================================================================
  50. ----- ORIENTATION & LAYOUT -----
  51. ==============================================================================]]
  52. -- forward & inverse matrices used for the flat orientation.
  53. local FLAT = {M = mat2(3.0/2.0, 0.0, 3.0^0.5/2.0, 3.0^0.5 ),
  54. W = mat2(2.0/3.0, 0.0, -1.0/3.0 , 3.0^0.5/3.0),
  55. start_angle = 0.0}
  56. -- forward & inverse matrices used for the pointy orientation.
  57. local POINTY = {M = mat2(3.0^0.5, 3.0^0.5/2.0, 0.0, 3.0/2.0),
  58. W = mat2(3.0^0.5/3.0, -1.0/3.0, 0.0, 2.0/3.0),
  59. start_angle = 0.5}
  60. -- stores layout: information that does not pertain to map shape
  61. function 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 cube_to_pixel(cube, layout)
  68. local M = layout.orientation.M
  69. local x = (M[1][1] * cube[1] + M[1][2] * cube[2]) * layout.size[1]
  70. local y = (M[2][1] * cube[1] + M[2][2] * cube[2]) * layout.size[2]
  71. return vec2(x + layout.origin[1], y + layout.origin[2])
  72. end
  73. -- screen to hex
  74. function pixel_to_cube(pix, layout)
  75. local W = layout.orientation.W
  76. local pix = (pix - layout.origin) / layout.size
  77. local s = W[1][1] * pix[1] + W[1][2] * pix[2]
  78. local t = W[2][1] * pix[1] + W[2][2] * pix[2]
  79. return cube_round(s, t, -s - t)
  80. end
  81. -- TODO test, learn am.draw
  82. function hex_corner_offset(corner, layout)
  83. local angle = 2.0 * math.pi * layout.orientation.start_angle + corner / 6
  84. return vec2(layout.size[1] * math.cos(angle),
  85. layout.size[2] * math.sin(angle))
  86. end
  87. -- TODO this thing
  88. function hex_corners(hex, layout)
  89. local corners = {}
  90. end
  91. --
  92. function cube_to_offset(cube)
  93. return vec2(cube[1], -cube[1] - cube[2] + (cube[1] + (cube[1] % 2)) / 2)
  94. end
  95. --
  96. function offset_to_cube(off)
  97. return vec2(off[1], off[2] - off[1] * (off[1] % 2) / 2)
  98. end
  99. --[[============================================================================
  100. ----- MAPS & STORAGE -----
  101. ==============================================================================]]
  102. -- information about the maps' dimensions are stored in a metatable, so you can
  103. -- retrieve details about arbitrary maps after they are created.
  104. -- TODO make all functions work regardless of layout. as it stands, they kind
  105. -- of do, just not always nicely.
  106. -- returns ordered ring-shaped map of |radius| from |center|.
  107. function ring_map(center, radius)
  108. local map = {}
  109. local mt = {__index={center=center, radius=radius}}
  110. setmetatable(map, mt)
  111. local walk = center + HEX_DIRECTIONS[6] * radius
  112. for i = 1, 6 do
  113. for j = 1, radius do
  114. table.insert(map, walk)
  115. walk = hex_neighbour(walk, i)
  116. end
  117. end
  118. return map
  119. end
  120. -- returns ordered hexagonal map of |radius| rings from |center|.
  121. -- the only difference between hex_spiral_map and hex_hexagonal_map is that
  122. -- hex_spiral_map is ordered, in a spiral path from the |center|.
  123. function spiral_map(center, radius)
  124. local map = {center}
  125. local mt = {__index={center=center, radius=radius}}
  126. setmetatable(map, mt)
  127. for i = 1, radius do
  128. table.append(map, hex_ring_map(center, i))
  129. end
  130. return map
  131. end
  132. -- returns unordered parallelogram-shaped map of |width| and |height|.
  133. function parallelogram_map(width, height)
  134. local map = {}
  135. local mt = {__index={width=width, height=height}}
  136. setmetatable(map, mt)
  137. for i = 0, width do
  138. for j = 0, height do
  139. map[vec2(i, -j)] = true
  140. end
  141. end
  142. return map
  143. end
  144. -- returns unordered triangular map of |size|.
  145. function triangular_map(size)
  146. local map = {}
  147. local mt = {__index={size=size}}
  148. setmetatable(map, mt)
  149. for i = 0, size do
  150. for j = size - s, size do
  151. map[vec2(i, j)] = true
  152. end
  153. end
  154. return map
  155. end
  156. -- returns unordered hexagonal map of |radius|.
  157. function hexagonal_map(radius)
  158. local map = {}
  159. local mt = {__index={radius=radius}}
  160. setmetatable(map, mt)
  161. for i = -radius, radius do
  162. local j1 = math.max(-radius, -i - radius)
  163. local j2 = math.min(radius, -i + radius)
  164. for j = j1, j2 do
  165. map[vec2(i, j)] = true
  166. end
  167. end
  168. return map
  169. end
  170. -- returns unordered rectangular map of |width| and |height|.
  171. function rectangular_map(width, height)
  172. local map = {}
  173. local mt = {__index={width=width, height=height}}
  174. setmetatable(map, mt)
  175. for i = 0, width do
  176. for j = 0, height do
  177. map[vec2(i, -j - math.floor(i/2))] = true
  178. end
  179. end
  180. return map
  181. end
  182. --[[============================================================================
  183. ----- TESTS -----
  184. ==============================================================================]]
  185. function test_all()
  186. print("it works trust me")
  187. end