Author Topic: Breakout  (Read 4590 times)

0 Members and 1 Guest are viewing this topic.

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 »
  • Best Answer
  • 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 »
  • Best Answer
  • 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 »
  • Best Answer
  • 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 »
  • Best Answer
  • 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 »
  • Best Answer
  • 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 »
  • Best Answer
  • 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 »
  • Best Answer
  • :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 »
  • Best Answer
  • 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 »
  • Best Answer
  • 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 »
  • Best Answer
  • Very nice work, Fellippe and BPlus!

    FellippeHeitor

    • Guest
    Re: Breakout
    « Reply #11 on: March 26, 2019, 12:07:43 pm »
  • Best Answer
  • 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 »
  • Best Answer
  • 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 »

    Offline bplus

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

    FellippeHeitor

    • Guest
    Re: Breakout
    « Reply #14 on: March 26, 2019, 01:24:42 pm »
  • Best Answer
  • 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.