drop.lua 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. -- title: drop
  2. -- author: pixelbath
  3. -- desc: 99 balls / wallsmash
  4. -- script: lua
  5. -- https://codeincomplete.com/articles/collision-detection-in-breakout/
  6. t=0
  7. dt=0
  8. x=96
  9. y=24
  10. num_rows=10
  11. num_cols=10
  12. rows_start=4
  13. balls={}
  14. lasers=0
  15. blocks={}
  16. blockWidth = 24
  17. blockHeight = 13
  18. previewDotCount = 31
  19. -- starting player stuff
  20. playerBalls = 1
  21. playerLasers = 0
  22. launchBalls = 0
  23. xpos=120
  24. ypos=130
  25. angle=-90
  26. initialAngleSpeed=1
  27. angleMin = -170
  28. angleMax = -10
  29. ballVel = 2.5
  30. laserJitter = 2 -- degrees
  31. -- launch control
  32. ballGapTime = 50
  33. laserGapTime = 20 -- todo: random delay?
  34. launchMode = false
  35. launchBallTimer = 0
  36. launchLaserTimer = 0
  37. launchBalls = playerBalls
  38. launchLasers = playerLasers
  39. -- debug stuff
  40. freeze = false
  41. function generate_grid()
  42. for row=0,num_rows-1 do
  43. blocks[row] = {}
  44. for col=0,num_cols-1 do
  45. if row < 5 and math.random() > 0.5 then
  46. blocks[row][col] = 5
  47. else
  48. blocks[row][col] = 0
  49. end
  50. end
  51. end
  52. end
  53. function launch_ball()
  54. theta=math.pi * angle / 180
  55. table.insert(balls, {
  56. x = xpos,
  57. y = ypos,
  58. vx = ballVel * math.cos(theta),
  59. vy = ballVel * math.sin(theta),
  60. })
  61. launchBalls = launchBalls - 1
  62. end
  63. function draw_preview()
  64. theta=math.pi * angle / 180
  65. xtarget=xpos + (160 * math.cos(theta))
  66. ytarget=ypos + (160 * math.sin(theta))
  67. dotGapX = (xtarget - xpos) / previewDotCount
  68. dotGapY = (ytarget - ypos) / previewDotCount
  69. -- line(xpos, ypos, xtarget, ytarget, 8)
  70. dotx=xpos
  71. doty=ypos
  72. for i=0,previewDotCount do
  73. pix(dotx, doty, 5)
  74. dotx = dotx + dotGapX
  75. doty = doty + dotGapY
  76. end
  77. print(playerBalls, xpos-8, 130, 12, false, 1, true)
  78. print(playerLasers, xpos+5, 130, 10, false, 1, true)
  79. end
  80. function draw_balls_and_lasers()
  81. for k,ball in pairs(balls) do
  82. circ(ball.x, ball.y, 1, 12)
  83. ball.x = ball.x + ball.vx
  84. ball.y = ball.y + ball.vy
  85. check_ball_collisions(ball)
  86. -- wall bounce
  87. if ball.x <= 0 or ball.x >= 240 then
  88. ball.vx = ball.vx * -1
  89. end
  90. if ball.y <= 0 then
  91. ball.vy = ball.vy * -1
  92. end
  93. -- prune the fallen boyz
  94. if ball.y >= ypos + 2 then
  95. table.remove(balls, k)
  96. if #balls == 0 then
  97. end
  98. end
  99. end
  100. end
  101. function circleRect(cx, cy, radius, rx, ry, rw, rh)
  102. -- temporary variables to set edges for testing
  103. local testX = cx
  104. local testY = cy
  105. -- which edge is closest?
  106. if cx < rx then testX = rx -- test left edge
  107. elseif cx > rx+rw then testX = rx+rw end -- right edge
  108. if cy < ry then testY = ry -- top edge
  109. elseif cy > ry+rh then testY = ry+rh end -- bottom edge
  110. -- get distance from closest edges
  111. local distX = cx-testX
  112. local distY = cy-testY
  113. local distance = math.sqrt( (distX*distX) + (distY*distY) )
  114. -- if the distance is less than the radius, collision!
  115. if distance <= radius then
  116. return true
  117. end
  118. return false
  119. end
  120. function check_ball_collisions(ball)
  121. for row=0,num_rows-1 do
  122. for col=0,num_cols-1 do
  123. blockVal = blocks[row][col]
  124. if blockVal > 0 then
  125. local blockX = col * blockWidth
  126. local blockY = row * blockHeight
  127. -- if ball.x >= blockX then
  128. -- end
  129. -- if ball.x >= col * blockWidth and ball.x <= col * blockWidth + blockWidth then
  130. -- if ball.y >= row * blockHeight and ball.y <= row * blockHeight + blockHeight then
  131. -- if row * blockHeight - ball.y <= 1 or row * blockHeight + blockHeight - ball.y <= 1 then
  132. -- ball.vy = ball.vy * -1
  133. -- blocks[row][col] = blockVal - 1
  134. -- freeze = true
  135. -- else
  136. -- ball.vx = ball.vx * -1
  137. -- blocks[row][col] = blockVal - 1
  138. -- freeze = true
  139. -- end
  140. -- end
  141. -- end
  142. if circleRect(ball.x, ball.y, 2, blockX, blockY, blockWidth, blockHeight) then
  143. -- bottom
  144. if ball.y <= blockY - (blockHeight/2) then
  145. -- ball.y = blockY+1
  146. ball.vy = ball.vy * -1
  147. return
  148. end
  149. -- top
  150. if ball.y >= blockY + (blockHeight/2) then
  151. -- ball.y = blockY-1
  152. ball.vy = ball.vy * -1
  153. return
  154. end
  155. -- left
  156. if ball.x < blockX - (blockWidth/2) then
  157. -- ball.x = blockX-1
  158. ball.vx = ball.vx * -1
  159. return
  160. end
  161. -- right
  162. if ball.x > blockX then
  163. -- ball.x = blockX+1
  164. ball.vx = ball.vx * -1
  165. return
  166. end
  167. freeze = true
  168. end
  169. end
  170. end
  171. end
  172. end
  173. function draw_blocks()
  174. for row=0,num_rows-1 do
  175. for col=0,num_cols-1 do
  176. blockVal = blocks[row][col]
  177. colorCursor = 1
  178. printPos = col * blockWidth + 8
  179. if blockVal > 0 then
  180. if blockVal < 18 then
  181. colorCursor = colorCursor + 1
  182. end
  183. if blockVal < 14 then
  184. colorCursor = colorCursor + 1
  185. end
  186. if blockVal < 9 then
  187. colorCursor = colorCursor + 1
  188. printPos = col * blockWidth + 10
  189. end
  190. rect(col * blockWidth, row * blockHeight, blockWidth, blockHeight, colorCursor)
  191. print(blockVal, printPos, row * blockHeight + 4, 0, false, 1, true)
  192. end
  193. end
  194. end
  195. end
  196. function draw_debug()
  197. print(angle, 2, 130, 5, false, 1, true)
  198. print(playerBalls, 18, 130, 5, false, 1, true)
  199. print(#balls, 24, 130, 5, false, 1, true)
  200. print(launchMode, 34, 130, 5, false, 1, true)
  201. print(launchBallTimer, 64, 130, 5, false, 1, true)
  202. end
  203. -- P1 starts at 0; for players up to P4 add 8 to the ID value
  204. -- U D L R, A B X Y -> 0 1 2 3, 4 5 6 7
  205. function handle_input()
  206. -- move faster
  207. if btn(5) then
  208. angleSpeed=initialAngleSpeed + initialAngleSpeed * 0.5
  209. else
  210. angleSpeed=initialAngleSpeed
  211. end
  212. -- move slower
  213. if btn(6) then
  214. angleSpeed=initialAngleSpeed * 0.3
  215. else
  216. angleSpeed=initialAngleSpeed
  217. end
  218. if btnp(4) then
  219. launchMode = true
  220. end
  221. if btn(2) then
  222. angle=angle-angleSpeed
  223. end
  224. if btn(3) then
  225. angle=angle+angleSpeed
  226. end
  227. -- clamp angle values
  228. if angle < angleMin then
  229. angle=angleMin-angleSpeed
  230. end
  231. if angle > angleMax then
  232. angle=angleMax
  233. end
  234. end
  235. -- run this stuff for init
  236. generate_grid()
  237. function TIC()
  238. if not freeze then
  239. t=time()
  240. end
  241. cls(0)
  242. draw_blocks()
  243. if launchMode then
  244. if launchBalls > 0 then
  245. if launchBallTimer == 0 then
  246. launchBallTimer = ballGapTime
  247. launch_ball()
  248. end
  249. launchBallTimer = launchBallTimer - 1
  250. end
  251. if launchLasers > 0 then
  252. if launchBallTimer == 0 then
  253. launchLaserTimer = ballGapTime
  254. launch_laser()
  255. end
  256. launchLaserTimer = launchLaserTimer - 1
  257. end
  258. draw_balls_and_lasers()
  259. -- if we're outta balls, turn off launchMode
  260. if #balls == 0 then
  261. launchMode = false
  262. launchBallTimer = 0
  263. launchLaserTimer = 0
  264. -- temp
  265. launchBalls = playerBalls
  266. end
  267. else
  268. handle_input()
  269. draw_preview()
  270. end
  271. draw_debug()
  272. end
  273. -- <TILES>
  274. -- 001:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  275. -- 002:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  276. -- 003:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  277. -- 004:0000000000ccc0000ccccc000ccccc000ccccc0000ccc0000000000000000000
  278. -- </TILES>
  279. -- <WAVES>
  280. -- 000:00000000ffffffff00000000ffffffff
  281. -- 001:0123456789abcdeffedcba9876543210
  282. -- 002:0123456789abcdef0123456789abcdef
  283. -- </WAVES>
  284. -- <SFX>
  285. -- 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000
  286. -- </SFX>
  287. -- <PALETTE>
  288. -- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
  289. -- </PALETTE>