-- title: drop
-- author: pixelbath
-- desc: 99 balls / wallsmash
-- script: lua
-- https://codeincomplete.com/articles/collision-detection-in-breakout/
t=0
dt=0
x=96
y=24
num_rows=10
num_cols=10
rows_start=4
balls={}
lasers=0
blocks={}
blockWidth = 24
blockHeight = 13
previewDotCount = 31
-- starting player stuff
playerBalls = 1
playerLasers = 0
launchBalls = 0
xpos=120
ypos=130
angle=-90
initialAngleSpeed=1
angleMin = -170
angleMax = -10
ballVel = 2.5
laserJitter = 2 -- degrees
-- launch control
ballGapTime = 50
laserGapTime = 20 -- todo: random delay?
launchMode = false
launchBallTimer = 0
launchLaserTimer = 0
launchBalls = playerBalls
launchLasers = playerLasers
-- debug stuff
freeze = false
function 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
end
end
function 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 - 1
end
function 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)
end
function 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
end
end
function 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 false
end
function 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
end
end
function 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
end
end
function 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 7
function 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
end
end
-- run this stuff for init
generate_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
--
-- 001:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-- 002:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-- 003:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-- 004:0000000000ccc0000ccccc000ccccc000ccccc0000ccc0000000000000000000
--
--
-- 000:00000000ffffffff00000000ffffffff
-- 001:0123456789abcdeffedcba9876543210
-- 002:0123456789abcdef0123456789abcdef
--
--
-- 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000
--
--
-- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
--