Advertisement
cookertron

Enemy Fleet - Python Pygame

Apr 16th, 2020
1,028
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.30 KB | None | 0 0
  1. import pygame
  2. import lzma, base64
  3. import time, math, random
  4.  
  5. ENEMYFLEET_SPRITES = b'/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AT+AhldAAOAjkKY23w2zlqFsNf/5cxaAOxdN8As5Ysmb\
  6. TRMHQV5Jg6V0NsrLpAPkQElcEzcyxXgwm3JefykstBV+7adR72+xmk+qanXZKa77X1N9C9792CSEFTR9TGpbkAnUvQcwjFR0Z6mu\
  7. JrywnJ8lSsKlVr2scXmlMB6uQo5/huPxUgl8fDAszSdIzy7NLvowIyqlXTc6K1ULqk9uy4BHHjz4F+CGC42+laUvelshNK7ZNJmt\
  8. laQLzDpcRqh/U1vx3hG5ct490FcdQEmPp911reyvKW1sWEJp8PVXW0+um6HyOQbTRIeHl32IvPfQHyhXgyLyqkfrv6VjdDZaGHm3\
  9. Lr8GPGSG67UY2YRyoqTRT73mTbxYLOQcdjkVvuWa30Z3D+Fxiltvlx2tA7rFRmjct0OnNb11x681SZr6NbyrLJQwaYPFRDBVUFgU\
  10. lFezZ5utnrWnVPCH0Ih5dVcKoo6IcnTasppSfv7FssFaJFckQeHA57zlmkGMZZA+BIpfKSU2cr7COjLh4RTbGg4zBu8iLAtxdKzQ\
  11. 6HWVqSENuvAFvkGY7ZrQdAtCaAlH0xgJzfodRWfx8SX3AvshlPkCn/mr1LIO9KFaVuNjtuyxziQpWJE9tsXSyCx6JvGYNBBTJKDD\
  12. 92Zyki9YXQCtjxoyEKIhEr2qo7zdzjMKQiHcSkGEirM+tLBdoNryTrJKAWyZxmUuDUHO5TgAf3RK1T2AAAAAABpay/xVB7KHQABt\
  13. QT/CQAApc0GrbHEZ/sCAAAAAARZWg=='
  14.  
  15.  
  16. class spritesSheet:
  17.     def b(s, a):
  18.         return a[1 :], int.from_bytes(a[: 1], "big")
  19.  
  20.     def w(s, a):
  21.         return a[2 :], int.from_bytes(a[: 2], "big")
  22.  
  23.     def d(s, a):
  24.         return a[4 :], int.from_bytes(a[: 4], "big")
  25.  
  26.     def rgb(s, a):
  27.         return a[3 :], int.from_bytes(a[: 3], "big")
  28.  
  29.     def name(s, a):
  30.         sl = int.from_bytes(a[: 1], "big")
  31.         return a[1 + sl :], a[1 : sl + 1].decode("utf-8")
  32.  
  33.     def cr(s, index):
  34.         return [index % s.c * s.cw, int(index / s.c) * s.ch, s.cw, s.ch]
  35.  
  36.     def __init__(s, lz64_data):
  37.         # decompress data
  38.         data = lzma.decompress(base64.b64decode(lz64_data))
  39.  
  40.         # get image dimensions
  41.         data, s.c = s.b(data) # cols
  42.         data, s.r = s.b(data) # rows
  43.         data, s.cw = s.b(data) # cell width
  44.         data, s.ch = s.b(data) # cell height
  45.         s.iw = s.c * s.cw # image width
  46.         s.ih = s.r * s.ch # image height
  47.  
  48.         # get palette length
  49.         data, s.pl = s.b(data) # palette length
  50.  
  51.         # get palette
  52.         s.palette = []
  53.         for index in range(s.pl):
  54.             data, irgb = s.rgb(data)
  55.             s.palette.append(irgb)
  56.  
  57.         # create pygame surface to place spritesheet
  58.         s.surface = pygame.Surface((s.iw, s.ih))
  59.         pa = pygame.PixelArray(s.surface)
  60.  
  61.         # get image data length in bytes
  62.         idl = s.iw * s.ih
  63.  
  64.         # extract image data
  65.         for index in range(idl):
  66.             data, pi = s.b(data) # palette index
  67.             pa[index % s.iw][int(index / s.iw)] = s.palette[pi]
  68.         pa.close()
  69.         del pa
  70.  
  71.         # make the sprites using the assembly data
  72.         s.sprites = {}
  73.         cell = pygame.Surface((s.cw, s.ch)) # to temp store cell
  74.  
  75.         while data:
  76.             data, sn = s.name(data) # sprite name
  77.             data, sw = s.w(data) # sprite width, if width is zero then it's a copy instruction
  78.  
  79.             if sw == 0: # copy instruction?
  80.                 data, snc = s.name(data) #sprite name to copy
  81.                 data, at = s.b(data) # assembly attribute
  82.  
  83.                 # apply attribute 0 = none, 1 = h flip, 2 = v flip, 3 = rot 90, 4 = rot 180, 5 = rot 270
  84.                 if at == 0:
  85.                     s.sprites[sn] = s.sprites[snc].copy()
  86.                 elif at == 1:
  87.                     s.sprites[sn] = pygame.transform.flip(s.sprites[snc], True, False)
  88.                 elif at == 2:
  89.                     s.sprites[sn] = pygame.transform.flip(s.sprites[snc], False, True)
  90.                 elif at == 3:
  91.                     s.sprites[sn] = pygame.transform.rotate(s.sprites[snc], -90)
  92.                 elif at == 4:
  93.                     s.sprites[sn] = pygame.transform.rotate(s.sprites[snc], -180)                      
  94.                 elif at == 5:
  95.                     s.sprites[sn] = pygame.transform.rotate(s.sprites[snc], -270)  
  96.                 continue
  97.  
  98.             data, sh = s.w(data) # sprite height
  99.  
  100.             sc = math.ceil(sw / s.cw) # sprite columns
  101.             sr = math.ceil(sh / s.ch) # sprite rows
  102.             scc = sc * sr # sprite cell count
  103.             scc_index = 0
  104.  
  105.             # create a surface for the sprite
  106.             s.sprites[sn] = pygame.Surface((sw, sh))
  107.  
  108.             # cycle through assembly instructions
  109.             while scc_index < scc:
  110.                 #print(scc_index, scc)
  111.                 data, ci = s.w(data) # cell index
  112.                 data, at = s.b(data) # assembly attribute
  113.  
  114.                 if at < 6: # single cell placement?
  115.                     # calc x, y coords of cell placement
  116.                     x = scc_index % sc * s.cw
  117.                     y = int(scc_index / sc) * s.ch
  118.  
  119.                     # get cell image
  120.                     cell.blit(s.surface, (0, 0), s.cr(ci))
  121.  
  122.                     # apply attribute 0 = none, 1 = h flip, 2 = v flip, 3 = rot 90, 4 = rot 180, 5 = rot 270
  123.                     if at == 0:
  124.                         s.sprites[sn].blit(cell, (x, y))
  125.                     elif at == 1:
  126.                         s.sprites[sn].blit(pygame.transform.flip(cell, True, False), (x, y))
  127.                     elif at == 2:
  128.                         s.sprites[sn].blit(pygame.transform.flip(cell, False, True), (x, y))
  129.                     elif at == 3:
  130.                         s.sprites[sn].blit(pygame.transform.rotate(cell, -90), (x, y))
  131.                     elif at == 4:
  132.                         s.sprites[sn].blit(pygame.transform.rotate(cell, -180), (x, y))                        
  133.                     elif at == 5:
  134.                         s.sprites[sn].blit(pygame.transform.rotate(cell, -270), (x, y))                        
  135.                     scc_index += 1
  136.                 else:
  137.                     data, r = s.w(data) # get range count
  138.  
  139.                     for index in range(r):
  140.                         # get x, y coords of cell placement
  141.                         x = (scc_index + index) % sc * s.cw
  142.                         y = int((scc_index + index) / sc) * s.ch
  143.                        
  144.                         # get cell image
  145.                         cell.blit(s.surface, (0, 0), s.cr(ci))
  146.                            
  147.                         # apply attribute 6 = none, 7 = h flip, 8 = v flip, 9 = rot 90, 10 = rot 180, 11 = rot 270
  148.                         if at == 6 or at == 12 or at == 18:
  149.                             s.sprites[sn].blit(cell, (x, y))
  150.                         elif at == 7 or at == 13 or at == 19:
  151.                             s.sprites[sn].blit(pygame.transform.flip(cell, True, False), (x, y))
  152.                         elif at == 8 or at == 14 or at == 20:
  153.                             s.sprites[sn].blit(pygame.transform.flip(cell, False, True), (x, y))
  154.                         elif at == 9 or at == 15 or at == 21:
  155.                             s.sprites[sn].blit(pygame.transform.rotate(cell, -90), (x, y))
  156.                         elif at == 10 or at == 16 or at == 22:
  157.                             s.sprites[sn].blit(pygame.transform.rotate(cell, -180), (x, y))                        
  158.                         elif at == 11 or at == 17 or at == 23:
  159.                             s.sprites[sn].blit(pygame.transform.rotate(cell, -270), (x, y))
  160.                        
  161.                         # increment/decrement the sprite sheet cell index
  162.                         if at > 11 and at < 18:
  163.                             ci += 1
  164.                         elif at > 17:
  165.                             ci -= 1
  166.  
  167.                     scc_index += r
  168.  
  169.     def colorKey(s, color):
  170.         for key, sprite in s.sprites.items():
  171.             sprite.set_colorkey(color)
  172.  
  173. class bullets:
  174.     class bullet:
  175.         def __init__(s):
  176.             global shipX, shipY
  177.             global ZX_TILE_SIZE
  178.  
  179.             s.x = shipX + ZX_TILE_SIZE
  180.             s.y = shipY + ZX_TILE_SIZE - 4
  181.  
  182.     def __init__(s):
  183.         s.bullets = []
  184.  
  185.     def draw(s):
  186.         global ZX_SURFACE, SPRITES
  187.         for b in s.bullets:
  188.             ZX_SURFACE.blit(SPRITES.sprites['bullet'], (int(b.x), int(b.y)))
  189.    
  190.     def move(s):
  191.         global BULLET_SPEED
  192.         global W
  193.  
  194.         deadBullets = []
  195.         for b in s.bullets:
  196.             b.x += BULLET_SPEED
  197.             if b.x >= W: deadBullets += [b]
  198.         for db in deadBullets:
  199.             s.bullets.remove(db)
  200.    
  201.     def add(s):
  202.         s.bullets += [s.bullet()]
  203.  
  204. class UFOs:
  205.     class bullet:
  206.         def __init__(s, x, y):
  207.             global shipX, shipY
  208.             global ZX_TILE_SIZE
  209.             s.x = x
  210.             s.y = y + int(ZX_TILE_SIZE  / 2)
  211.  
  212.             x = s.x - shipX
  213.             y = s.y - shipY
  214.             d = math.hypot(s.x - shipX, s.y - shipY)
  215.             s.vx = (x / d) * UFO_BULLET_SPEED
  216.             s.vy = (y / d) * UFO_BULLET_SPEED
  217.  
  218.     class UFO:
  219.         def __init__(s):
  220.             global UFO_BULLET_SPEED, UFO_BULLET_DELAY
  221.             global ZX_TILE_SIZE
  222.             global W
  223.  
  224.             s.x = W
  225.             s.y = random.randint(ZX_TILE_SIZE, H - ZX_TILE_SIZE * 2)
  226.            
  227.             s.bulletTime = int(UFO_BULLET_DELAY / 2)
  228.             s.dead = False
  229.  
  230.     def __init__(s):
  231.         s.ufos = []
  232.         s.bullets = []
  233.  
  234.     def draw(s):
  235.         global ZX_SURFACE, SPRITES
  236.  
  237.         for u in s.ufos:
  238.             ZX_SURFACE.blit(SPRITES.sprites['ufo'], (int(u.x), int(u.y)))
  239.         for b in s.bullets:
  240.             ZX_SURFACE.blit(SPRITES.sprites['ufo_bullet'], (int(b.x), int(b.y)))
  241.    
  242.     def move(s):
  243.         global UFO_SPEED, UFO_BULLET_SPEED, UFO_BULLET_DELAY
  244.         global EXPLOSIONS
  245.         global ZX_TILE_SIZE
  246.  
  247.         deadUFOs = []
  248.         for u in s.ufos:
  249.             if u.dead:
  250.                 EXPLOSIONS.add(u.x + ZX_TILE_SIZE, u.y + ZX_TILE_SIZE / 2)
  251.                 deadUFOs += [u]
  252.                 continue
  253.  
  254.             u.x += UFO_SPEED
  255.             if u.x < -ZX_TILE_SIZE * 2:
  256.                 deadUFOs += [u]
  257.             if u.bulletTime:
  258.                 u.bulletTime -= 1
  259.                 if not u.bulletTime:
  260.                     s.bullets += [s.bullet(u.x, u.y)]
  261.                     u.bulletTime = UFO_BULLET_DELAY
  262.         for du in deadUFOs:
  263.             s.ufos.remove(du)
  264.  
  265.         deadBullets = []
  266.         for b in s.bullets:
  267.             b.x += b.vx
  268.             b.y += b.vy
  269.             if b.x < ZX_TILE_SIZE:
  270.                 deadBullets += [b]
  271.         for db in deadBullets:
  272.             s.bullets.remove(db)
  273.  
  274.     def add(s):
  275.         s.ufos += [s.UFO()]
  276.  
  277. class explosions:
  278.     class explosion:
  279.         def __init__(s, x, y, delay):
  280.             global EXPLOSION_RADIUS
  281.             s.x = x + random.uniform(-1, 1) * EXPLOSION_RADIUS
  282.             s.y = y + random.uniform(-1, 1) * EXPLOSION_RADIUS
  283.  
  284.             s.frame = 1
  285.             s.delay = delay
  286.  
  287.     def __init__(s):
  288.         s.explosions = []
  289.  
  290.     def add(s, x, y):
  291.         global EXPLOSION_COUNT, EXPLOSION_DELAY
  292.        
  293.         for index in range(EXPLOSION_COUNT):
  294.             s.explosions += [s.explosion(x, y, index * EXPLOSION_DELAY)]
  295.  
  296.     def draw(s):
  297.         global ZX_SURFACE, SPRITES
  298.         global ZX_TILE_SIZE
  299.  
  300.         for e in s.explosions:
  301.             if e.delay: continue
  302.             ZX_SURFACE.blit(SPRITES.sprites['exp' + str(e.frame)], (int(e.x - ZX_TILE_SIZE / 2), int(e.y - ZX_TILE_SIZE / 2)))
  303.  
  304.     def move(s):
  305.         global EXPLOSION_FRAMES
  306.  
  307.         deadExplosions = []
  308.         for e in s.explosions:
  309.             if e.delay:
  310.                 e.delay -= 1
  311.             else:
  312.                 e.frame += 1
  313.                 if e.frame == EXPLOSION_FRAMES + 1:
  314.                     deadExplosions += [e]
  315.         for de in deadExplosions:
  316.             s.explosions.remove(de)
  317.  
  318. SCALE = 3
  319. ZX_TILE_SIZE = 8
  320. ZX_WIDTH = 32
  321. ZX_HEIGHT = 24
  322.  
  323. W, H = ZX_WIDTH * ZX_TILE_SIZE, ZX_HEIGHT * ZX_TILE_SIZE
  324. HW, HH = int(W / 2), int(H / 2)
  325. FPS = 60
  326.  
  327. pygame.init()
  328. DS = pygame.display.set_mode((W * SCALE, H * SCALE))
  329. ZX_SURFACE = pygame.Surface((W, H))
  330. CLOCK = pygame.time.Clock()
  331.  
  332. SPRITES = spritesSheet(ENEMYFLEET_SPRITES)
  333. SPRITES.colorKey([0, 0, 0])
  334.  
  335. THRUST = 0.2
  336. MAX_THRUST = 2
  337.  
  338. shipX = 10
  339. shipY = HH
  340. shipVX = 0
  341. shipVY = 0
  342. shipDead = False
  343.  
  344. BULLETS = bullets()
  345. BULLET_DELAY = int(FPS / 6)
  346. BULLET_SPEED = 10
  347. bulletTime = 0
  348.  
  349. UFOS = UFOs()
  350. UFO_SPEED = -1
  351. UFO_BULLET_SPEED = -1.5
  352. UFO_BULLET_DELAY = int(FPS) * 2
  353.  
  354. UFO_STARTING_FREQUENCY = int(2 * FPS)
  355. UFO_FREQUENCY_REDUCTION_COUNT = 10
  356. UFO_FREQUENCY_REDUCTION = 5
  357. ufoDelay = UFO_STARTING_FREQUENCY
  358. ufoFrequency = UFO_STARTING_FREQUENCY
  359. ufoCount = 0
  360.  
  361. EXPLOSIONS = explosions()
  362. EXPLOSION_FRAMES = 6
  363. EXPLOSION_COUNT = 20
  364. EXPLOSION_DELAY = 1
  365. EXPLOSION_RADIUS = 8
  366.  
  367. while True:
  368.     e = pygame.event.get()
  369.  
  370.     k = pygame.key.get_pressed()
  371.  
  372.     # exit game
  373.     if k[pygame.K_ESCAPE]: break
  374.  
  375.     # keyboard controls
  376.     # vertical movement
  377.     if not shipDead:
  378.         if k[pygame.K_UP]:
  379.             if shipVY > -MAX_THRUST:
  380.                 shipVY -= THRUST
  381.         elif k[pygame.K_DOWN]:
  382.             if shipVY < MAX_THRUST:
  383.                 shipVY += THRUST
  384.         else:
  385.             shipVY /= 1.1
  386.  
  387.         # horizontal movement
  388.         blitThruster = False
  389.         if k[pygame.K_RIGHT]:
  390.             if shipVX < MAX_THRUST:
  391.                 shipVX += THRUST
  392.             blitThruster = True
  393.         elif k[pygame.K_LEFT]:
  394.             if shipVX > -MAX_THRUST:
  395.                 shipVX -= THRUST
  396.         else:
  397.             shipVX /= 1.1
  398.  
  399.         # fire!
  400.         if k[pygame.K_SPACE] and bulletTime == 0:
  401.             BULLETS.add()
  402.             bulletTime = BULLET_DELAY
  403.  
  404.         # decrement the bullet delay
  405.         if bulletTime:
  406.             bulletTime -= 1
  407.  
  408.         # apply motion to the ship
  409.         shipX += shipVX
  410.         shipY += shipVY
  411.  
  412.     # move ship bullets
  413.     BULLETS.move()
  414.  
  415.     # apply motion to UFOs
  416.     UFOS.move()
  417.  
  418.     # animate explosions
  419.     EXPLOSIONS.move()
  420.  
  421.     # time to add a UFO?
  422.     if ufoDelay:
  423.         ufoDelay -= 1
  424.         if not ufoDelay:
  425.             UFOS.add()
  426.             ufoCount += 1
  427.             if ufoCount == UFO_FREQUENCY_REDUCTION_COUNT:
  428.                 ufoFrequency -= UFO_FREQUENCY_REDUCTION
  429.                 if ufoFrequency < 10:
  430.                     ufoFrequency = 10
  431.             ufoDelay = ufoFrequency
  432.  
  433.     # check for collision between ship bullets and ufos
  434.     for b in BULLETS.bullets:
  435.         for u in UFOS.ufos:
  436.             if not (b.x > u.x + ZX_TILE_SIZE or b.x + 7 < u.x or b.y + 3 < u.y or b.y > u.y + ZX_TILE_SIZE):
  437.                 u.dead = True
  438.  
  439.     # check for collision between ufo bullets and ship
  440.     if not shipDead:
  441.         for b in UFOS.bullets:
  442.             if not (b.x > shipX + ZX_TILE_SIZE or b.x + 4 < shipX or b.y > shipY + ZX_TILE_SIZE or b.y + 4 < shipY):
  443.                 shipDead = True
  444.                 EXPLOSIONS.add(shipX, shipY)
  445.                 break
  446.  
  447.     """ drawing/blitting bit """
  448.     # clear display
  449.     ZX_SURFACE.fill([0, 0, 0])
  450.    
  451.     if not shipDead:
  452.         # blit space ship
  453.         ZX_SURFACE.blit(SPRITES.sprites['ship'], (int(shipX), int(shipY)))
  454.        
  455.         # blit thrusters but only if ship moving to the right
  456.         if blitThruster:
  457.             ZX_SURFACE.blit(SPRITES.sprites['thruster'], (int(shipX - ZX_TILE_SIZE), int(shipY)))
  458.  
  459.     # blit bullets
  460.     BULLETS.draw()
  461.  
  462.     # blit UFOS and UFO Bullets
  463.     UFOS.draw()
  464.  
  465.     # blit explosion frames
  466.     EXPLOSIONS.draw()
  467.  
  468.     # scale surface to fit primary display
  469.     DS.blit(pygame.transform.scale(ZX_SURFACE, (W * SCALE, H * SCALE)), (0, 0))
  470.  
  471.     pygame.display.update()
  472.     CLOCK.tick(FPS)  
  473. pygame.quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement