main.lua 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. -- title: cylshooter
  2. -- author: pixelbath
  3. -- desc: short description
  4. -- site: website link
  5. -- license: MIT License (change this to your license of choice)
  6. -- version: 0.1
  7. -- script: lua
  8. -- The idea:
  9. -- like Resogun, a cylindrical shooter
  10. -- 1. render map
  11. -- 2. fix column-by-column, raycast style
  12. -- 3. how to draw background?
  13. -- 1. render bg map offscreen
  14. -- 2. memcpy to onscreen
  15. -- 3. render fg map offscreen
  16. -- 4. memcpy/pix the fg to the screen?
  17. local t=0
  18. local player = {
  19. x=140, y=70,
  20. vx=0, vy=0,
  21. speed=1.5,
  22. }
  23. function player:update()
  24. self.vx = 0
  25. self.vy = 0
  26. if btn(0) then
  27. self.vy=-self.speed
  28. end
  29. if btn(1) then
  30. self.vy=self.speed
  31. end
  32. if btn(2) then
  33. self.vx=-self.speed
  34. end
  35. if btn(3) then
  36. self.vx=self.speed
  37. end
  38. -- slow down diagonal movements
  39. if self.vx * self.vy ~= 0 then
  40. self.vx = self.vx * 0.707
  41. self.vy = self.vy * 0.707
  42. end
  43. self.x = self.x + self.vx
  44. self.y = self.y + self.vy
  45. end
  46. local Random = {
  47. angle = {
  48. between = function(min, max)
  49. return min + math.random() * (max - min)
  50. end
  51. }
  52. }
  53. local Shot = {
  54. x = 20,
  55. y = 20,
  56. speed = {},
  57. direction = {},
  58. position = {},
  59. velocity = {},
  60. bullets = {},
  61. }
  62. function Shot:new()
  63. local shot = setmetatable({}, { __index = Shot })
  64. shot.bullets = {}
  65. return shot
  66. end
  67. function Shot.speed:set(value)
  68. return function()
  69. Shot.speed = value
  70. end
  71. end
  72. function Shot.position:set(distance, bearing)
  73. return function()
  74. Shot.x = math.cos(math.rad(bearing)) * distance
  75. Shot.y = math.sin(math.rad(bearing)) * distance
  76. end
  77. end
  78. function Shot.velocity:set(speed, direction)
  79. return function()
  80. Shot.speed = speed
  81. Shot.direction = direction
  82. end
  83. end
  84. function Shot.direction:add(degrees)
  85. return function()
  86. Shot.direction = Shot.direction + degrees
  87. end
  88. end
  89. -- Pattern manager
  90. local PatternManager = {
  91. activePatterns = {},
  92. windowWidth = 800, -- Default window size
  93. windowHeight = 600 -- Default window size
  94. }
  95. function PatternManager:new(windowWidth, windowHeight)
  96. local manager = setmetatable({}, { __index = PatternManager })
  97. manager.activePatterns = {}
  98. manager.windowWidth = windowWidth or 800
  99. manager.windowHeight = windowHeight or 600
  100. return manager
  101. end
  102. -- Initialize the pattern manager with window dimensions
  103. patternManager = PatternManager:new(240,136)
  104. function TIC()
  105. cls()
  106. if t==0 then
  107. -- Start both patterns
  108. patternManager:startPattern("firstShot")
  109. patternManager:startPattern("secondShot")
  110. end
  111. -- player:update()
  112. patternManager:update()
  113. patternManager:draw()
  114. t = t + 1
  115. end
  116. -- Pattern system functions
  117. local function aim()
  118. return function()
  119. local dx = player.x - Shot.x
  120. local dy = player.y - Shot.y
  121. Shot.direction = math.deg(math.atan2(dy, dx))
  122. end
  123. end
  124. local function line(count, options)
  125. return function()
  126. local speedChange = options.shotSpeedChange or 0
  127. local currentSpeed = Shot.speed
  128. for i = 1, count do
  129. currentSpeed = currentSpeed + (speedChange * (count - 1))
  130. table.insert(Shot.bullets, {
  131. x = Shot.x,
  132. y = Shot.y,
  133. speed = currentSpeed,
  134. direction = Shot.direction,
  135. vanishTime = nil
  136. })
  137. end
  138. end
  139. end
  140. local function wait(frames)
  141. return function()
  142. for i = 1, frames do
  143. coroutine.yield()
  144. end
  145. end
  146. end
  147. local function fire(actions)
  148. return function()
  149. local bullet = {
  150. x = Shot.x,
  151. y = Shot.y,
  152. speed = Shot.speed,
  153. direction = Shot.direction,
  154. vanishTime = nil
  155. }
  156. -- for _, action in ipairs(actions) do
  157. -- if type(action) == "function" then
  158. -- action(bullet)
  159. -- end
  160. -- end
  161. table.insert(Shot.bullets, bullet)
  162. end
  163. end
  164. local function vanish()
  165. return function(bullet)
  166. bullet.vanishTime = 0
  167. end
  168. end
  169. local function loop(actions)
  170. return function()
  171. while true do
  172. for _, action in ipairs(actions) do
  173. if type(action) == "function" then
  174. action()
  175. end
  176. end
  177. end
  178. end
  179. end
  180. -- Pattern definitions
  181. local patterns = {
  182. firstShot = {
  183. Shot.speed:set(2),
  184. loop({
  185. -- Shot.position:set(150, Random.angle.between(0, 360)),
  186. aim(),
  187. line(8, { shotSpeedChange = 0.5 }),
  188. wait(100)
  189. })
  190. },
  191. secondShot = {
  192. Shot.velocity:set(1, 90),
  193. loop({
  194. fire({
  195. wait(60),
  196. vanish()
  197. }),
  198. Shot.direction:add(12),
  199. wait(1)
  200. })
  201. },
  202. }
  203. function PatternManager:startPattern(patternName)
  204. local pattern = patterns[patternName]
  205. if not pattern then
  206. error("Pattern " .. patternName .. " not found")
  207. end
  208. local co = coroutine.create(function()
  209. for _, action in ipairs(pattern) do
  210. if type(action) == "function" then
  211. action()
  212. end
  213. end
  214. end)
  215. table.insert(self.activePatterns, {
  216. coroutine = co,
  217. name = patternName
  218. })
  219. end
  220. function PatternManager:update()
  221. -- Update all active patterns
  222. for i = #self.activePatterns, 1, -1 do
  223. local pattern = self.activePatterns[i]
  224. if coroutine.status(pattern.coroutine) ~= "dead" then
  225. local success, err = coroutine.resume(pattern.coroutine)
  226. if not success then
  227. error("Error in pattern " .. pattern.name .. ": " .. err)
  228. end
  229. else
  230. table.remove(self.activePatterns, i)
  231. end
  232. end
  233. -- Update bullet positions
  234. for i = #Shot.bullets, 1, -1 do
  235. local bullet = Shot.bullets[i]
  236. if bullet.vanishTime then
  237. bullet.vanishTime = bullet.vanishTime + 1
  238. if bullet.vanishTime >= 30 then
  239. table.remove(Shot.bullets, i)
  240. end
  241. else
  242. bullet.x = bullet.x + math.cos(math.rad(bullet.direction)) * bullet.speed
  243. bullet.y = bullet.y + math.sin(math.rad(bullet.direction)) * bullet.speed
  244. -- Remove bullets that are off screen
  245. if bullet.x < -50 or bullet.x > self.windowWidth + 50 or
  246. bullet.y < -50 or bullet.y > self.windowHeight + 50 then
  247. table.remove(Shot.bullets, i)
  248. end
  249. end
  250. end
  251. end
  252. function PatternManager:draw()
  253. -- Draw all bullets
  254. for _, bullet in ipairs(Shot.bullets) do
  255. circ(bullet.x, bullet.y, 2, 6)
  256. end
  257. end
  258. -- <PALETTE>
  259. -- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
  260. -- </PALETTE>