| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 | -- title: drop-- author: pixelbath-- desc:   99 balls / wallsmash-- script: lua-- https://codeincomplete.com/articles/collision-detection-in-breakout/t=0dt=0x=96y=24num_rows=10num_cols=10rows_start=4balls={}lasers=0blocks={}blockWidth = 24blockHeight = 13previewDotCount = 31-- starting player stuffplayerBalls = 1playerLasers = 0launchBalls = 0xpos=120ypos=130angle=-90initialAngleSpeed=1angleMin = -170angleMax = -10ballVel = 2.5laserJitter = 2 -- degrees-- launch controlballGapTime = 50laserGapTime = 20 -- todo: random delay?launchMode = falselaunchBallTimer = 0launchLaserTimer = 0launchBalls = playerBallslaunchLasers = playerLasers-- debug stufffreeze = falsefunction generate_grid()  for row=0,num_rows-1 do    blocks[row] = {}    for col=0,num_cols-1 do      if row < 5 and math.random() > 0.5 then        blocks[row][col] = 5      else        blocks[row][col] = 0      end    end  endendfunction launch_ball()  theta=math.pi * angle / 180  table.insert(balls, {    x = xpos,    y = ypos,    vx = ballVel * math.cos(theta),    vy = ballVel * math.sin(theta),  })  launchBalls = launchBalls - 1endfunction draw_preview()  theta=math.pi * angle / 180  xtarget=xpos + (160 * math.cos(theta))  ytarget=ypos + (160 * math.sin(theta))  dotGapX = (xtarget - xpos) / previewDotCount  dotGapY = (ytarget - ypos) / previewDotCount  -- line(xpos, ypos, xtarget, ytarget, 8)  dotx=xpos  doty=ypos  for i=0,previewDotCount do    pix(dotx, doty, 5)    dotx = dotx + dotGapX    doty = doty + dotGapY  end  print(playerBalls, xpos-8, 130, 12, false, 1, true)  print(playerLasers, xpos+5, 130, 10, false, 1, true)endfunction draw_balls_and_lasers()  for k,ball in pairs(balls) do    circ(ball.x, ball.y, 1, 12)    ball.x = ball.x + ball.vx    ball.y = ball.y + ball.vy    check_ball_collisions(ball)    -- wall bounce    if ball.x <= 0 or ball.x >= 240 then      ball.vx = ball.vx * -1    end    if ball.y <= 0 then      ball.vy = ball.vy * -1    end    -- prune the fallen boyz    if ball.y >= ypos + 2 then      table.remove(balls, k)      if #balls == 0 then              end    end  endendfunction circleRect(cx, cy, radius, rx, ry, rw, rh)  -- temporary variables to set edges for testing  local testX = cx  local testY = cy  -- which edge is closest?  if cx < rx then         testX = rx          -- test left edge  elseif cx > rx+rw then  testX = rx+rw end   -- right edge  if cy < ry then          testY = ry         -- top edge  elseif cy > ry+rh then  testY = ry+rh end   -- bottom edge  -- get distance from closest edges  local distX = cx-testX  local distY = cy-testY  local distance = math.sqrt( (distX*distX) + (distY*distY) )  -- if the distance is less than the radius, collision!  if distance <= radius then    return true  end  return falseendfunction check_ball_collisions(ball)  for row=0,num_rows-1 do    for col=0,num_cols-1 do      blockVal = blocks[row][col]      if blockVal > 0 then        local blockX = col * blockWidth        local blockY = row * blockHeight        -- if ball.x >= blockX then        -- end        -- if ball.x >= col * blockWidth and ball.x <= col * blockWidth + blockWidth then        --   if ball.y >= row * blockHeight and ball.y <= row * blockHeight + blockHeight then        --     if row * blockHeight - ball.y <= 1 or row * blockHeight + blockHeight - ball.y <= 1 then        --       ball.vy = ball.vy * -1        --       blocks[row][col] = blockVal - 1        --       freeze = true        --     else        --       ball.vx = ball.vx * -1        --       blocks[row][col] = blockVal - 1        --       freeze = true        --     end        --   end        -- end        if circleRect(ball.x, ball.y, 2, blockX, blockY, blockWidth, blockHeight) then          -- bottom          if ball.y <= blockY - (blockHeight/2) then            -- ball.y = blockY+1            ball.vy = ball.vy * -1            return          end          -- top          if ball.y >= blockY + (blockHeight/2) then            -- ball.y = blockY-1            ball.vy = ball.vy * -1            return          end          -- left          if ball.x < blockX - (blockWidth/2) then            -- ball.x = blockX-1            ball.vx = ball.vx * -1            return          end          -- right          if ball.x > blockX then            -- ball.x = blockX+1            ball.vx = ball.vx * -1            return          end          freeze = true        end      end    end  endendfunction draw_blocks()  for row=0,num_rows-1 do    for col=0,num_cols-1 do      blockVal = blocks[row][col]      colorCursor = 1      printPos = col * blockWidth + 8      if blockVal > 0 then        if blockVal < 18 then          colorCursor = colorCursor + 1        end        if blockVal < 14 then          colorCursor = colorCursor + 1        end        if blockVal < 9 then          colorCursor = colorCursor + 1          printPos = col * blockWidth + 10        end        rect(col * blockWidth, row * blockHeight, blockWidth, blockHeight, colorCursor)        print(blockVal, printPos, row * blockHeight + 4, 0, false, 1, true)      end    end  endendfunction draw_debug()  print(angle, 2, 130, 5, false, 1, true)  print(playerBalls, 18, 130, 5, false, 1, true)  print(#balls, 24, 130, 5, false, 1, true)  print(launchMode, 34, 130, 5, false, 1, true)  print(launchBallTimer, 64, 130, 5, false, 1, true)end-- P1 starts at 0; for players up to P4 add 8 to the ID value-- U D L R, A B X Y -> 0 1 2 3, 4 5 6 7function handle_input()  -- move faster  if btn(5) then    angleSpeed=initialAngleSpeed + initialAngleSpeed * 0.5  else    angleSpeed=initialAngleSpeed  end  -- move slower  if btn(6) then    angleSpeed=initialAngleSpeed * 0.3  else    angleSpeed=initialAngleSpeed  end  if btnp(4) then    launchMode = true  end  if btn(2) then    angle=angle-angleSpeed  end  if btn(3) then    angle=angle+angleSpeed  end  -- clamp angle values  if angle < angleMin then    angle=angleMin-angleSpeed  end  if angle > angleMax then    angle=angleMax  endend-- run this stuff for initgenerate_grid()function TIC()  if not freeze then    t=time()  end  cls(0)  draw_blocks()  if launchMode then    if launchBalls > 0 then      if launchBallTimer == 0 then        launchBallTimer = ballGapTime        launch_ball()      end      launchBallTimer = launchBallTimer - 1    end    if launchLasers > 0 then      if launchBallTimer == 0 then        launchLaserTimer = ballGapTime        launch_laser()      end      launchLaserTimer = launchLaserTimer - 1    end    draw_balls_and_lasers()    -- if we're outta balls, turn off launchMode    if #balls == 0 then      launchMode = false      launchBallTimer = 0      launchLaserTimer = 0      -- temp      launchBalls = playerBalls    end  else    handle_input()    draw_preview()  end  draw_debug()end-- <TILES>-- 001:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-- 002:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-- 003:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-- 004:0000000000ccc0000ccccc000ccccc000ccccc0000ccc0000000000000000000-- </TILES>-- <WAVES>-- 000:00000000ffffffff00000000ffffffff-- 001:0123456789abcdeffedcba9876543210-- 002:0123456789abcdef0123456789abcdef-- </WAVES>-- <SFX>-- 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000-- </SFX>-- <PALETTE>-- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57-- </PALETTE>
 |