Advertisement
cookertron

Breakout Style Game - Python Pygame

Apr 15th, 2020
439
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.92 KB | None | 0 0
  1. import pygame
  2. import lzma, base64
  3. import time, math
  4.  
  5. BREAKOUT_SPRITES = b'/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4APdAjRdAAKAjkKoM08lH2uEOo/rcuUOhxiX0ZkQV0GNZp2\
  6. c0laZz/AQYennOMPOt3ciHQEI/1DsSnXBO4tnu5kDdIIMRG7iK4j5kCzxz6/G6r2+4Fuum8hJM/Yeljt2fE/ULrCvXQ734Qijj6m\
  7. bu88jRCGH7tcVrgQMl3GPX8W7fi4RbwhruQSfYKR/bvCAYNKkEv7vRxn5toCsvXAAg19ezKtqLEhFK810/fCKZd2JCmMLrrx1o/N\
  8. UI//+fZaeppOJ5uDZcOHw4qIoz75bxMxSIZUvehGvtNF3qfc1610Er2aCHTgjDcVW1HWxse47+Xf8B+37qbPFwCdJfzuO8Y5qFHD\
  9. QUp6QPJNOHzm3Rx9fZ0CCHm/auvZgup+nVL1bU0vAQ42S0uScdzEyyB5GbnKL4n8Y0tBjCiu7JFo4elvWA9B60zBvlo4FOT/YFZ3\
  10. 0/FrUeMOdLUoomUWDZ4cI5shVvOKGmE1qKzFuxo/zTDJSDkyRwuwA1LyRCET8JneWILCGe/vrSpZ4tTPFRoQk6u4vwSl2l4Oc6Re\
  11. Q5se78SG3UzqhjD7El/HH6s1B5MEk4HPp2CS+E8Ax4dCfzPg/cwrkHFcTHFOAjjs59ha7RjAq2wqXBJi2ckizfbalZlxYtzXyYzO\
  12. my85ngyD0b+0Z4YGEIw+xNJ4Up4md6wYUFt/yBWnZiEGImsqxrFp1FF0hdS5uou5c82NXSODYwbEdGXRqW1WAhhZEf/ucMsGRbr3\
  13. qoMwOVNIFxI4aNgD/d5614KloKgAB0ATeBwAAHbYv57HEZ/sCAAAAAARZWg=='
  14.  
  15. MAP = b'/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AFfADddAADuGE1r3b4H/A7syKBXW69az164Q4tMGeDoPiBScQvgano899RG\
  16. ZHePlTQvu2GfNLBsFotLCgAAANaAZ217PTDeAAFT4AIAAADQoZLLscRn+wIAAAAABFla'
  17.  
  18. class maps:
  19.     class brick:
  20.         def __init__(s, id, index):
  21.             global ZX_WIDTH, ZX_TILE_SIZE
  22.  
  23.             s.x = index % ZX_WIDTH * ZX_TILE_SIZE
  24.             s.y = int(index / ZX_WIDTH) * ZX_TILE_SIZE
  25.             s.id = id
  26.             s.dead = False
  27.  
  28.     def __init__(s, lz64_data):
  29.         data = lzma.decompress(base64.b64decode(lz64_data))
  30.  
  31.         s.bricks = []
  32.         for index in range(11 * ZX_WIDTH):
  33.             id = data[index]
  34.             s.bricks.append(s.brick(id, index))
  35.    
  36.     def draw(s):
  37.         global SPRITES
  38.         global ZX_SURFACE
  39.  
  40.         for b in s.bricks:
  41.             if b.dead: continue
  42.             ZX_SURFACE.blit(SPRITES.sprites['b' + str(b.id)], (b.x, b.y))
  43.  
  44. class spritesSheet:
  45.     def b(s, a):
  46.         return a[1 :], int.from_bytes(a[: 1], "big")
  47.  
  48.     def w(s, a):
  49.         return a[2 :], int.from_bytes(a[: 2], "big")
  50.  
  51.     def d(s, a):
  52.         return a[4 :], int.from_bytes(a[: 4], "big")
  53.  
  54.     def rgb(s, a):
  55.         return a[3 :], int.from_bytes(a[: 3], "big")
  56.  
  57.     def name(s, a):
  58.         sl = int.from_bytes(a[: 1], "big")
  59.         return a[1 + sl :], a[1 : sl + 1].decode("utf-8")
  60.  
  61.     def cr(s, index):
  62.         return [index % s.c * s.cw, int(index / s.c) * s.ch, s.cw, s.ch]
  63.  
  64.     def __init__(s, lz64_data):
  65.         # decompress data
  66.         data = lzma.decompress(base64.b64decode(lz64_data))
  67.  
  68.         # get image dimensions
  69.         data, s.c = s.b(data) # cols
  70.         data, s.r = s.b(data) # rows
  71.         data, s.cw = s.b(data) # cell width
  72.         data, s.ch = s.b(data) # cell height
  73.         s.iw = s.c * s.cw # image width
  74.         s.ih = s.r * s.ch # image height
  75.  
  76.         # get palette length
  77.         data, s.pl = s.b(data) # palette length
  78.  
  79.         # get palette
  80.         s.palette = []
  81.         for index in range(s.pl):
  82.             data, irgb = s.rgb(data)
  83.             s.palette.append(irgb)
  84.  
  85.         # create pygame surface to place spritesheet
  86.         s.surface = pygame.Surface((s.iw, s.ih))
  87.         pa = pygame.PixelArray(s.surface)
  88.  
  89.         # get image data length in bytes
  90.         idl = s.iw * s.ih
  91.  
  92.         # extract image data
  93.         for index in range(idl):
  94.             data, pi = s.b(data) # palette index
  95.             pa[index % s.iw][int(index / s.iw)] = s.palette[pi]
  96.         pa.close()
  97.         del pa
  98.  
  99.         # make the sprites using the assembly data
  100.         s.sprites = {}
  101.         cell = pygame.Surface((s.cw, s.ch)) # to temp store cell
  102.  
  103.         while data:
  104.             data, sn = s.name(data) # sprite name
  105.             data, sw = s.w(data) # sprite width, if width is zero then it's a copy instruction
  106.  
  107.             if sw == 0: # copy instruction?
  108.                 data, snc = s.name(data) #sprite name to copy
  109.                 data, at = s.b(data) # assembly attribute
  110.  
  111.                 # apply attribute 0 = none, 1 = h flip, 2 = v flip, 3 = rot 90, 4 = rot 180, 5 = rot 270
  112.                 if at == 0:
  113.                     s.sprites[sn] = s.sprites[snc].copy()
  114.                 elif at == 1:
  115.                     s.sprites[sn] = pygame.transform.flip(s.sprites[snc], True, False)
  116.                 elif at == 2:
  117.                     s.sprites[sn] = pygame.transform.flip(s.sprites[snc], False, True)
  118.                 elif at == 3:
  119.                     s.sprites[sn] = pygame.transform.rotate(s.sprites[snc], -90)
  120.                 elif at == 4:
  121.                     s.sprites[sn] = pygame.transform.rotate(s.sprites[snc], -180)                      
  122.                 elif at == 5:
  123.                     s.sprites[sn] = pygame.transform.rotate(s.sprites[snc], -270)  
  124.                 continue
  125.  
  126.             data, sh = s.w(data) # sprite height
  127.  
  128.             sc = math.ceil(sw / s.cw) # sprite columns
  129.             sr = math.ceil(sh / s.ch) # sprite rows
  130.             scc = sc * sr # sprite cell count
  131.             scc_index = 0
  132.  
  133.             # create a surface for the sprite
  134.             s.sprites[sn] = pygame.Surface((sw, sh))
  135.  
  136.             # cycle through assembly instructions
  137.             while scc_index < scc:
  138.                 #print(scc_index, scc)
  139.                 data, ci = s.w(data) # cell index
  140.                 data, at = s.b(data) # assembly attribute
  141.  
  142.                 if at < 6: # single cell placement?
  143.                     # calc x, y coords of cell placement
  144.                     x = scc_index % sc * s.cw
  145.                     y = int(scc_index / sc) * s.ch
  146.  
  147.                     # get cell image
  148.                     cell.blit(s.surface, (0, 0), s.cr(ci))
  149.  
  150.                     # apply attribute 0 = none, 1 = h flip, 2 = v flip, 3 = rot 90, 4 = rot 180, 5 = rot 270
  151.                     if at == 0:
  152.                         s.sprites[sn].blit(cell, (x, y))
  153.                     elif at == 1:
  154.                         s.sprites[sn].blit(pygame.transform.flip(cell, True, False), (x, y))
  155.                     elif at == 2:
  156.                         s.sprites[sn].blit(pygame.transform.flip(cell, False, True), (x, y))
  157.                     elif at == 3:
  158.                         s.sprites[sn].blit(pygame.transform.rotate(cell, -90), (x, y))
  159.                     elif at == 4:
  160.                         s.sprites[sn].blit(pygame.transform.rotate(cell, -180), (x, y))                        
  161.                     elif at == 5:
  162.                         s.sprites[sn].blit(pygame.transform.rotate(cell, -270), (x, y))                        
  163.                     scc_index += 1
  164.                 else:
  165.                     data, r = s.w(data) # get range count
  166.  
  167.                     for index in range(r):
  168.                         # get x, y coords of cell placement
  169.                         x = (scc_index + index) % sc * s.cw
  170.                         y = int((scc_index + index) / sc) * s.ch
  171.                        
  172.                         # get cell image
  173.                         cell.blit(s.surface, (0, 0), s.cr(ci))
  174.                            
  175.                         # apply attribute 6 = none, 7 = h flip, 8 = v flip, 9 = rot 90, 10 = rot 180, 11 = rot 270
  176.                         if at == 6 or at == 12 or at == 18:
  177.                             s.sprites[sn].blit(cell, (x, y))
  178.                         elif at == 7 or at == 13 or at == 19:
  179.                             s.sprites[sn].blit(pygame.transform.flip(cell, True, False), (x, y))
  180.                         elif at == 8 or at == 14 or at == 20:
  181.                             s.sprites[sn].blit(pygame.transform.flip(cell, False, True), (x, y))
  182.                         elif at == 9 or at == 15 or at == 21:
  183.                             s.sprites[sn].blit(pygame.transform.rotate(cell, -90), (x, y))
  184.                         elif at == 10 or at == 16 or at == 22:
  185.                             s.sprites[sn].blit(pygame.transform.rotate(cell, -180), (x, y))                        
  186.                         elif at == 11 or at == 17 or at == 23:
  187.                             s.sprites[sn].blit(pygame.transform.rotate(cell, -270), (x, y))
  188.                        
  189.                         # increment/decrement the sprite sheet cell index
  190.                         if at > 11 and at < 18:
  191.                             ci += 1
  192.                         elif at > 17:
  193.                             ci -= 1
  194.  
  195.                     scc_index += r
  196.  
  197. SCALE = 3
  198. ZX_TILE_SIZE = 8
  199. ZX_WIDTH = 32
  200. ZX_HEIGHT = 24
  201.  
  202. W, H = ZX_WIDTH * ZX_TILE_SIZE, ZX_HEIGHT * ZX_TILE_SIZE
  203. HW, HH = int(W / 2), int(H / 2)
  204. FPS = 60
  205.  
  206. pygame.init()
  207. DS = pygame.display.set_mode((W * SCALE, H * SCALE))
  208. ZX_SURFACE = pygame.Surface((W, H))
  209. CLOCK = pygame.time.Clock()
  210.  
  211. SPRITES = spritesSheet(BREAKOUT_SPRITES)
  212. BRICKS = maps(MAP)
  213.  
  214. BAT_WIDTH = 6 * ZX_TILE_SIZE
  215. BAT_WIDTH_HALF = int(BAT_WIDTH / 2)
  216. BAT_HEIGHT = ZX_TILE_SIZE
  217. batX = pygame.mouse.get_pos()[0] - BAT_WIDTH_HALF
  218. batY = H - BAT_HEIGHT
  219.  
  220. BALL_RADIUS = int(ZX_TILE_SIZE / 2)
  221. BALL_COLLISION_RADIUS = BALL_RADIUS - 1
  222. ballX, ballY = HW, H - BAT_HEIGHT - BALL_RADIUS
  223. ballVX, ballVY = 0, -1
  224.  
  225. BALL_MAX_VX = 1
  226. BALL_VX_CHUNK = BALL_MAX_VX / BAT_WIDTH_HALF
  227.  
  228. start = False
  229.  
  230. while True:
  231.     e = pygame.event.get()
  232.     if pygame.key.get_pressed()[pygame.K_ESCAPE]: break
  233.     if pygame.mouse.get_pressed()[0]: start = True
  234.  
  235.     batX = pygame.mouse.get_pos()[0] / SCALE - BAT_WIDTH_HALF
  236.     if batX <= 0:
  237.         batX = 0
  238.     elif batX + BAT_WIDTH >= W:
  239.         batX = W - BAT_WIDTH
  240.  
  241.     if not start:
  242.         ballX = batX + BAT_WIDTH_HALF
  243.  
  244.     if ballY + BALL_RADIUS <= batY and ballY + BALL_RADIUS + ballVY >= batY:
  245.         if ballX >= batX and ballX <= batX + BAT_WIDTH:
  246.             ballVY = -ballVY
  247.            
  248.             ballHitX = ballX - (batX + BAT_WIDTH_HALF)
  249.             ballVX = ballHitX * BALL_VX_CHUNK
  250.  
  251.     bx1 = ballX - BALL_COLLISION_RADIUS
  252.     by1 = ballY - BALL_COLLISION_RADIUS
  253.     bx2 = ballX + BALL_COLLISION_RADIUS
  254.     by2 = ballY + BALL_COLLISION_RADIUS
  255.    
  256.     for b in BRICKS.bricks:
  257.         if b.dead: continue
  258.         if ((bx2 <= b.x and bx2 + ballVX >= b.x)  or (bx1 >= b.x + ZX_TILE_SIZE and bx1 + ballVX <= b.x + ZX_TILE_SIZE)) and not (by2 < b.y or by1 > b.y + ZX_TILE_SIZE):
  259.             ballVX = -ballVX
  260.             b.dead = True
  261.         if ((by2 <= b.y and by2 + ballVY >= b.y)  or (by1 >= b.y + ZX_TILE_SIZE and by1 + ballVY <= b.y + ZX_TILE_SIZE)) and not (bx2 < b.x or bx1 > b.x + ZX_TILE_SIZE):
  262.             ballVY = -ballVY
  263.             b.dead = True
  264.  
  265.     if start:
  266.         ballX += ballVX
  267.         ballY += ballVY
  268.  
  269.     if ballY >= H - BALL_RADIUS:
  270.         break
  271.     elif ballY <= BALL_RADIUS:
  272.         ballVY = -ballVY
  273.  
  274.     if ballX >= W - BALL_RADIUS or ballX <= BALL_RADIUS:
  275.         ballVX = -ballVX    
  276.  
  277.     ZX_SURFACE.fill([0, 0, 0])
  278.     ZX_SURFACE.blit(SPRITES.sprites['bat'], (int(batX), int(batY)))
  279.     ZX_SURFACE.blit(SPRITES.sprites['ball'], (int(ballX - BALL_RADIUS), int(ballY - BALL_RADIUS)))
  280.  
  281.     BRICKS.draw()
  282.  
  283.     DS.blit(pygame.transform.scale(ZX_SURFACE, (W * SCALE, H * SCALE)), (0, 0))
  284.  
  285.     pygame.display.update()
  286.     CLOCK.tick(FPS)  
  287. pygame.quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement