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.

203 lines
5.5 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
4 years ago
5 years ago
  1. math.randomseed(os.time())
  2. math.random()
  3. math.random()
  4. math.random()
  5. -- assets/non-or-trivial code
  6. require "color"
  7. require "sound"
  8. require "texture"
  9. require "src/entity"
  10. require "src/extra"
  11. require "src/geometry"
  12. require "src/hexyz"
  13. require "src/grid"
  14. require "src/mob"
  15. require "src/projectile"
  16. require "src/tower"
  17. -- Globals
  18. WIN = am.window{
  19. width = 1920,
  20. height = 1080,
  21. title = "hexyz",
  22. highdpi = true,
  23. letterbox = true
  24. }
  25. OFF_SCREEN = vec2(WIN.width * 2) -- arbitrary pixel position that is garunteed to be off screen
  26. WORLD = false -- root scene node of everything considered to be in the game world
  27. TIME = 0 -- runtime of the current game in seconds (not whole program runtime)
  28. SCORE = 0 -- score of the player
  29. MONEY = 0 -- available resources
  30. MOUSE = false -- position of the mouse at the start of every frame, if an action is tracking it
  31. -- global audio settings
  32. MUSIC_VOLUME = 0.1
  33. SFX_VOLUME = 0.1
  34. -- game stuff
  35. SELECTED_TOWER_TYPE = TOWER_TYPE.REDEYE
  36. -- top right display types
  37. local TRDTS = {
  38. NOTHING = -1,
  39. CENTERED_EVENQ = 0,
  40. EVENQ = 1,
  41. HEX = 2,
  42. PLATFORM = 3,
  43. PERF = 4,
  44. SEED = 5
  45. }
  46. local TRDT = TRDTS.SEED
  47. local function select_tower(tower_type)
  48. SELECTED_TOWER_TYPE = tower_type
  49. WIN.scene"tower_tooltip".text = tower_type_tostring(tower_type)
  50. end
  51. local function game_action(scene)
  52. if SCORE < 0 then game_end() end
  53. TIME = TIME + am.delta_time
  54. SCORE = SCORE + am.delta_time
  55. MOUSE = WIN:mouse_position()
  56. local hex = pixel_to_hex(MOUSE - WORLDSPACE_COORDINATE_OFFSET)
  57. local rounded_mouse = hex_to_pixel(hex) + WORLDSPACE_COORDINATE_OFFSET
  58. local evenq = hex_to_evenq(hex)
  59. local centered_evenq = evenq{ y = -evenq.y } - vec2(math.floor(HEX_GRID_WIDTH/2)
  60. , math.floor(HEX_GRID_HEIGHT/2))
  61. local tile = HEX_MAP.get(hex.x, hex.y)
  62. local hot = is_interactable(tile, evenq{ y = -evenq.y })
  63. do_entity_updates()
  64. do_mob_spawning()
  65. if WIN:mouse_pressed"left" then
  66. if hot and is_buildable(hex, tile, nil) then
  67. make_and_register_tower(hex, SELECTED_TOWER_TYPE)
  68. end
  69. end
  70. if WIN:key_pressed"escape" then
  71. game_end()
  72. elseif WIN:key_pressed"f1" then
  73. TRDT = (TRDT + 1) % #table.keys(TRDTS)
  74. elseif WIN:key_pressed"tab" then
  75. select_tower((SELECTED_TOWER_TYPE + 1) % #table.keys(TOWER_TYPE))
  76. end
  77. if tile and hot then
  78. WIN.scene"hex_cursor".center = rounded_mouse
  79. else
  80. WIN.scene"hex_cursor".center = OFF_SCREEN
  81. end
  82. WIN.scene"score".text = string.format("SCORE: %.2f", SCORE)
  83. WIN.scene"money".text = string.format("MONEY: %d", MONEY)
  84. do
  85. local str = ""
  86. if TRDT == TRDTS.CENTERED_EVENQ then
  87. str = centered_evenq.x .. "," .. centered_evenq.y .. " (cevenq)"
  88. elseif TRDT == TRDTS.EVENQ then
  89. str = evenq.x .. "," .. evenq.y .. " (evenq)"
  90. elseif TRDT == TRDTS.HEX then
  91. str = hex.x .. "," .. hex.y .. " (hex)"
  92. elseif TRDT == TRDTS.PLATFORM then
  93. str = string.format("%s %s lang %s", am.platform, am.version, am.language())
  94. elseif TRDT == TRDTS.PERF then
  95. str = table.tostring(am.perf_stats())
  96. elseif TRDT == TRDTS.SEED then
  97. str = "SEED: " .. HEX_MAP.seed
  98. end
  99. WIN.scene"coords".text = str
  100. end
  101. end
  102. function game_end()
  103. WIN.scene.paused = true
  104. -- de-initialize stuff
  105. delete_all_entities()
  106. SCORE = 0
  107. WIN.scene = game_scene()
  108. end
  109. function update_score(diff)
  110. SCORE = SCORE + diff
  111. end
  112. local function toolbelt()
  113. local toolbelt_height = hex_height(HEX_SIZE) * 2
  114. local tower_tooltip = am.translate(WIN.left + 10, WIN.bottom + toolbelt_height + 10)
  115. ^ am.text(tower_type_tostring(SELECTED_TOWER_TYPE), "left"):tag"tower_tooltip"
  116. local toolbelt = am.group{
  117. tower_tooltip,
  118. am.rect(WIN.left, WIN.bottom, WIN.right, WIN.bottom + toolbelt_height, COLORS.TRANSPARENT)
  119. }
  120. --[[
  121. local padding = 22
  122. local size = toolbelt_height - padding
  123. for i = 0, 0 do
  124. toolbelt:append(
  125. am.translate(vec2(size + padding, 0) * i + vec2(WIN.left + padding/3, WIN.bottom + padding/3))
  126. ^ am.rect(0, 0, size, size, COLORS.BLACK)
  127. )
  128. end
  129. ]]
  130. return toolbelt
  131. end
  132. -- @NOTE must be global to allow the game_action to reference it
  133. function game_scene()
  134. local score = am.translate(WIN.left + 10, WIN.top - 20) ^ am.text("", "left"):tag"score"
  135. local money = am.translate(WIN.left + 10, WIN.top - 40) ^ am.text("", "left"):tag"money"
  136. local coords = am.translate(WIN.right - 10, WIN.top - 20) ^ am.text("", "right", "top"):tag"coords"
  137. local hex_cursor = am.circle(OFF_SCREEN, HEX_SIZE, COLORS.TRANSPARENT, 6):tag"hex_cursor"
  138. local curtain = am.rect(WIN.left, WIN.bottom, WIN.right, WIN.top, COLORS.TRUE_BLACK)
  139. curtain:action(coroutine.create(function()
  140. am.wait(am.tween(curtain, 3, { color = vec4(0) }, am.ease.out(am.ease.hyperbola)))
  141. WIN.scene:remove(curtain)
  142. end))
  143. HEX_MAP, WORLD = random_map()
  144. local scene = am.group{
  145. WORLD,
  146. curtain,
  147. hex_cursor,
  148. toolbelt(),
  149. score,
  150. money,
  151. coords,
  152. }
  153. scene:action(game_action)
  154. --scene:action(am.play(SOUNDS.TRACK1))
  155. return scene
  156. end
  157. load_textures()
  158. WIN.scene = game_scene()
  159. noglobals()