Author Topic: Breakout  (Read 7318 times)

0 Members and 1 Guest are viewing this topic.

This topic contains a post which is marked as Best Answer. Press here if you would like to see it.

FellippeHeitor

  • Guest
Breakout
« on: March 24, 2019, 11:34:16 pm »
Control the paddle with your mouse or your keyboard arrows.

Code: QB64: [Select]
  1. CONST true = -1, false = 0
  2.  
  3. DIM gameArea AS LONG
  4. gameArea = _NEWIMAGE(400, 500, 32)
  5. SCREEN gameArea
  6. _TITLE "Breakout"
  7.  
  8. TYPE Block
  9.     x AS INTEGER
  10.     y AS INTEGER
  11.     c AS _UNSIGNED LONG
  12.     state AS _BYTE
  13.  
  14. TYPE Ball
  15.     x AS SINGLE
  16.     y AS SINGLE
  17.     c AS _UNSIGNED LONG
  18.     radius AS INTEGER
  19.     state AS _BYTE
  20.     xDir AS _BYTE
  21.     yDir AS _BYTE
  22.     xVel AS SINGLE
  23.     yVel AS SINGLE
  24.  
  25. CONST blockWidth = 50
  26. CONST blockHeight = 25
  27. CONST paddleHeight = 10
  28.  
  29. DIM SHARED block(1 TO 80) AS Block, ball AS Ball
  30. DIM SHARED win AS _BYTE, quit AS STRING * 1
  31. DIM SHARED paddleX AS INTEGER, paddleY AS INTEGER
  32. DIM SHARED paddleWidth AS INTEGER
  33. DIM SHARED score AS INTEGER, lives AS INTEGER
  34.  
  35. paddleY = _HEIGHT - blockHeight - paddleHeight - 1
  36.  
  37.     IF lives = 0 THEN score = 0: lives = 3
  38.     win = false
  39.     generateBlocks
  40.     paddleWidth = 100
  41.     ball.state = false
  42.     ball.c = _RGB32(161, 161, 155)
  43.     ball.radius = 5
  44.     ball.xDir = 1
  45.     ball.yDir = -1
  46.     ball.xVel = 3
  47.     ball.yVel = 3
  48.  
  49.     _KEYCLEAR
  50.  
  51.     DO
  52.         alpha = map(ball.xVel, 3, 6, 255, 30)
  53.         LINE (0, 0)-(_WIDTH, _HEIGHT), _RGBA32(0, 0, 0, alpha), BF
  54.         showBlocks
  55.         doPaddle
  56.         doBall
  57.  
  58.         m$ = "Score:" + STR$(score) + " Lives:" + STR$(lives)
  59.         COLOR _RGB32(0, 0, 0)
  60.         _PRINTSTRING (1, 1), m$
  61.         COLOR _RGB32(255, 255, 255)
  62.         _PRINTSTRING (0, 0), m$
  63.  
  64.         _DISPLAY
  65.         _LIMIT 60
  66.     LOOP UNTIL win OR lives = 0
  67.  
  68.  
  69.     CLS
  70.     IF win THEN
  71.         PRINT "Good job, you win."
  72.     ELSE
  73.         PRINT "You lose."
  74.     END IF
  75.  
  76.     PRINT "Continue (y/n)?"
  77.  
  78.     DO
  79.         quit = LCASE$(INPUT$(1))
  80.     LOOP UNTIL quit = "y" OR quit = "n"
  81.  
  82. LOOP WHILE quit = "y"
  83.  
  84.  
  85. SUB generateBlocks
  86.     FOR i = 1 TO 8
  87.         FOR j = 1 TO 10
  88.             b = b + 1
  89.             block(b).x = (i - 1) * blockWidth
  90.             block(b).y = (j - 1) * blockHeight
  91.             block(b).c = _RGB32(255 * RND, 255 * RND, 255 * RND)
  92.             block(b).state = RND
  93.         NEXT
  94.     NEXT
  95.  
  96. SUB showBlocks
  97.     win = true
  98.     FOR i = 1 TO 80
  99.         IF block(i).state = false THEN _CONTINUE
  100.         win = false
  101.         LINE (block(i).x, block(i).y)-STEP(blockWidth - 1, blockHeight - 1), block(i).c, BF
  102.         LINE (block(i).x, block(i).y)-STEP(blockWidth - 1, blockHeight - 1), _RGB32(0, 0, 0), B
  103.     NEXT
  104.  
  105. SUB doPaddle
  106.     STATIC lastX AS INTEGER
  107.  
  108.     IF _MOUSEX <> lastX THEN
  109.         lastX = _MOUSEX
  110.         paddleX = _MOUSEX - paddleWidth / 2
  111.     END IF
  112.  
  113.     IF _KEYDOWN(19200) THEN paddleX = paddleX - 5
  114.     IF _KEYDOWN(19712) THEN paddleX = paddleX + 5
  115.  
  116.     IF paddleX < 0 THEN paddleX = 0
  117.     IF paddleX + paddleWidth > _WIDTH - 1 THEN paddleX = _WIDTH - 1 - paddleWidth
  118.  
  119.     LINE (paddleX + paddleHeight / 2, paddleY)-STEP(paddleWidth - paddleHeight, paddleHeight), _RGB32(89, 161, 255), BF
  120.     CircleFill paddleX + paddleHeight / 2, paddleY + paddleHeight / 2, paddleHeight / 2, _RGB32(194, 89, 61)
  121.     CircleFill paddleX + paddleWidth - paddleHeight / 2, paddleY + paddleHeight / 2, paddleHeight / 2, _RGB32(194, 89, 61)
  122.     IF _MOUSEBUTTON(1) OR _KEYDOWN(13) THEN ball.state = true
  123.  
  124. SUB doBall
  125.     IF ball.state = false THEN
  126.         ball.x = paddleX + paddleWidth / 2
  127.         ball.y = paddleY - (ball.radius)
  128.     ELSE
  129.         ball.x = ball.x + ball.xDir * ball.xVel
  130.         ball.y = ball.y + ball.yDir * ball.yVel
  131.  
  132.         checkCollision
  133.     END IF
  134.     CircleFill ball.x, ball.y, ball.radius, ball.c
  135.  
  136. SUB checkCollision
  137.     'paddle
  138.     IF ball.x > paddleX AND ball.x < paddleX + paddleWidth AND ball.y > paddleY AND ball.y < paddleY + paddleHeight THEN
  139.         IF ball.x < paddleX + paddleWidth / 2 THEN
  140.             ball.xDir = -1
  141.             ball.xVel = map(ball.x, paddleX, paddleX + paddleWidth / 3, 6, 3)
  142.         ELSE
  143.             ball.xDir = 1
  144.             ball.xVel = map(ball.x, paddleX + paddleWidth / 3, paddleX + paddleWidth, 3, 6)
  145.         END IF
  146.         IF ball.xVel < 3 THEN ball.xVel = 3
  147.  
  148.         IF ball.yDir = 1 AND ball.y < paddleY + paddleHeight / 2 THEN ball.yDir = -1
  149.         EXIT SUB
  150.     END IF
  151.  
  152.     'blocks
  153.     FOR i = 1 TO 80
  154.         IF block(i).state = false THEN _CONTINUE
  155.         IF ball.x > block(i).x AND ball.x < block(i).x + blockWidth AND ball.y > block(i).y AND ball.y < block(i).y + blockHeight THEN
  156.             block(i).state = false
  157.             IF ball.x < block(i).x + blockWidth / 2 THEN ball.xDir = -1 ELSE ball.xDir = 1
  158.             IF ball.y < block(i).y + blockHeight / 2 THEN ball.yDir = -1 ELSE ball.yDir = 1
  159.             points = ((_RED32(block(i).c) + _GREEN32(block(i).c) + _BLUE32(block(i).c)) / 3) / 10
  160.             score = score + points
  161.             EXIT SUB
  162.         END IF
  163.     NEXT
  164.  
  165.     'walls
  166.     IF ball.x < ball.radius THEN ball.xDir = 1
  167.     IF ball.x > _WIDTH - ball.radius THEN ball.xDir = -1
  168.     IF ball.y > _HEIGHT + ball.radius THEN
  169.         lives = lives - 1
  170.         ball.state = false
  171.         ball.xDir = 1
  172.         ball.yDir = -1
  173.         ball.xVel = 3
  174.         ball.yVel = 3
  175.     END IF
  176.     IF ball.y < 0 THEN ball.yDir = 1
  177.  
  178. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  179.     ' CX = center x coordinate
  180.     ' CY = center y coordinate
  181.     '  R = radius
  182.     '  C = fill color
  183.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  184.     DIM X AS INTEGER, Y AS INTEGER
  185.     Radius = ABS(R)
  186.     RadiusError = -Radius
  187.     X = Radius
  188.     Y = 0
  189.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  190.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  191.     WHILE X > Y
  192.         RadiusError = RadiusError + Y * 2 + 1
  193.         IF RadiusError >= 0 THEN
  194.             IF X <> Y + 1 THEN
  195.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  196.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  197.             END IF
  198.             X = X - 1
  199.             RadiusError = RadiusError - X * 2
  200.         END IF
  201.         Y = Y + 1
  202.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  203.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  204.     WEND
  205.  
  206. FUNCTION map! (value!, minRange!, maxRange!, newMinRange!, newMaxRange!)
  207.     map! = ((value! - minRange!) / (maxRange! - minRange!)) * (newMaxRange! - newMinRange!) + newMinRange!
  208.  

2019-03-25 00_49_38-Breakout.png
« Last Edit: March 25, 2019, 12:18:30 am by FellippeHeitor »

Offline qb4ever

  • Newbie
  • Posts: 40
  • LOCATE 15,15: COLOR 14: PRINT "Hello World!"
    • View Profile
Re: Breakout
« Reply #1 on: March 25, 2019, 05:44:35 am »
Great job !
Probably, the best basic breakout ever.
Have a nice day.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Breakout
« Reply #2 on: March 25, 2019, 11:46:26 am »
Very interesting variations from what I have played and coded.

Usually there is a solid wall of blocks with each layer up a color with a point value.
Here the block state is assigned by RND, 0 or 1 (present or not), I've not seen that before.

The ball approaches paddle at same basic angle but velocity depends on where ball hits paddle.
I wonder if there are blocks unreachable because the angle is so restricted?

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Breakout
« Reply #3 on: March 25, 2019, 07:17:13 pm »
Nice job. You can never go wrong with a nice breakout game. Well done.
Logic is the beginning of wisdom.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Breakout
« Reply #4 on: March 25, 2019, 11:02:39 pm »
Found my old SdlBasic program and translated it to QB64. Here it is, might be fun to compare. All mouse!
Code: QB64: [Select]
  1. _TITLE "Breakout trans from SdlBasic" 'B+ tranlate 2019-03-25
  2. 'Breakout.sdlbas  (B+=MGA) 2016-12-24
  3. 'adapted from just posted JB version add 3d modifications
  4.  
  5.  
  6. CONST xmax = 700 '<==== drawing area width
  7. CONST ymax = 560 '<==== drawing area height
  8. SCREEN _NEWIMAGE(xmax, ymax, 32)
  9.  
  10. '              Recommend: If you go FULLSCREEN then MOUSEHIDE
  11. '      You might want to keep mouse visible to see when it goes off screen in height
  12.  
  13. ' wall is 50 pixels X 14 columns wide = 700 make screen width
  14. ' wall is 20 pixels X 8  rows = 160 = 1/3 screen height = 480 + 20  paddle height
  15. ' under paddle track score and lifes on one line padded by blank lines 540 = 27
  16. ' so total height 480 to paddle 500 + 60 for 3 lines = 560 (text height 20)
  17.  
  18. CONST br = 10 ' ball radius
  19. CONST bkw = 50 ' brick width
  20. CONST bkh = 20 ' brick height
  21. CONST py = 480 ' paddle surface
  22.  
  23. 'colors used
  24. CONST red = &HFFFF0000
  25. CONST orange = &HFFFF6400
  26. CONST green = &HFF008000
  27. CONST yellow = &HFFFFFF00
  28. CONST silver = &HFFD0C6C6
  29. CONST white = &HFFFFFFFF
  30. CONST black = &HFF000000
  31.  
  32. DIM SHARED bx, by, dx, dy, px, my, pw, plf, prt, score, life, hits, obk, rbk, speedups
  33. bx = 0 ' ball x position
  34. by = 0 ' ball y position
  35. dx = 0 ' ball horizontal change
  36. dy = 0 ' ball vertical change
  37.  
  38. px = 0 ' paddle x
  39. pw = 50 ' paddle width,  100 wide to start half that at certain point
  40. plf = 0 ' paddle left side
  41. prt = 0 ' paddle right side
  42.  
  43. score = 0
  44. life = 5 '  (or balls left) only 3 allowed according to wiki
  45. hits = 0 'bricks busted
  46. obk = 0 ' first orange brick hits bool
  47. rbk = 0 ' first red brick hit bool, when this happens paddle width is cut in half!
  48. speedups = 0 ' count, bump up dy when hits = 4 and 8, then with first orange, then with first red
  49. scrn = 0
  50.  
  51. DIM SHARED wc(13, 7), wp(13, 7) 'brick wall colors, brick wall points according to color
  52. ' get 448 points clear 1 screen/wall, perfect game is clearing 2 screens/walls
  53.  
  54. initwall 'load arrays with data
  55. initball 'set dx, dy, bx, by ball position and change
  56. drawtable
  57. updatescore
  58. WHILE life AND _KEYDOWN(27) = 0
  59.     drawtable
  60.     drawpaddle
  61.     drawball
  62.     updatescore
  63.     IF hits = 112 AND scrn = 0 THEN 'setup new
  64.         _DELAY 1
  65.         scrn = 1
  66.         speedups = 0: obk = 0: rbk = 0: pw = 50
  67.         initwall
  68.         drawtable
  69.         initball
  70.     ELSE
  71.         IF hits = 224 THEN
  72.             COLOR white
  73.             Text 65, 200, 32, orange, "Congratulations on a perfect score!!!"
  74.             EXIT WHILE
  75.         END IF
  76.     END IF
  77.     _DISPLAY
  78.     _LIMIT 60 '< adjust as needed for speed of your system
  79. COLOR white
  80. Text 260, 290, 48, orange, "Game Over"
  81.  
  82. SUB initwall
  83.     DIM cr AS _UNSIGNED LONG
  84.     FOR r = 0 TO 7
  85.         SELECT CASE r
  86.             CASE 0, 1: cr = red: p = 7
  87.             CASE 2, 3: cr = orange: p = 5
  88.             CASE 4, 5: cr = green: p = 3
  89.             CASE 6, 7: cr = yellow: p = 1
  90.         END SELECT
  91.         FOR c = 0 TO 13
  92.             wc(c, r) = cr: wp(c, r) = p
  93.         NEXT
  94.     NEXT
  95.  
  96. SUB initball 'set ball in play with location and dx, dy
  97.     bx = rand(br, 700 - br)
  98.     by = rand(py - 100, py - 10)
  99.     dx = rand(3, 7)
  100.     IF rand(0, 1) THEN dx = -1 * dx
  101.     dy = (3 + speedups) * -1
  102.  
  103. SUB drawtable ' in JB don't want to redraw this every loop
  104.     CLS
  105.     FOR r = 0 TO 7
  106.         FOR c = 0 TO 13
  107.             IF wp(c, r) THEN
  108.                 FOR i = 1 TO 10
  109.                     COLOR _RGB32(120, 60, 60)
  110.                     LINE (c * bkw + i, r * bkh + bkh + i)-(c * bkw + bkw + i, r * bkh + bkh + i)
  111.                     COLOR silver
  112.                     PSET (c * bkw + i, r * bkh + bkh + i)
  113.                     'ink(white)
  114.                     LINE (c * bkw + bkw + i, r * bkh + i)-(c * bkw + bkw + i, r * bkh + bkh + i)
  115.                 NEXT
  116.                 COLOR wc(c, r)
  117.                 LINE (c * bkw, r * bkh)-(c * bkw + bkw, r * bkh + bkh), , BF
  118.                 COLOR white
  119.                 LINE (c * bkw, r * bkh)-(c * bkw + bkw, r * bkh + bkh), , B
  120.             END IF
  121.         NEXT
  122.     NEXT
  123.  
  124. SUB drawpaddle ' update paddle to mouseY, paddle top and bottom are global
  125.     'erase last paddle, it is aligned with Blue Computer Goal Line
  126.     COLOR black
  127.     EllipseFill px, py + 10, pw, 20, black
  128.     px = _MOUSEX 'update paddle location
  129.     my = _MOUSEY
  130.     plf = px - pw
  131.     prt = px + pw
  132.     FOR i = 20 TO 1 STEP -1
  133.         cc = 255 - i * 10
  134.         EllipseFill px, py + 10, pw - (20 - i), i, _RGB32(cc, .5 * cc, .25 * cc)
  135.     NEXT
  136.  
  137. SUB drawball
  138.     'erase last ball, blend into table color
  139.     CircleFill bx, by, br, black
  140.  
  141.     'update
  142.     bx = bx + dx
  143.     IF bx < br THEN dx = dx * -1: bx = br + 1
  144.     IF bx > xmax - br THEN dx = dx * -1: bx = xmax - br - 1
  145.  
  146.     by = by + dy
  147.     IF by + br > py THEN 'ball past paddle line
  148.         by = py - br 'don't let ball go into paddle or goal
  149.         IF bx + br < plf OR bx - br > prt THEN 'paddle miss
  150.             life = life - 1
  151.             ' if life = 0 then end game
  152.             updatescore
  153.             silverball bx, by
  154.             _DELAY 2.5 'reflect on position of ball and loss of life
  155.             CircleFill bx, by, br, black
  156.             initball 'get ball rolling again
  157.         ELSE 'paddle hit
  158.             dy = dy * -1
  159.             dx = dx + rand(-2, 2)
  160.             IF dx > 7 THEN: dx = 7:
  161.             IF dx < -7 THEN dx = -7
  162.         END IF
  163.     ELSE
  164.         IF by - br < 0 THEN 'ball hits back border, reverse direction
  165.             by = br: dy = dy * -1
  166.         ELSE
  167.             IF by - br < 160 THEN 'in wall area, what row and column?
  168.                 starthits = hits
  169.                 'maybe should check all 4 corners or smaller ball
  170.                 row = INT((by - br) / bkh): col = INT((bx - br) / bkw)
  171.                 handleBall row, col
  172.                 row = INT((by - br) / bkh): col = INT((bx + br) / bkw)
  173.                 handleBall row, col
  174.                 row = INT((by + br) / bkh): col = INT((bx - br) / bkw)
  175.                 handleBall row, col
  176.                 row = INT((by + br) / bkh): col = INT((bx + br) / bkw)
  177.                 handleBall row, col
  178.                 IF hits <> starthits THEN: dy = dy * -1: 'reverse ball direction
  179.             END IF
  180.         END IF
  181.     END IF
  182.     silverball bx, by
  183.  
  184. SUB handleBall (row, col)
  185.     IF 0 <= row AND row <= 7 AND 0 <= col AND col <= 13 THEN
  186.         IF wp(col, row) THEN 'brick just hit, lot's to do before update ball
  187.             hits = hits + 1
  188.             IF hits = 4 OR hits = 8 OR hits = 116 OR hits = 120 THEN
  189.                 speedups = speedups + 1
  190.                 IF dy < 0 THEN: dy = dy - 1: ELSE: dy = dy + 1:
  191.             END IF
  192.             value = wp(col, row)
  193.             IF value = 5 THEN 'first orange brick
  194.                 IF obk = 0 THEN 'flag first orange speed increase
  195.                     obk = 1
  196.                     speedups = speedups + 1
  197.                     IF dy < 0 THEN: dy = dy - 1: ELSE: dy = dy + 1:
  198.                 END IF
  199.             END IF
  200.             IF value = 7 THEN 'flag first red, speed increase paddle decrease!
  201.                 IF rbk = 0 THEN
  202.                     rbk = 1
  203.                     speedups = speedups + 1
  204.                     IF dy < 0 THEN: dy = dy - 1: ELSE: dy = dy + 1:
  205.                     ' erase last paddle before change width
  206.                     EllipseFill px, py + 10, pw, 20, black
  207.                     pw = pw / 2
  208.                 END IF
  209.             END IF
  210.             score = score + wp(col, row) 'update score with point value
  211.             wp(col, row) = 0 'no points here now
  212.             'black out box
  213.             LINE (col * bkw, row * bkh)-(col * bkw + bkw, row * bkh + bkh), black, BF
  214.         END IF
  215.     END IF
  216.  
  217. SUB updatescore
  218.     LINE (0, 500)-(xmax, ymax), black, BF
  219.     dys$ = RIGHT$("    " + STR$(my), 4)
  220.     dxs$ = RIGHT$("    " + STR$(px), 4)
  221.     scores$ = RIGHT$("   " + STR$(score), 3)
  222.     ms$ = " Mouse:" + dxs$ + "," + dys$ + "   Lifes:" + STR$(life) + "     Score:" + scores$
  223.     Text 0, 520, 32, silver, ms$
  224.  
  225. SUB silverball (x, y)
  226.     FOR i = 10 TO 1 STEP -1
  227.         cc = 255 - i * 20
  228.         CircleFill x, y, i, _RGB32(cc, cc, cc)
  229.     NEXT
  230.  
  231. FUNCTION rand% (lo%, hi%)
  232.     rand% = INT(RND * (hi% - lo% + 1)) + lo%
  233.  
  234. SUB EllipseFill (CX AS INTEGER, CY AS INTEGER, a AS INTEGER, b AS INTEGER, C AS _UNSIGNED LONG)
  235.     ' CX = center x coordinate
  236.     ' CY = center y coordinate
  237.     '  a = semimajor axis
  238.     '  b = semiminor axis
  239.     '  C = fill color
  240.     IF a = 0 OR b = 0 THEN EXIT SUB
  241.     DIM h2 AS _INTEGER64
  242.     DIM w2 AS _INTEGER64
  243.     DIM h2w2 AS _INTEGER64
  244.     DIM x AS INTEGER
  245.     DIM y AS INTEGER
  246.     w2 = a * a
  247.     h2 = b * b
  248.     h2w2 = h2 * w2
  249.     LINE (CX - a, CY)-(CX + a, CY), C, BF
  250.     DO WHILE y < b
  251.         y = y + 1
  252.         x = SQR((h2w2 - y * y * w2) \ h2)
  253.         LINE (CX - x, CY + y)-(CX + x, CY + y), C, BF
  254.         LINE (CX - x, CY - y)-(CX + x, CY - y), C, BF
  255.     LOOP
  256.  
  257. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  258.     ' CX = center x coordinate
  259.     ' CY = center y coordinate
  260.     '  R = radius
  261.     '  C = fill color
  262.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  263.     DIM X AS INTEGER, Y AS INTEGER
  264.     Radius = ABS(R)
  265.     RadiusError = -Radius
  266.     X = Radius
  267.     Y = 0
  268.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  269.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  270.     WHILE X > Y
  271.         RadiusError = RadiusError + Y * 2 + 1
  272.         IF RadiusError >= 0 THEN
  273.             IF X <> Y + 1 THEN
  274.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  275.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  276.             END IF
  277.             X = X - 1
  278.             RadiusError = RadiusError - X * 2
  279.         END IF
  280.         Y = Y + 1
  281.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  282.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  283.     WEND
  284.  
  285. SUB Text (x, y, textHeight, K AS _UNSIGNED LONG, txt$)
  286.     fg = _DEFAULTCOLOR
  287.     cur& = _DEST
  288.     I& = _NEWIMAGE(8 * LEN(txt$), 16, 32)
  289.     _DEST I&
  290.     COLOR K, _RGBA32(0, 0, 0, 0)
  291.     _PRINTSTRING (0, 0), txt$
  292.     mult = textHeight / 16
  293.     xlen = LEN(txt$) * 8 * mult
  294.     _PUTIMAGE (x, y)-STEP(xlen, textHeight), I&, cur&
  295.     COLOR fg
  296.     _FREEIMAGE I&
  297.  
  298.  
  299.  

SldBasic had a nice sub for displaying text at a given pixel height. I think I will try to duplicate, Rotozoom is overkill.

EDIT: I have updated this code with a sim of SdlBasic's Text(x, y, height, text$) subroutine to get text at different sizes (and now color parameter.)
« Last Edit: March 26, 2019, 10:01:22 am by bplus »

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Breakout
« Reply #5 on: March 26, 2019, 01:23:28 am »
Nice conversion. I thought it was quite sneaky how, after I accumulated about 200 points, the bat (which looks like a long loaf of bread) turned into a hamburger bun... Cool
Logic is the beginning of wisdom.

FellippeHeitor

  • Guest
Re: Breakout
« Reply #6 on: March 26, 2019, 09:34:03 am »
Cool, version bplus, thanks for sharing! Love the 3d blocks too!

@johnno56 it does indeed look like a loaf of bread :-)

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Breakout
« Reply #7 on: March 26, 2019, 10:12:15 am »
:D yep! Loaf of bread and hamburger bun! Ha! that paddle ain't half what it used to be when you hit the first red brick!
But I like how silver ball sinks into the bread a little before bouncing back out.

I have updated the code with a sim of SdlBasic's Text() routine that allows text to be sized. This is actually the toolbox routine I wanted to make before I got Rotozoom involved for rotations.

And instead of tracking dx, dy of ball, it tracks mouse position.
I have noticed when I play the game, that I am constantly moving the mouse outside the screen boundary getting the paddle stuck, so maybe by tracking mouse / paddle x, y on score board, will help warn the player.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Breakout
« Reply #8 on: March 26, 2019, 10:40:19 am »
Oh, I have to say, Fellippes random fill of blocks makes for a much more entertaining knock out of the remaining bricks!

It would be nice to have that aspect and still keep games fair for scoring between players which I think the original game was doing. I thought the game needed more paddle control so players could have a chance to direct where the ball goes after contact with paddle.

FellippeHeitor

  • Guest
Re: Breakout
« Reply #9 on: March 26, 2019, 10:46:21 am »
Since I can't stop tweaking this, here's the latest iteration of my breakout clone (I'm calling it Blockout for now):

- I've built in a particle system which allows for some cool visual additions.
- Three types of blocks: regular, hit twice and unbreakable.
- Power-ups: you get a Fireball (allows destroying "hit twice" blocks at once), Shooter, Magnetic paddle, Breakthrough, Stretch Paddle.
- Power-ups show up when you destroy certain blocks. You must catch them to activate them.

Code: QB64: [Select]
  1. CONST true = -1, false = 0
  2.  
  3.  
  4. DIM gameArea AS LONG
  5. gameArea = _NEWIMAGE(400, 500, 32)
  6. SCREEN gameArea
  7. _TITLE "Blockout"
  8.  
  9. TYPE Block
  10.     x AS INTEGER
  11.     y AS INTEGER
  12.     c AS _UNSIGNED LONG
  13.     state AS _BYTE
  14.     special AS _BYTE
  15.     kind AS _BYTE
  16.  
  17. TYPE Ball
  18.     x AS SINGLE
  19.     y AS SINGLE
  20.     c AS _UNSIGNED LONG
  21.     radius AS INTEGER
  22.     state AS _BYTE
  23.     xDir AS _BYTE
  24.     yDir AS _BYTE
  25.     xVel AS SINGLE
  26.     yVel AS SINGLE
  27.  
  28. TYPE Particle
  29.     x AS SINGLE
  30.     y AS SINGLE
  31.     xAcc AS SINGLE
  32.     yAcc AS SINGLE
  33.     xVel AS SINGLE
  34.     yVel AS SINGLE
  35.     state AS _BYTE
  36.     size AS INTEGER
  37.     lifeSpan AS SINGLE
  38.     birth AS SINGLE
  39.     special AS _BYTE
  40.     kind AS _BYTE
  41.  
  42. TYPE Special
  43.     start AS SINGLE
  44.     span AS INTEGER
  45.  
  46. CONST gravity = .03
  47.  
  48. CONST blockWidth = 50
  49. CONST blockHeight = 25
  50. CONST paddleHeight = 10
  51.  
  52. CONST round = 0
  53. CONST square = 1
  54. CONST specialPower = 2
  55.  
  56. CONST left = -1
  57. CONST right = 1
  58. CONST up = -1
  59. CONST down = 1
  60.  
  61. CONST regular = 0
  62. CONST hitTwice = 1
  63. CONST unbreakable = 2
  64.  
  65. CONST bullet = 1
  66.  
  67. DIM SHARED block(1 TO 80) AS Block, ball AS Ball
  68. DIM SHARED particle(1 TO 10000) AS Particle
  69. DIM SHARED win AS _BYTE, quit AS STRING * 1
  70. DIM SHARED paddleX AS INTEGER, paddleY AS INTEGER
  71. DIM SHARED paddleWidth AS SINGLE, magneticOffset AS INTEGER
  72. DIM SHARED score AS INTEGER, lives AS INTEGER
  73. DIM SHARED paused AS _BYTE, stillImage&
  74.  
  75. DIM SHARED electricColor(1 TO 2) AS _UNSIGNED LONG
  76. electricColor(1) = _RGB32(255)
  77. electricColor(2) = _RGB32(50, 211, 255)
  78.  
  79. CONST FireBall = 1
  80. CONST Shooter = 2
  81. CONST BreakThrough = 3
  82. CONST Magnetic = 4
  83. CONST StretchPaddle = 5
  84. CONST StretchPaddle2 = 6
  85. CONST totalSpecialPowers = 6
  86.  
  87. DIM SHARED special(1 TO totalSpecialPowers) AS Special
  88.  
  89. FOR i = 1 TO totalSpecialPowers
  90.     special(i).span = 15
  91.  
  92. CONST defaultPaddleWidth = 100
  93.  
  94. paddleY = _HEIGHT - blockHeight - paddleHeight - 1
  95.  
  96.     IF lives = 0 THEN score = 0: lives = 3
  97.     win = false
  98.     paused = false
  99.     generateBlocks
  100.     paddleWidth = defaultPaddleWidth
  101.     ball.state = false
  102.     ball.c = _RGB32(161, 161, 155)
  103.     ball.radius = 5
  104.     ball.xDir = right
  105.     ball.yDir = up
  106.     ball.xVel = 3
  107.     ball.yVel = 3
  108.     FOR i = 1 TO totalSpecialPowers
  109.         special(i).start = 0
  110.     NEXT
  111.     magneticOffset = paddleWidth / 2
  112.  
  113.     FOR i = 1 TO UBOUND(particle)
  114.         resetParticle particle(i)
  115.     NEXT
  116.  
  117.  
  118.     DO
  119.         k& = _KEYHIT
  120.         'IF k& = ASC("s") THEN special(Shooter).start = TIMER
  121.         'IF k& = ASC("m") THEN special(Magnetic).start = TIMER
  122.         'IF k& = ASC("b") THEN special(BreakThrough).start = TIMER
  123.         'IF k& = ASC("f") THEN special(FireBall).start = TIMER
  124.         'IF k& = ASC("p") THEN special(StretchPaddle).start = TIMER
  125.         'IF k& = ASC("P") THEN special(StretchPaddle2).start = TIMER
  126.         'IF k& = ASC("r") THEN EXIT DO
  127.  
  128.         noFocus%% = lostFocus
  129.         IF (paused = true AND k& = 13) OR k& = 27 OR noFocus%% THEN
  130.             IF paused THEN
  131.                 _FREEIMAGE stillImage&
  132.                 paused = false
  133.                 showFullScreenMessage%% = false
  134.                 pauseDiff = TIMER - pauseStart
  135.                 FOR i = 1 TO totalSpecialPowers
  136.                     IF special(i).start > 0 THEN
  137.                         special(i).start = special(i).start + pauseDiff
  138.                     END IF
  139.                 NEXT
  140.                 FOR i = 1 TO UBOUND(particle)
  141.                     IF particle(i).birth > 0 THEN
  142.                         particle(i).birth = particle(i).birth + pauseDiff
  143.                     END IF
  144.                 NEXT
  145.             ELSE
  146.                 paused = true
  147.                 IF noFocus%% THEN showFullScreenMessage%% = true
  148.                 pauseStart = TIMER
  149.                 stillImage& = _COPYIMAGE(0)
  150.             END IF
  151.         END IF
  152.  
  153.         IF paused THEN
  154.             _PUTIMAGE , stillImage&
  155.             m$ = "Paused (ENTER to continue)"
  156.             COLOR _RGB32(0)
  157.             _PRINTSTRING ((_WIDTH - _PRINTWIDTH(m$)) / 2 + 1, (_HEIGHT - _FONTHEIGHT) / 2 + 1 + _FONTHEIGHT), m$
  158.             COLOR _RGB32(255)
  159.             _PRINTSTRING ((_WIDTH - _PRINTWIDTH(m$)) / 2, (_HEIGHT - _FONTHEIGHT) / 2 + _FONTHEIGHT), m$
  160.  
  161.             IF showFullScreenMessage%% THEN
  162.                 m$ = "(Hit Alt+Enter to switch to fullscreen)"
  163.                 COLOR _RGB32(0)
  164.                 _PRINTSTRING ((_WIDTH - _PRINTWIDTH(m$)) / 2 + 1, (_HEIGHT - _FONTHEIGHT) / 2 + 1 + _FONTHEIGHT * 2), m$
  165.                 COLOR _RGB32(255)
  166.                 _PRINTSTRING ((_WIDTH - _PRINTWIDTH(m$)) / 2, (_HEIGHT - _FONTHEIGHT) / 2 + _FONTHEIGHT * 2), m$
  167.             END IF
  168.         ELSE
  169.             IF TIMER - special(BreakThrough).start < special(BreakThrough).span THEN
  170.                 alpha = map(ball.xVel, 3, 6, 80, 30)
  171.             ELSE
  172.                 alpha = 255
  173.             END IF
  174.             LINE (0, 0)-(_WIDTH, _HEIGHT), _RGBA32(0, 0, 0, alpha), BF
  175.  
  176.             showBlocks
  177.             doPaddle
  178.             doBall
  179.             doParticles
  180.  
  181.             m$ = "Score:" + STR$(score) + " Lives:" + STR$(lives)
  182.             COLOR _RGB32(0)
  183.             _PRINTSTRING (1, 1), m$
  184.             COLOR _RGB32(255)
  185.             _PRINTSTRING (0, 0), m$
  186.  
  187.             'IF TIMER - special(FireBall).start < special(FireBall).span THEN
  188.             '    _PRINTSTRING (0, 350), "fireball: " + STR$(INT(TIMER - special(FireBall).start))
  189.             'END IF
  190.  
  191.             'IF TIMER - special(BreakThrough).start < special(BreakThrough).span THEN
  192.             '    _PRINTSTRING (0, 370), "breakthrough: " + STR$(INT(TIMER - special(BreakThrough).start))
  193.             'END IF
  194.  
  195.             'IF TIMER - special(Shooter).start < special(Shooter).span THEN
  196.             '    _PRINTSTRING (0, 388), "shooter: " + STR$(INT(TIMER - special(Shooter).start))
  197.             'END IF
  198.  
  199.             'IF TIMER - special(Magnetic).start < special(Magnetic).span THEN
  200.             '    _PRINTSTRING (0, 406), "magnetic: " + STR$(INT(TIMER - special(Magnetic).start))
  201.             'END IF
  202.  
  203.             IF TIMER - special(StretchPaddle).start < special(StretchPaddle).span THEN
  204.                 '_PRINTSTRING (0, 422), "stretch: " + STR$(INT(TIMER - special(StretchPaddle).start))
  205.                 paddleWidth = defaultPaddleWidth * 1.5
  206.             ELSE
  207.                 paddleWidth = defaultPaddleWidth
  208.             END IF
  209.  
  210.             IF TIMER - special(StretchPaddle2).start < special(StretchPaddle2).span THEN
  211.                 '_PRINTSTRING (0, 438), "stretch2: " + STR$(INT(TIMER - special(StretchPaddle2).start))
  212.                 paddleWidth = defaultPaddleWidth * 2
  213.             ELSE
  214.                 IF TIMER - special(StretchPaddle).start > special(StretchPaddle).span OR special(StretchPaddle).start = 0 THEN
  215.                     paddleWidth = defaultPaddleWidth
  216.                 END IF
  217.             END IF
  218.  
  219.         END IF
  220.  
  221.         _DISPLAY
  222.         _LIMIT 60
  223.     LOOP UNTIL win OR lives = 0
  224.  
  225.  
  226.     CLS
  227.     IF win THEN
  228.         PRINT "Good job, you win."
  229.         PRINT "Continue (y/n)?"
  230.     ELSE
  231.         PRINT "You lose."
  232.         PRINT "Restart (y/n)?"
  233.     END IF
  234.  
  235.     _KEYCLEAR
  236.  
  237.     DO
  238.         quit = LCASE$(INPUT$(1))
  239.     LOOP UNTIL quit = "y" OR quit = "n"
  240.  
  241. LOOP WHILE quit = "y"
  242.  
  243.  
  244. FUNCTION lostFocus%%
  245.     STATIC Focused AS _BYTE
  246.  
  247.     IF _WINDOWHASFOCUS = false THEN
  248.         IF Focused THEN
  249.             Focused = false
  250.             lostFocus%% = true
  251.         END IF
  252.     ELSE
  253.         Focused = true
  254.     END IF
  255.  
  256. SUB doParticles
  257.     DIM thisColor AS _UNSIGNED LONG, alpha AS _UNSIGNED _BYTE
  258.  
  259.     FOR i = 1 TO UBOUND(particle)
  260.         IF particle(i).state = false THEN _CONTINUE
  261.         IF particle(i).lifeSpan > 0 AND TIMER - particle(i).birth > particle(i).lifeSpan THEN particle(i).state = false: _CONTINUE
  262.  
  263.         'move
  264.         particle(i).xVel = particle(i).xVel + particle(i).xAcc
  265.         particle(i).yVel = particle(i).yVel + particle(i).yAcc + gravity
  266.         particle(i).x = particle(i).x + particle(i).xVel
  267.         particle(i).y = particle(i).y + particle(i).yVel
  268.  
  269.         IF particle(i).kind = bullet THEN
  270.             l = newParticle
  271.             IF l THEN
  272.                 particle(l).r = 222 + (RND * 30)
  273.                 particle(l).g = 100 + (RND * 70)
  274.                 particle(l).x = particle(i).x
  275.                 particle(l).y = particle(i).y
  276.                 particle(l).lifeSpan = 0.05
  277.             END IF
  278.         END IF
  279.  
  280.         'check visibility
  281.         IF particle(i).x - particle(i).size / 2 < 0 OR particle(i).x + particle(i).size / 2 > _WIDTH OR particle(i).y - particle(i).size / 2 < 0 OR particle(i).y + particle(i).size / 2 > _HEIGHT THEN
  282.             particle(i).state = false
  283.             _CONTINUE
  284.         END IF
  285.  
  286.         'show
  287.         IF particle(i).lifeSpan > 0 THEN
  288.             alpha = map(TIMER - particle(i).birth, 0, particle(i).lifeSpan, 255, 0)
  289.         ELSE
  290.             alpha = 255
  291.         END IF
  292.  
  293.         thisColor = _RGBA32(particle(i).r, particle(i).g, particle(i).b, alpha)
  294.  
  295.         IF particle(i).size > 0 THEN
  296.             SELECT CASE particle(i).kind
  297.                 CASE round, bullet
  298.                     CircleFill particle(i).x, particle(i).y, particle(i).size, thisColor
  299.                 CASE square
  300.                     LINE (particle(i).x - size / 2, particle(i).y - size / 2)-STEP(particle(i).size, particle(i).size), thisColor, BF
  301.                 CASE specialPower
  302.                     SELECT CASE particle(i).special
  303.                         'CONST FireBall = 1
  304.                         'CONST Shooter = 2
  305.                         'CONST BreakThrough = 3
  306.                         'CONST Magnetic = 4
  307.                         'CONST StretchPaddle = 5
  308.                         'CONST StretchPaddle2 = 6
  309.                         CASE FireBall
  310.                             FOR j = 1 TO 10
  311.                                 l = newParticle
  312.                                 IF l = 0 THEN EXIT FOR
  313.                                 particle(l).r = 222 + (RND * 30)
  314.                                 particle(l).g = 100 + (RND * 70)
  315.                                 particle(l).x = particle(i).x + COS(RND * _PI(2)) * (ball.radius * RND)
  316.                                 particle(l).y = particle(i).y + SIN(RND * _PI(2)) * (ball.radius * RND)
  317.                                 particle(l).lifeSpan = .1
  318.                             NEXT
  319.                             CircleFill particle(i).x, particle(i).y, particle(i).size, _RGBA32(222 + (RND * 30), 100 + (RND * 70), 0, RND * 255)
  320.                             specialDrawn = true
  321.                         CASE Shooter
  322.                             LINE (particle(i).x - 7, particle(i).y + 1)-STEP(15, 8), _RGB32(89, 161, 255), BF
  323.                             CircleFill particle(i).x - 7, particle(i).y + 5, 4, _RGB32(194, 89, 61)
  324.                             CircleFill particle(i).x - 7, particle(i).y + 2, 3, _RGB32(194, 133, 61)
  325.                             CircleFill particle(i).x - 7, particle(i).y, 3, _RGB32(194, 188, 61)
  326.  
  327.                             l = newParticle
  328.                             IF l > 0 THEN
  329.                                 particle(l).r = 222 + (RND * 30)
  330.                                 particle(l).g = 100 + (RND * 70)
  331.                                 particle(l).x = particle(i).x - 7
  332.                                 particle(l).y = particle(i).y
  333.                                 particle(l).lifeSpan = .1
  334.                             END IF
  335.  
  336.                             specialDrawn = true
  337.                         CASE BreakThrough
  338.                             CircleFill particle(i).x - 8, particle(i).y + 8, 3, _RGB32(177, 30)
  339.                             CircleFill particle(i).x - 6, particle(i).y + 6, 3, _RGB32(177, 50)
  340.                             CircleFill particle(i).x - 3, particle(i).y + 3, 4, _RGB32(177, 100)
  341.                             CircleFill particle(i).x, particle(i).y, 4, _RGB32(177, 200)
  342.                             specialDrawn = true
  343.                         CASE Magnetic
  344.                             FOR j = 1 TO 2
  345.                                 PSET (particle(i).x + COS(0) * (particle(i).size + particle(i).size * RND), particle(i).y + SIN(0) * (particle(i).size + particle(i).size * RND)), electricColor(j)
  346.                                 FOR k = 0 TO _PI(2) STEP .2
  347.                                     LINE -(particle(i).x + COS(k) * (particle(i).size + particle(i).size * RND), particle(i).y + SIN(k) * (particle(i).size + particle(i).size * RND)), electricColor(j)
  348.                                 NEXT
  349.                                 LINE -(particle(i).x + COS(0) * (particle(i).size + particle(i).size * RND), particle(i).y + SIN(0) * (particle(i).size + particle(i).size * RND)), electricColor(j)
  350.                             NEXT
  351.                             specialDrawn = true
  352.                         CASE StretchPaddle
  353.                             LINE (particle(i).x - 7, particle(i).y + 1)-STEP(15, 8), _RGB32(89, 161, 255), BF
  354.                             CircleFill particle(i).x - 7, particle(i).y + 5, 4, _RGB32(194, 89, 61)
  355.                             _FONT 8
  356.                             COLOR _RGB32(255, 150)
  357.                             _PRINTSTRING (particle(i).x - 16, particle(i).y - 10), "1.5x"
  358.                             _FONT 16
  359.                             specialDrawn = true
  360.                         CASE StretchPaddle2
  361.                             LINE (particle(i).x - 3, particle(i).y + 1)-STEP(15, 8), _RGB32(89, 161, 255), BF
  362.                             CircleFill particle(i).x - 3, particle(i).y + 5, 4, _RGB32(194, 89, 61)
  363.                             _FONT 8
  364.                             COLOR _RGB32(255, 150)
  365.                             _PRINTSTRING (particle(i).x + 8, particle(i).y - 10), "2x"
  366.                             _FONT 16
  367.                             specialDrawn = true
  368.                     END SELECT
  369.             END SELECT
  370.         ELSE
  371.             PSET (particle(i).x, particle(i).y), thisColor
  372.         END IF
  373.  
  374.         'check collision with paddle if this particle contains a special power
  375.         IF particle(i).special THEN
  376.             'IF specialDrawn = false THEN
  377.             '    m$ = LTRIM$(STR$(particle(i).special))
  378.             '    COLOR _RGB32(0)
  379.             '    _PRINTSTRING (particle(i).x + 1, particle(i).y + 1), m$
  380.             '    COLOR _RGB32(255)
  381.             '    _PRINTSTRING (particle(i).x, particle(i).y), m$
  382.             'END IF
  383.             IF particle(i).x - particle(i).size / 2 > paddleX AND particle(i).x + particle(i).size / 2 < paddleX + paddleWidth AND particle(i).y + particle(i).size / 2 >= paddleY THEN
  384.                 particle(i).state = false
  385.                 special(particle(i).special).start = TIMER
  386.             END IF
  387.         END IF
  388.  
  389.         'check collision with blocks if this particle is a bullet
  390.         IF particle(i).kind = bullet THEN
  391.             FOR j = 1 TO 80
  392.                 IF block(j).state = false THEN _CONTINUE
  393.                 IF particle(i).x > block(j).x AND particle(i).x < block(j).x + blockWidth AND particle(i).y < block(j).y + blockHeight THEN
  394.                     destroyBlock j, false
  395.                     IF TIMER - special(BreakThrough).start > special(BreakThrough).span OR special(BreakThrough).start = 0 THEN
  396.                         particle(i).state = false
  397.                     END IF
  398.                     EXIT FOR
  399.                 END IF
  400.             NEXT
  401.         END IF
  402.     NEXT
  403.  
  404. SUB resetParticle (this AS Particle)
  405.     DIM empty AS Particle
  406.     this = empty
  407.  
  408. SUB generateBlocks
  409.     FOR i = 1 TO 8
  410.         FOR j = 1 TO 10
  411.             b = b + 1
  412.             block(b).x = (i - 1) * blockWidth
  413.             block(b).y = (j - 1) * blockHeight
  414.             minRGB = 50
  415.             DO
  416.                 red = 255 * RND
  417.                 green = 255 * RND
  418.                 blue = 255 * RND
  419.             LOOP UNTIL red > minRGB AND green > minRGB AND blue > minRGB
  420.             block(b).c = _RGB32(red, green, blue)
  421.             block(b).state = RND
  422.             r = RND * 1000
  423.             IF r > 150 AND r < 200 THEN
  424.                 block(b).special = RND * totalSpecialPowers
  425.             END IF
  426.  
  427.             r = RND * 1000
  428.             IF r > 150 AND r < 200 THEN
  429.                 block(b).kind = RND * 2
  430.             END IF
  431.         NEXT
  432.     NEXT
  433.  
  434. SUB showBlocks
  435.     FOR i = 1 TO 80
  436.         IF block(i).state = false THEN _CONTINUE
  437.         activeBlocks = activeBlocks + 1
  438.         IF block(i).kind <> unbreakable THEN
  439.             LINE (block(i).x, block(i).y)-STEP(blockWidth - 1, blockHeight - 1), block(i).c, BF
  440.         END IF
  441.  
  442.         IF block(i).kind = hitTwice THEN
  443.             FOR x = block(i).x TO block(i).x + blockWidth - 1 STEP 5
  444.                 LINE (x, block(i).y)-(x, block(i).y + blockHeight - 1), _RGB32(188)
  445.             NEXT
  446.         ELSEIF block(i).kind = unbreakable THEN
  447.             activeBlocks = activeBlocks - 1
  448.             FOR x = block(i).x TO block(i).x + blockWidth - 1 STEP 5
  449.                 LINE (x, block(i).y)-(x, block(i).y + blockHeight - 1), _RGB32(72)
  450.             NEXT
  451.             FOR y = block(i).y TO block(i).y + blockHeight - 1 STEP 5
  452.                 LINE (block(i).x, y)-(block(i).x + blockWidth - 1, y), _RGB32(72)
  453.             NEXT
  454.         END IF
  455.  
  456.         LINE (block(i).x, block(i).y)-STEP(blockWidth - 1, blockHeight - 1), _RGB32(255), B
  457.         LINE (block(i).x + 1, block(i).y + 1)-STEP(blockWidth - 3, blockHeight - 3), _RGB32(0), B
  458.  
  459.         IF block(i).special THEN
  460.             'COLOR _RGB32(0)
  461.             '_PRINTSTRING (block(i).x + 1, block(i).y + 1), STR$(block(i).special)
  462.             'COLOR _RGB32(255)
  463.             '_PRINTSTRING (block(i).x, block(i).y), STR$(block(i).special)
  464.             FOR j = 1 TO 5
  465.                 LINE (block(i).x + j, block(i).y + j)-STEP(blockWidth - j * 2, blockHeight - j * 2), _RGB32(255, 166, 0), B
  466.                 LINE (block(i).x + j, block(i).y + j)-STEP(blockWidth - j * 2, blockHeight - j * 2), _RGB32(255, 238, 0), B
  467.             NEXT
  468.         END IF
  469.     NEXT
  470.     win = (activeBlocks = 0)
  471.  
  472. SUB doPaddle
  473.     STATIC lastX AS INTEGER
  474.  
  475.     IF _MOUSEX <> lastX THEN
  476.         lastX = _MOUSEX
  477.         paddleX = _MOUSEX - paddleWidth / 2
  478.     END IF
  479.  
  480.     IF _KEYDOWN(19200) THEN paddleX = paddleX - 5
  481.     IF _KEYDOWN(19712) THEN paddleX = paddleX + 5
  482.  
  483.     IF paddleX < 0 THEN paddleX = 0
  484.     IF paddleX + paddleWidth > _WIDTH - 1 THEN paddleX = _WIDTH - 1 - paddleWidth
  485.  
  486.     LINE (paddleX + paddleHeight / 2, paddleY)-STEP(paddleWidth - paddleHeight, paddleHeight), _RGB32(89, 161, 255), BF
  487.     CircleFill paddleX + paddleHeight / 2, paddleY + paddleHeight / 2, paddleHeight / 2, _RGB32(194, 89, 61)
  488.     CircleFill paddleX + paddleWidth - paddleHeight / 2, paddleY + paddleHeight / 2, paddleHeight / 2, _RGB32(194, 89, 61)
  489.  
  490.     IF TIMER - special(Magnetic).start < special(Magnetic).span THEN
  491.         FOR j = 1 TO 2
  492.             PSET (paddleX + paddleHeight / 2, paddleY), electricColor(j)
  493.             FOR i = paddleX + paddleHeight TO paddleX + paddleWidth - paddleHeight STEP paddleWidth / 10
  494.                 LINE -(i, paddleY - (RND * 10)), electricColor(j)
  495.             NEXT
  496.             LINE -(paddleX + paddleWidth - paddleHeight / 2, paddleY), electricColor(j)
  497.  
  498.         NEXT
  499.     END IF
  500.  
  501.     IF _MOUSEBUTTON(1) OR _KEYDOWN(13) THEN ball.state = true
  502.  
  503.         STATIC mouseWasDown AS _BYTE
  504.         mouseWasDown = true
  505.     END IF
  506.  
  507.     IF TIMER - special(Shooter).start < special(Shooter).span THEN
  508.         CircleFill paddleX + paddleHeight / 2, paddleY, paddleHeight / 3, _RGB32(194, 133, 61)
  509.         CircleFill paddleX + paddleWidth - paddleHeight / 2, paddleY, paddleHeight / 3, _RGB32(194, 133, 61)
  510.  
  511.         CircleFill paddleX + paddleHeight / 2, paddleY - paddleHeight / 4, paddleHeight / 4, _RGB32(194, 188, 61)
  512.         CircleFill paddleX + paddleWidth - paddleHeight / 2, paddleY - paddleHeight / 4, paddleHeight / 4, _RGB32(194, 188, 61)
  513.  
  514.         IF _MOUSEBUTTON(1) = false AND mouseWasDown THEN
  515.             mouseWasDown = false
  516.  
  517.             FOR i = 1 TO 2
  518.                 l = newParticle
  519.                 particle(l).r = 100
  520.                 particle(l).g = 100
  521.                 particle(l).b = 100
  522.                 IF i = 1 THEN particle(l).x = paddleX + paddleHeight / 2 ELSE particle(l).x = paddleX + paddleWidth - paddleHeight / 2
  523.                 particle(l).y = paddleY
  524.                 particle(l).yVel = -4.5
  525.                 particle(l).yAcc = -gravity * 1.5
  526.                 particle(l).size = 2
  527.                 particle(l).kind = bullet
  528.             NEXT
  529.         END IF
  530.     END IF
  531.  
  532.  
  533. SUB doBall
  534.     IF ball.state = false THEN
  535.         ball.x = paddleX + magneticOffset
  536.         ball.y = paddleY - (ball.radius)
  537.     ELSE
  538.         ball.x = ball.x + ball.xDir * ball.xVel
  539.         ball.y = ball.y + ball.yDir * ball.yVel
  540.  
  541.         ballCollision
  542.     END IF
  543.  
  544.     IF TIMER - special(FireBall).start < special(FireBall).span THEN
  545.         FOR j = 1 TO 10
  546.             l = newParticle
  547.             IF l = 0 THEN EXIT FOR
  548.             particle(l).r = 222 + (RND * 30)
  549.             particle(l).g = 100 + (RND * 70)
  550.             particle(l).x = ball.x + COS(RND * _PI(2)) * (ball.radius * RND)
  551.             particle(l).y = ball.y + SIN(RND * _PI(2)) * (ball.radius * RND)
  552.             particle(l).lifeSpan = RND
  553.         NEXT
  554.     END IF
  555.  
  556.     CircleFill ball.x, ball.y, ball.radius, ball.c
  557.  
  558. FUNCTION newParticle&
  559.     FOR i = 1 TO UBOUND(particle)
  560.         IF particle(i).state = false THEN
  561.             newParticle& = i
  562.             resetParticle particle(i)
  563.             particle(i).state = true
  564.             particle(i).birth = TIMER
  565.             EXIT FUNCTION
  566.         END IF
  567.     NEXT
  568.  
  569. SUB ballCollision
  570.     'paddle
  571.     IF ball.x > paddleX AND ball.x < paddleX + paddleWidth AND ball.y > paddleY AND ball.y < paddleY + paddleHeight THEN
  572.         IF TIMER - special(Magnetic).start < special(Magnetic).span THEN
  573.             ball.state = false
  574.             magneticOffset = ball.x - paddleX
  575.         END IF
  576.  
  577.         IF ball.x < paddleX + paddleWidth / 2 THEN
  578.             ball.xDir = left
  579.             ball.xVel = map(ball.x, paddleX, paddleX + paddleWidth / 3, 6, 3)
  580.         ELSE
  581.             ball.xDir = right
  582.             ball.xVel = map(ball.x, paddleX + paddleWidth / 3, paddleX + paddleWidth, 3, 6)
  583.         END IF
  584.         IF ball.xVel < 3 THEN ball.xVel = 3
  585.  
  586.         IF ball.yDir = 1 AND ball.y < paddleY + paddleHeight / 2 THEN ball.yDir = -1
  587.         EXIT SUB
  588.     END IF
  589.  
  590.     'blocks
  591.     FOR i = 1 TO 80
  592.         IF block(i).state = false THEN _CONTINUE
  593.         IF ball.x > block(i).x AND ball.x < block(i).x + blockWidth AND ball.y > block(i).y AND ball.y < block(i).y + blockHeight THEN
  594.             destroyBlock i, true
  595.             EXIT SUB
  596.         END IF
  597.     NEXT
  598.  
  599.     'walls
  600.     IF ball.x < ball.radius THEN ball.xDir = right
  601.     IF ball.x > _WIDTH - ball.radius THEN ball.xDir = left
  602.     IF ball.y > _HEIGHT + ball.radius THEN
  603.         lives = lives - 1
  604.         magneticOffset = paddleWidth / 2
  605.         ball.state = false
  606.         ball.xDir = right
  607.         ball.yDir = up
  608.         ball.xVel = 3
  609.         ball.yVel = 3
  610.     END IF
  611.     IF ball.y < 0 THEN ball.yDir = down
  612.  
  613. SUB destroyBlock (i AS LONG, ballHit AS _BYTE)
  614.     SELECT CASE block(i).kind
  615.         CASE regular
  616.             block(i).state = false
  617.  
  618.             IF TIMER - special(BreakThrough).start < special(BreakThrough).span THEN
  619.                 maxJ = 10
  620.                 maxK = 3
  621.                 FOR j = 1 TO maxJ
  622.                     FOR k = 1 TO maxK
  623.                         l = newParticle
  624.                         IF l = 0 THEN EXIT FOR
  625.                         a = RND * 1000
  626.                         IF a < 100 THEN
  627.                             particle(l).r = _RED32(block(i).c)
  628.                             particle(l).g = _GREEN32(block(i).c)
  629.                             particle(l).b = _BLUE32(block(i).c)
  630.                         ELSE
  631.                             particle(l).r = map(a, 0, 1000, 50, 255)
  632.                             particle(l).g = map(a, 0, 1000, 50, 255)
  633.                             particle(l).b = map(a, 0, 1000, 50, 255)
  634.                         END IF
  635.                         particle(l).x = block(i).x + ((blockWidth / maxJ) * (j - 1))
  636.                         particle(l).y = block(i).y + ((blockHeight / maxK) * (k - 1))
  637.                         a = RND
  638.                         IF ball.xDir = right AND ball.yDir = up THEN
  639.                             particle(l).xAcc = COS(map(a, 0, 1, _PI(1.5), _PI(2)))
  640.                             particle(l).yAcc = SIN(map(a, 0, 1, _PI(1.5), _PI(2)))
  641.                         ELSEIF ball.xDir = right AND ball.yDir = down THEN
  642.                             particle(l).xAcc = COS(map(a, 0, 1, 0, _PI(.5)))
  643.                             particle(l).yAcc = SIN(map(a, 0, 1, 0, _PI(.5)))
  644.                         ELSEIF ball.xDir = left AND ball.yDir = up THEN
  645.                             particle(l).xAcc = COS(map(a, 0, 1, _PI, _PI(1.5)))
  646.                             particle(l).yAcc = SIN(map(a, 0, 1, _PI, _PI(1.5)))
  647.                         ELSEIF ball.xDir = left AND ball.yDir = down THEN
  648.                             particle(l).xAcc = COS(map(a, 0, 1, _PI(.5), _PI))
  649.                             particle(l).yAcc = SIN(map(a, 0, 1, _PI(.5), _PI))
  650.                         END IF
  651.                         particle(l).lifeSpan = .5
  652.                         particle(l).size = 1
  653.                     NEXT
  654.                 NEXT
  655.             END IF
  656.  
  657.             IF block(i).special THEN
  658.                 STATIC lastSpecialGiven AS SINGLE
  659.                 IF TIMER - lastSpecialGiven > 3 THEN
  660.                     lastSpecialGiven = TIMER
  661.                     l = newParticle
  662.                     IF l THEN
  663.                         particle(l).size = 6
  664.                         particle(l).x = block(i).x + blockWidth / 2
  665.                         particle(l).y = block(i).y + blockHeight / 2
  666.                         particle(l).r = 255
  667.                         particle(l).g = 255
  668.                         particle(l).b = 255
  669.                         particle(l).kind = specialPower
  670.                         particle(l).special = block(i).special
  671.                     END IF
  672.                 END IF
  673.             END IF
  674.  
  675.             points = ((_RED32(block(i).c) + _GREEN32(block(i).c) + _BLUE32(block(i).c)) / 3) / 10
  676.             score = score + points
  677.         CASE hitTwice
  678.             block(i).kind = regular
  679.             IF ballHit THEN
  680.                 IF TIMER - special(FireBall).start < special(FireBall).span THEN destroyBlock i, ballHit
  681.             END IF
  682.         CASE unbreakable
  683.             'check if the ball is trapped between two unbreakable blocks
  684.             STATIC lastBlock(1 TO 3) AS Block
  685.             lastBlock(3) = lastBlock(2)
  686.             lastBlock(2) = lastBlock(1)
  687.             lastBlock(1) = block(i)
  688.             IF (lastBlock(1).x = lastBlock(3).x AND lastBlock(1).y = lastBlock(3).y) OR _
  689.                lastBlock(1).x = lastBlock(2).x AND lastBlock(1).y = lastBlock(2).y THEN
  690.                 IF ball.xVel > 4.5 AND ball.xVel < 6 THEN
  691.                     ball.xVel = 6
  692.                 ELSEIF ball.xVel = 6 THEN
  693.                     ball.xVel = 5
  694.                 END IF
  695.  
  696.                 IF ball.xVel <= 4.5 AND ball.xVel > 3 THEN
  697.                     ball.xVel = 3
  698.                 ELSEIF ball.xVel = 3 THEN
  699.                     ball.xVel = 4
  700.                 END IF
  701.             END IF
  702.     END SELECT
  703.  
  704.     IF ballHit THEN
  705.         IF (block(i).kind = unbreakable OR block(i).kind = hitTwice) THEN
  706.             FOR j = 1 TO map(ball.xVel, 3, 6, 10, 30)
  707.                 l = newParticle
  708.                 IF l = 0 THEN EXIT FOR
  709.                 particle(l).r = 222 + (RND * 30)
  710.                 particle(l).g = 100 + (RND * 70)
  711.                 particle(l).x = ball.x + COS(RND * _PI(2)) * (ball.radius * RND)
  712.                 particle(l).y = ball.y + SIN(RND * _PI(2)) * (ball.radius * RND)
  713.                 particle(l).lifeSpan = RND
  714.  
  715.                 a = RND
  716.                 IF ball.xDir = right AND ball.yDir = up THEN
  717.                     particle(l).xVel = COS(map(a, 0, 1, _PI(1.5), _PI(2)))
  718.                     particle(l).yVel = SIN(map(a, 0, 1, _PI(1.5), _PI(2)))
  719.                 ELSEIF ball.xDir = right AND ball.yDir = down THEN
  720.                     particle(l).xVel = COS(map(a, 0, 1, 0, _PI(.5)))
  721.                     particle(l).yVel = SIN(map(a, 0, 1, 0, _PI(.5)))
  722.                 ELSEIF ball.xDir = left AND ball.yDir = up THEN
  723.                     particle(l).xVel = COS(map(a, 0, 1, _PI, _PI(1.5)))
  724.                     particle(l).yVel = SIN(map(a, 0, 1, _PI, _PI(1.5)))
  725.                 ELSEIF ball.xDir = left AND ball.yDir = down THEN
  726.                     particle(l).xVel = COS(map(a, 0, 1, _PI(.5), _PI))
  727.                     particle(l).yVel = SIN(map(a, 0, 1, _PI(.5), _PI))
  728.                 END IF
  729.             NEXT
  730.         END IF
  731.  
  732.         IF TIMER - special(BreakThrough).start > special(BreakThrough).span OR special(BreakThrough).start = 0 THEN
  733.             IF ball.x < block(i).x + blockWidth / 2 THEN ball.xDir = left ELSE ball.xDir = right
  734.             IF ball.y < block(i).y + blockHeight / 2 THEN ball.yDir = up ELSE ball.yDir = down
  735.         END IF
  736.     END IF
  737.  
  738. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  739.     ' CX = center x coordinate
  740.     ' CY = center y coordinate
  741.     '  R = radius
  742.     '  C = fill color
  743.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  744.     DIM X AS INTEGER, Y AS INTEGER
  745.     Radius = ABS(R)
  746.     RadiusError = -Radius
  747.     X = Radius
  748.     Y = 0
  749.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  750.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  751.     WHILE X > Y
  752.         RadiusError = RadiusError + Y * 2 + 1
  753.         IF RadiusError >= 0 THEN
  754.             IF X <> Y + 1 THEN
  755.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  756.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  757.             END IF
  758.             X = X - 1
  759.             RadiusError = RadiusError - X * 2
  760.         END IF
  761.         Y = Y + 1
  762.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  763.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  764.     WEND
  765.  
  766. FUNCTION map! (value!, minRange!, maxRange!, newMinRange!, newMaxRange!)
  767.     map! = ((value! - minRange!) / (maxRange! - minRange!)) * (newMaxRange! - newMinRange!) + newMinRange!
  768.  

2019-03-26 11_45_29-Breakout.png

 
2019-03-26 11_45_05-Breakout.png

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Breakout
« Reply #10 on: March 26, 2019, 10:47:04 am »
Very nice work, Fellippe and BPlus!

FellippeHeitor

  • Guest
Re: Breakout
« Reply #11 on: March 26, 2019, 12:07:43 pm »
Very nice work, Fellippe and BPlus!

Thanks, Petr!

And here's the fireball:
Capturar.PNG

FellippeHeitor

  • Guest
Re: Breakout
« Reply #12 on: March 26, 2019, 12:45:14 pm »
I thought the game needed more paddle control so players could have a chance to direct where the ball goes after contact with paddle.

I hope you'll enjoy the magnetic paddle power-up I've added.

Sem título.png
« Last Edit: March 26, 2019, 12:47:18 pm by FellippeHeitor »

Marked as best answer by on November 16, 2024, 11:26:27 am

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Breakout
« Reply #13 on: March 26, 2019, 01:14:48 pm »
  • Undo Best Answer
  • Wow! marvelous variations Fellippe.

    FellippeHeitor

    • Guest
    Re: Breakout
    « Reply #14 on: March 26, 2019, 01:24:42 pm »
    Thanks! I had never actually played the original game and I cut my teeth on the format with a game called DXBall, back in Windows 98 days. That's where the inspiration for this one comes from.