Advertisement
cookertron

Drop! Version 5

Dec 30th, 2019
308
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 24.93 KB | None | 0 0
  1. import pygame
  2. import pygame.gfxdraw
  3. import sys, os, time, math, random
  4. import zlib, base64
  5.  
  6. # Pygame contants
  7. W = 1280
  8. H = 720
  9. HW = int(W / 2)
  10. HH = int(H / 2)
  11. FPS = 60
  12.  
  13. # Define some colors
  14. FUCHSIA = [255,   0, 255]
  15. PURPLE  = [128,   0, 128]
  16. TEAL    = [  0, 128, 128]
  17. LIME    = [  0, 255,   0]
  18. GREEN   = [  0, 128,   0]
  19. OLIVE   = [128, 128,   0]
  20. DOLIVE  = [ 64,  64,   0]
  21. YELLOW  = [255, 255,   0]
  22. ORANGE  = [255, 165,   0]
  23. RED     = [255,   0,   0]
  24. MAROON  = [128,   0,   0]
  25. SILVER  = [192, 192, 192]
  26. GRAY    = [128, 128, 128]
  27. BLUE    = [  0,   0, 255]
  28. NAVY    = [  0,   0, 128]
  29. AQUA    = [  0, 255, 255]
  30. WHITE   = [255, 255, 255]
  31. BLACK   = [  0,   0,   0]
  32.  
  33. BEACON_COLOR = [128, 64, 64]
  34.  
  35. # embedded graphics
  36. FONT_DATA = b'eJx1UktOxTAM9HjipGmRHvAWHIAFWwQr7n8xxu4HgUQrt7E9GX/xbquFdU\
  37. jsphN4JwMkcdolk+czLRo8EM1tCCFBX+FfvHsLR+Nn4ZpOTyBuTnubBHabMAh3sTsWfQyxem\
  38. JTyuq47kNgqXnXxSyslEgvDsZ6Anu+yWgOxHa5uJx8Wc2g4lFvd2WvczKu7eCblQ24qBOIIb\
  39. bu0oXqRm585MUFeldGxRUqJqMK1cV6+59JuC6b7Erg4MocwAG4F5saRHuRMiy7+qtGuX5qlC\
  40. dbEToyfdUocSEn0mHO4qOPNTLj4k9c7Kx/ZpG2I2tquvskd4+nXbxrTqlJk7WkKV51tmIpE0\
  41. 7wNaY24UH2LVQ9py4MsAJ/6MZzG4lsGXGprZs9t27W7m3HpNCX/Is3jq5j37XcUc0kdxJddV\
  42. Y937F0CVs='
  43. FONT_CHARMAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.!"
  44.  
  45. # Game constants
  46. GRAVITY = 0.5
  47.  
  48. BACKGROUND_COLOR_TOP = [0, 35, 35]
  49. BACKGROUND_COLOR_BOTTOM = [0, 32, 32]
  50. BACKGROUND_COLOR_TOP_INT = int.from_bytes(bytes(BACKGROUND_COLOR_TOP), "big")
  51.  
  52. TITLE_TEXT = "DROP!"
  53. TITLE_BLOCK_SIZE = 10
  54. TITLE_BLOCK_MAX_EASE_FRAMES = 1 * FPS
  55. TITLE_BLOCK_OPACITY_STEP = 10
  56. TITLE_COLOR_TOP = [170, 156, 28]
  57. TITLE_COLOR_BOTTOM = [215, 111, 25]
  58.  
  59. PLATFORM_BLOCK_SIZE = 10
  60. PLATFORM_BLOCK_SIZE_HALF = int(PLATFORM_BLOCK_SIZE / 2)
  61. PLATFORM_BLOCK_WIDTH = 10
  62. PLATFORM_BLOCK_HEIGHT = 3
  63. PLATFORM_WIDTH = PLATFORM_BLOCK_WIDTH * PLATFORM_BLOCK_SIZE
  64. PLATFORM_HEIGHT = PLATFORM_BLOCK_HEIGHT  * PLATFORM_BLOCK_SIZE
  65. PLATFORM_WIDTH_HALF = int(PLATFORM_WIDTH / 2)
  66. PLATFORM_HEIGHT_HALF = int(PLATFORM_HEIGHT / 2)
  67. PLATFORM_OPACITY_STEP = 10
  68. PLATFORM_EXISTS_TIME = 3 # secs
  69. PLATFORM_CRUMBLE_TIME = PLATFORM_EXISTS_TIME / PLATFORM_BLOCK_HEIGHT
  70.  
  71. PLAYER_SIZE = 10
  72. PLAYER_SIZE_HALF = int(PLAYER_SIZE / 2)
  73. PLAYER_LIVES = 3
  74. PLAYER_FALL_SCORE_LOSS = 0.25
  75.  
  76. FOOD_SIZE = 10
  77. FOOD_SIZE_HALF = int(FOOD_SIZE / 2)
  78. FOOD_MAX_EASE_FRAMES = 1 * FPS
  79. FOOD_EXISTS_TIME = 20
  80. FOOD_BEACON_END_SIZE = 200
  81. FOOD_BEACON_DURATION = 0.5 # seconds
  82. FOOD_DEAD_SCORE_LOSS = 0.5
  83.  
  84. LIFE_COUNT = 3
  85. LIFE_SIZE = 20
  86. LIFE_SIZE_HALF = int(LIFE_SIZE / 2)
  87. LIFE_OPACITY_STEP = 5
  88.  
  89. SCORE_SCALE = 5
  90. SCORE_SPACING = 5
  91. SCORE_COLOR_TOP = [48, 57, 26]
  92. SCORE_COLOR_BOTTOM = [28, 45, 29]
  93. SCORE_COLOR_BOTTOM_START = 7
  94.  
  95. class player:
  96.     def __init__(s):
  97.         s.reset()
  98.  
  99.     def reset(s):
  100.         global PLATFORM_WIDTH_HALF
  101.  
  102.         s.x = 5 + PLATFORM_WIDTH_HALF
  103.         s.y = -10        
  104.         s.velocityY = 0
  105.         s.currentState = s.falling
  106.  
  107.     def horizontalKeys(s):
  108.         k = pygame.key.get_pressed()
  109.         if k[pygame.K_a]:
  110.             s.x -= 3
  111.         if k[pygame.K_d]:
  112.             s.x += 3
  113.  
  114.     def jumpingKey(s):
  115.         k = pygame.key.get_pressed()
  116.         if k[pygame.K_SPACE]:
  117.             s.velocityY = -10
  118.             s.currentState = s.jumping
  119.  
  120.     def jumping(s):
  121.         s.y += s.velocityY
  122.         s.velocityY += GRAVITY
  123.         if s.velocityY >= 0:
  124.             s.currentState = s.falling
  125.  
  126.     def falling(s):
  127.         global H
  128.         global GRAVITY
  129.         global SCORE, PLAYER_FALL_SCORE_LOSS
  130.  
  131.         s.y += s.velocityY
  132.         s.velocityY += GRAVITY
  133.         if s.y >= H:
  134.             SCORE.score -= SCORE.score * PLAYER_FALL_SCORE_LOSS
  135.             s.reset()
  136.  
  137.     def walking(s):
  138.         global PLATFORMS
  139.         global PLAYER_SIZE_HALF
  140.         s.jumpingKey()
  141.  
  142.         if s.x + PLAYER_SIZE_HALF < PLATFORMS.activePlatform.x1 or s.x - PLAYER_SIZE_HALF > PLATFORMS.activePlatform.x2:
  143.             PLATFORMS.activePlatform = None
  144.             s.currentState = s.falling
  145.  
  146.     def draw(s):
  147.         global DS
  148.         global ORANGE
  149.         global PLAYER_SIZE, PLAYER_SIZE_HALF
  150.  
  151.         pygame.draw.rect(DS, ORANGE, (s.x - PLAYER_SIZE_HALF, int(s.y - PLAYER_SIZE), PLAYER_SIZE, PLAYER_SIZE), 0)
  152.  
  153.     def do(s):
  154.         s.draw()
  155.         s.horizontalKeys()
  156.         s.currentState()
  157.  
  158. class platformBlock:
  159.     def __init__(s, x, y, w, staticTime):
  160.         s.x = x
  161.         s.y = y
  162.         s.w = w
  163.         s.velocity = 0
  164.         s.opacity = 255
  165.        
  166.         s.dead = False
  167.  
  168.         s.timeCreated = time.time()
  169.         s.staticTime = staticTime
  170.  
  171.     def draw(s):
  172.         global DS
  173.         global DOLIVE
  174.         global PLATFORM_BLOCK_SIZE
  175.  
  176.         pygame.gfxdraw.box(DS, (s.x, int(s.y), s.w, PLATFORM_BLOCK_SIZE), DOLIVE + [s.opacity])
  177.  
  178.     def move(s):
  179.         global H
  180.         global PLATFORM_OPACITY_STEP
  181.         global GRAVITY
  182.  
  183.         if time.time() - s.timeCreated < s.staticTime: return
  184.  
  185.         s.velocity += GRAVITY * 1.5
  186.         s.y += s.velocity
  187.         if s.y >= H:
  188.             s.dead = True
  189.         s.opacity -= PLATFORM_OPACITY_STEP
  190.         if s.opacity <= 0:
  191.             s.opacity = 0
  192.             s.dead = True
  193.  
  194.     def do(s):
  195.         s.draw()
  196.         s.move()
  197.  
  198. class platform:
  199.     def __init__(s, x, y):
  200.         global PLATFORM_BLOCK_HEIGHT
  201.         global PLATFORM_WIDTH_HALF
  202.  
  203.         s.timeStamp = time.time()
  204.        
  205.         s.x1 = x - PLATFORM_WIDTH_HALF
  206.         s.x2 = x + PLATFORM_WIDTH_HALF
  207.         s.y = y
  208.  
  209.         s.h = PLATFORM_BLOCK_HEIGHT
  210.  
  211.     def draw(s, c):
  212.         global DS
  213.         global PLATFORM_WIDTH
  214.         global PLATFORM_BLOCK_SIZE
  215.        
  216.         pygame.draw.rect(DS, c, (s.x1, s.y, PLATFORM_WIDTH, s.h * PLATFORM_BLOCK_SIZE), 0)
  217.  
  218. class platforms:
  219.     def __init__(s):
  220.         global H
  221.         global PLATFORM_WIDTH_HALF, PLATFORM_HEIGHT_HALF
  222.  
  223.         s.platforms = [platform(PLATFORM_WIDTH_HALF + 5, H - PLATFORM_HEIGHT_HALF - 5)]
  224.         s.blocks = []
  225.         s.activePlatform = None
  226.  
  227.     def do(s):
  228.         global DS
  229.         global DOLIVE, OLIVE
  230.         global PLATFORM_WIDTH, PLATFORM_HEIGHT
  231.         global PLATFORM_BLOCK_SIZE, PLATFORM_BLOCK_WIDTH
  232.         global PLAYER
  233.  
  234.         deadPlatforms = []
  235.        
  236.         for p in s.platforms: #container
  237.             if p != s.activePlatform:
  238.                 p.draw(DOLIVE)
  239.  
  240.             if p == s.platforms[0]: continue
  241.  
  242.             now = time.time()
  243.             if now - p.timeStamp >= PLATFORM_CRUMBLE_TIME:
  244.                 p.timeStamp = now
  245.                 p.h -= 1
  246.                 if p.h == 0:
  247.                     deadPlatforms.append(p)
  248.                     s.blocks.append(platformBlock(p.x1, p.y, PLATFORM_WIDTH, 0))
  249.                     if p == s.activePlatform and PLAYER.currentState == PLAYER.walking:
  250.                         PLAYER.currentState = PLAYER.falling
  251.                         s.activePlatform = None
  252.                 else:
  253.                     for index in range(PLATFORM_BLOCK_WIDTH):
  254.                         s.blocks.append(platformBlock(p.x1 + index * PLATFORM_BLOCK_SIZE, p.y + p.h * PLATFORM_BLOCK_SIZE, PLATFORM_BLOCK_SIZE, random.uniform(0, PLATFORM_CRUMBLE_TIME)))
  255.        
  256.         for dp in deadPlatforms:
  257.             s.platforms.remove(dp)
  258.  
  259.         deadBlocks = []
  260.         for b in s.blocks:
  261.             b.do()
  262.             if b.dead: deadBlocks.append(b)
  263.         for db in deadBlocks:
  264.             s.blocks.remove(db)
  265.  
  266.         if s.activePlatform:
  267.             s.activePlatform.draw(OLIVE)
  268.  
  269.     def add(s, posxy):
  270.         global PLATFORM_HEIGHT_HALF
  271.         s.platforms.append(platform(posxy[0], posxy[1] - PLATFORM_HEIGHT_HALF))
  272.  
  273.     def doCollision(s):
  274.         global H
  275.         global PLAYER
  276.        
  277.         if PLAYER.currentState != PLAYER.falling: return
  278.  
  279.         possiblePlatforms = []
  280.         for p in s.platforms:
  281.             if PLAYER.x >= p.x1 and PLAYER.x <= p.x2:
  282.                 if PLAYER.y <= p.y and PLAYER.y + PLAYER.velocityY >= p.y:
  283.                     possiblePlatforms.append(p)
  284.        
  285.         if not possiblePlatforms: return
  286.  
  287.         y = H
  288.         s.activePlatform = None
  289.  
  290.         for p in possiblePlatforms:
  291.             if p.y < y:
  292.                 s.activePlatform = p
  293.                 y = p.y
  294.  
  295.         PLAYER.y = y
  296.         PLAYER.velocityY = 0
  297.         PLAYER.currentState = PLAYER.walking
  298.  
  299. class food:
  300.     def __init__(s, x, y):
  301.         global H, HW
  302.         global FOOD_SIZE_HALF
  303.         global FOOD_MAX_EASE_TIME, FOOD_EXISTS_TIME
  304.  
  305.         s.x = x
  306.         s.y = -FOOD_SIZE_HALF
  307.         s.py = y
  308.        
  309.         fallInDuration = FOOD_MAX_EASE_FRAMES * (s.py / H)
  310.         s.fallIn = [-FOOD_SIZE_HALF + round(fallIn(fi, 0, s.py + FOOD_SIZE_HALF, fallInDuration)) for fi in range(int(fallInDuration) + 1)]
  311.         if s.fallIn[-1] != s.py: s.fallIn.append(s.py)
  312.         s.fallInIndex = 0
  313.  
  314.         dropOutTarget = (H + FOOD_SIZE_HALF - s.py)
  315.         dropOutDuration = FOOD_MAX_EASE_FRAMES * (dropOutTarget / H)
  316.         s.dropOut = [s.py + round(dropOut(fi, 0, dropOutTarget, dropOutDuration)) for fi in range(int(dropOutDuration) + 1)]
  317.         if s.dropOut[-1] != H + FOOD_SIZE_HALF: s.dropOut.append(H + FOOD_SIZE_HALF)
  318.         s.dropOutIndex = 0
  319.  
  320.         s.timeStamp = time.time()
  321.         s.ready = False
  322.         s.readyTime = None
  323.  
  324.         s.beaconTime = None
  325.         s.nextBeaconTime = int(FOOD_EXISTS_TIME / 2)
  326.  
  327.         s.dead = False
  328.  
  329.     def do(s):
  330.         global DS
  331.         global RED
  332.         global FOOD_SIZE, FOOD_SIZE_HALF
  333.         global FOOD_EXISTS_TIME
  334.         global FOOD_BEACON_END_SIZE, BEACONS
  335.         global SCORE, FOOD_DEAD_SCORE_LOSS
  336.  
  337.         pygame.draw.rect(DS, RED, (s.x - FOOD_SIZE_HALF, s.y - FOOD_SIZE_HALF, FOOD_SIZE, FOOD_SIZE), 0)
  338.  
  339.         now = time.time()
  340.  
  341.         if not s.ready:
  342.             s.y = s.fallIn[s.fallInIndex]
  343.             s.fallInIndex += 1
  344.             if s.fallInIndex == len(s.fallIn):
  345.                 s.ready = True
  346.                 s.readyTime = now
  347.                 s.beaconTime = s.readyTime
  348.                 BEACONS.add(s.x, s.y, FOOD_SIZE, FOOD_BEACON_END_SIZE, FOOD_BEACON_DURATION)
  349.             return
  350.  
  351.         if s.ready and now - s.readyTime > FOOD_EXISTS_TIME:
  352.             s.y = s.dropOut[s.dropOutIndex]
  353.             s.dropOutIndex += 1
  354.             if s.dropOutIndex == len(s.dropOut):
  355.                 s.dead = True
  356.                 SCORE.score -= SCORE.score * FOOD_DEAD_SCORE_LOSS
  357.  
  358.         else:
  359.             if now >= s.beaconTime + s.nextBeaconTime:
  360.                 s.beaconTime = now
  361.                 s.nextBeaconTime /= 2
  362.                 if s.nextBeaconTime < 0.25: s.nextBeaconTime = 0.25
  363.                 BEACONS.add(s.x, s.y, FOOD_SIZE, FOOD_BEACON_END_SIZE, FOOD_BEACON_DURATION)
  364.  
  365. class foods:
  366.     def __init__(s):
  367.         s.container = []
  368.         #s.add()
  369.  
  370.     def do(s):
  371.         global LIVES
  372.         deadFood = []
  373.         for f in s.container:
  374.             f.do()
  375.             if f.dead:
  376.                 deadFood.append(f)
  377.                 LIVES.loseLife()
  378.                 s.add()
  379.  
  380.         for df in deadFood:
  381.             s.container.remove(df)
  382.  
  383.     def add(s):
  384.         global W, H
  385.         global FOOD_SIZE_HALF
  386.         global SCORE
  387.  
  388.         s.container.append(food(random.randint(FOOD_SIZE_HALF, W - FOOD_SIZE_HALF), random.randint(0, H)))
  389.  
  390.     def doCollision(s):
  391.         global PLAYER, PLAYER_SIZE_HALF
  392.         global FOOD_SIZE_HALF
  393.  
  394.         removeFood = []
  395.         for f in s.container:
  396.             if PLAYER.x - PLAYER_SIZE_HALF > f.x + FOOD_SIZE_HALF or PLAYER.x + PLAYER_SIZE_HALF < f.x - FOOD_SIZE_HALF \
  397.             or PLAYER.y - PLAYER_SIZE_HALF > f.y + FOOD_SIZE_HALF or PLAYER.y + PLAYER_SIZE_HALF < f.y - FOOD_SIZE_HALF:
  398.                 pass
  399.             else:
  400.                 #print(time.time() - f.timeStamp)
  401.                 SCORE.score += time.time() - f.timeStamp
  402.                 removeFood.append(f)
  403.        
  404.         for rf in removeFood:
  405.             s.container.remove(rf)
  406.             s.add()
  407.  
  408. class beacon:
  409.     def __init__(s, x, y, startSize, endSize, time):
  410.         global FPS
  411.  
  412.         s.x = x
  413.         s.y = y
  414.  
  415.         frameCount = FPS * time
  416.         s.growData = [startSize + round(fallIn(fi, 0, endSize, frameCount)) for fi in range(int(frameCount) + 1)]
  417.         if s.growData[-1] != endSize: s.growData.append(endSize)          
  418.         s.growIndex = 0
  419.  
  420.         s.opacityStep = 64 / frameCount
  421.  
  422.         s.dead = False
  423.    
  424.     def do(s):
  425.         global DS
  426.         global BEACON_COLOR
  427.  
  428.         size = int(s.growData[s.growIndex] / 2)
  429.         pygame.gfxdraw.box(DS, (s.x - size, s.y - size, size * 2, size * 2), BEACON_COLOR + [int(64 +s.opacityStep - s.opacityStep * s.growIndex)])
  430.  
  431.         s.growIndex += 1
  432.         if s.growIndex == len(s.growData):
  433.             s.dead = True
  434.  
  435. class beacons:
  436.     def __init__(s):
  437.         s.container = []
  438.  
  439.     def add(s, x, y, startSize, endSize, time):
  440.         s.container.append(beacon(x, y, startSize, endSize, time))
  441.  
  442.     def do(s):
  443.         deadBeacons = []
  444.         for b in s.container:
  445.             b.do()
  446.             if b.dead: deadBeacons.append(b)
  447.         for db in deadBeacons:
  448.             s.container.remove(db)
  449.  
  450. class life:
  451.     def __init__(s, x):
  452.         global LIFE_SIZE_HALF
  453.        
  454.         s.x = x
  455.         s.y = 5 + LIFE_SIZE_HALF
  456.         s.velocity = 0
  457.         s.opacity = 255
  458.  
  459.         s.dead = False
  460.         s.remove = False
  461.  
  462.     def do(s):
  463.         global DS
  464.         global PURPLE
  465.         global LIFE_SIZE, LIFE_SIZE_HALF
  466.         global LIFE_OPACITY_STEP
  467.        
  468.         pygame.gfxdraw.box(DS, (s.x - LIFE_SIZE_HALF, int(s.y - LIFE_SIZE_HALF), LIFE_SIZE, LIFE_SIZE), PURPLE + [s.opacity])
  469.        
  470.         if not s.dead: return
  471.        
  472.         s.opacity -= LIFE_OPACITY_STEP
  473.         s.y += s.velocity
  474.         s.velocity += GRAVITY
  475.         if s.opacity <=0: s.remove = True
  476.  
  477. class lives:
  478.     def __init__(s):
  479.         global W
  480.         global LIFE_COUNT
  481.         global LIFE_SIZE, LIFE_SIZE_HALF        
  482.  
  483.         s.lives = [life(W +  LIFE_SIZE_HALF - (x * (LIFE_SIZE + 5))) for x in range(LIFE_COUNT, 0, -1)]
  484.  
  485.     def do(s):
  486.         removeLives = []
  487.         for l in s.lives:
  488.             l.do()
  489.             if l.remove:
  490.                 removeLives.append(l)
  491.         for rl in removeLives:
  492.             s.lives.remove(rl)
  493.  
  494.     def loseLife(s):
  495.         global game_over
  496.         liveCount = len(s.lives)
  497.  
  498.         for l in s.lives:
  499.             liveCount -=1
  500.             if l.dead: continue
  501.             l.dead = True
  502.             break
  503.        
  504.         if liveCount == 0:
  505.             game_over = True
  506.  
  507.  
  508. class bkgdPoint:
  509.     def __init__(s, x):
  510.         global HH
  511.         s.p = [x, 0]
  512.         s.r = random.randint(50, HH - 50)
  513.         s.a = random.uniform(0, 6.283185307179586)
  514.         s.s = random.uniform(0.01, 0.035)
  515.  
  516.     def calc(s):
  517.         global HH
  518.         s.p[1] = HH + int(math.cos(s.a) * s.r)
  519.         s.a += s.s
  520.        
  521. class background:
  522.     def __init__(s):
  523.         global W, H
  524.  
  525.         s.points = [bkgdPoint(x) for x in range(0, W, int(W / 10))] + [bkgdPoint(W)]
  526.         s.poly1 = [[W, 0], [0, 0]] + [bp.p for bp in s.points]
  527.         s.poly2 = [[W, H], [0, H]] + [bp.p for bp in s.points]
  528.  
  529.     def draw(s):
  530.         global DS
  531.         global BACKGROUND_COLOR_TOP, BACKGROUND_COLOR_BOTTOM
  532.  
  533.         pygame.draw.polygon(DS, BACKGROUND_COLOR_TOP, s.poly1)
  534.         pygame.draw.polygon(DS, BACKGROUND_COLOR_BOTTOM, s.poly2)
  535.  
  536.     def do(s):
  537.         for bp in s.points: bp.calc()
  538.         s.draw()
  539.  
  540. class font:
  541.     def __init__(s, img, charMap, spacing):
  542.         s.surface = img
  543.         s.surfaceWidth, s.surfaceHeight = img.get_size()
  544.         s.cols = len(charMap)
  545.         s.charWidth = int(s.surfaceWidth / s.cols)
  546.  
  547.         s.spacing = spacing
  548.  
  549.         s.charMap = charMap
  550.  
  551.     def textSurface(s, text, scale = None):
  552.         surfaceWidth = len(text) * s.charWidth + s.spacing * (len(text) - 1)
  553.         surface = pygame.Surface((surfaceWidth, s.surfaceHeight))
  554.        
  555.         charPosX = 0
  556.         for c in text:
  557.             charIndex = s.charMap.find(c)
  558.             if charIndex == -1:
  559.                 charPosX += s.charWidth + s.spacing
  560.                 continue
  561.            
  562.             charOffsetX = charIndex * s.charWidth
  563.  
  564.             surface.blit(s.surface, (charPosX, 0), (charOffsetX, 0, s.charWidth, s.surfaceHeight))
  565.             charPosX += s.charWidth + s.spacing
  566.  
  567.         if scale != None:
  568.             return pygame.transform.scale(surface, (surfaceWidth * scale, s.surfaceHeight * scale))
  569.        
  570.         return surface
  571.  
  572.     def size(s, text):
  573.         return (len(text) * s.charWidth + s.spacing * (len(text) - 1), s.surfaceHeight)
  574.  
  575. class titleBlock:
  576.     def __init__(s, x, y):
  577.         global H        
  578.         global BACKGROUND_COLOR_TOP
  579.         global TITLE_BLOCK_SIZE
  580.         global TITLE_BLOCK_MAX_EASE_FRAMES
  581.  
  582.         s.x = x
  583.         s.y = -TITLE_BLOCK_SIZE
  584.         s.py = y
  585.  
  586.         fallInDuration = TITLE_BLOCK_MAX_EASE_FRAMES * (y / H)
  587.         s.fallIn = [-TITLE_BLOCK_SIZE + round(fallIn(fi, 0, y + TITLE_BLOCK_SIZE, fallInDuration)) for fi in range(int(fallInDuration) + 1)]
  588.         if s.fallIn[-1] != y: s.fallIn.append(y)
  589.         s.fallInIndex = 0
  590.  
  591.         s.staticTime = random.uniform(3, 5)
  592.         s.timeStamp = None
  593.  
  594.         s.velocity = 0
  595.        
  596.         s.color = BACKGROUND_COLOR_TOP
  597.         s.opacity = 255
  598.  
  599.         s.dead = False
  600.  
  601.     def do(s):
  602.         global DS
  603.         global WHITE
  604.         global GRAVITY
  605.         global TITLE_BLOCK_SIZE
  606.         global TITLE_BLOCK_OPACITY_STEP
  607.  
  608.         if s.dead: return
  609.  
  610.         pygame.gfxdraw.box(DS, (s.x, int(s.y), TITLE_BLOCK_SIZE, TITLE_BLOCK_SIZE), s.color + [s.opacity])
  611.  
  612.         if s.fallInIndex < len(s.fallIn):
  613.             s.y = s.fallIn[s.fallInIndex]
  614.             s.fallInIndex += 1
  615.         elif s.timeStamp == None:
  616.             s.timeStamp = time.time()
  617.        
  618.         if s.timeStamp == None: return
  619.  
  620.         if time.time() >= s.timeStamp + s.staticTime:
  621.             s.y += s.velocity
  622.             s.velocity += GRAVITY
  623.             s.opacity -= TITLE_BLOCK_OPACITY_STEP
  624.             if s.opacity <= 0:
  625.                 s.dead = True
  626.  
  627.     def reset(s):
  628.         global BACKGROUND_COLOR_TOP
  629.         global TITLE_BLOCK_SIZE
  630.         s.y = -TITLE_BLOCK_SIZE
  631.         s.fallInIndex = 0
  632.         s.timeStamp = None
  633.         s.velocity = 0
  634.         s.opacity = 255
  635.         s.color = BACKGROUND_COLOR_TOP
  636.         s.dead = False
  637.  
  638. class titleBlocks:
  639.     def __init__(s):
  640.         global HW, HH
  641.         global FONT
  642.         global TITLE_TEXT
  643.         global TITLE_BLOCK_SIZE
  644.  
  645.         FONT.spacing = 4
  646.         titleSurface = FONT.textSurface(TITLE_TEXT)
  647.         w, h = FONT.size(TITLE_TEXT)
  648.         FONT.spacing = 1
  649.        
  650.         cx = HW - int(w / 2) * TITLE_BLOCK_SIZE
  651.         cy = HH - int(h / 2) * TITLE_BLOCK_SIZE
  652.  
  653.         s.allDead = False
  654.         s.container = []
  655.  
  656.         pixelArray = pygame.PixelArray(titleSurface)
  657.         for x in range(w):
  658.             for y in range(h):
  659.                 if pixelArray[x][y] != 0:
  660.                     s.container.append(titleBlock(cx + x * TITLE_BLOCK_SIZE, cy + y * TITLE_BLOCK_SIZE))
  661.         pixelArray.close()
  662.  
  663.     def do(s):
  664.         global DS
  665.         global BACKGROUND_COLOR_TOP_INT
  666.         global TITLE_COLOR_TOP, TITLE_COLOR_BOTTOM
  667.  
  668.         pa = pygame.PixelArray(DS)
  669.         for tb in s.container:
  670.             colorInt = pa[tb.x][int(tb.y)]
  671.             if colorInt == BACKGROUND_COLOR_TOP_INT:
  672.                 tb.color = TITLE_COLOR_TOP
  673.             else:
  674.                 tb.color = TITLE_COLOR_BOTTOM
  675.         pa.close()
  676.  
  677.         s.deadCount = 0
  678.         for tb in s.container:
  679.             if s.allDead:
  680.                 tb.reset()
  681.             tb.do()
  682.             if tb.dead: s.deadCount += 1
  683.         if s.deadCount == len(s.container):
  684.             s.allDead = True
  685.         else:
  686.             s.allDead = False
  687.  
  688. class score:
  689.     def __init__(s):
  690.         global FONT_CHARMAP
  691.         global SCORE_COLOR_TOP, SCORE_COLOR_BOTTOM, SCORE_COLOR_BOTTOM_START
  692.  
  693.         s.reset()
  694.        
  695.         s.font = font(imgUnzip(FONT_DATA, (BLACK, SCORE_COLOR_TOP)), FONT_CHARMAP, 1)
  696.         scoreColorBottom = s.font.surface.map_rgb(SCORE_COLOR_BOTTOM)
  697.  
  698.         pa = pygame.PixelArray(s.font.surface)
  699.         for y in range(SCORE_COLOR_BOTTOM_START, s.font.surfaceHeight):
  700.             for x in range(s.font.surfaceWidth):
  701.                 if pa[x][y] != 0:
  702.                     pa[x][y] = scoreColorBottom
  703.         pa.close()
  704.  
  705.     def reset(s):
  706.         s.score = 0
  707.         s.x = 0
  708.         s.y = 0
  709.         s.prevScore = -1
  710.  
  711.     def draw(s):
  712.         global DS
  713.         global W, H
  714.         global BLACK
  715.         global SCORE_SCALE, SCORE_SPACING
  716.  
  717.         if s.prevScore != s.score:
  718.             if s.score < 0: s.score = 0
  719.             s.prevScore = s.score
  720.             s.scoreSurface = s.font.textSurface(str(round(s.score, 2)), SCORE_SCALE)
  721.             s.scoreSurface.set_colorkey(0)
  722.             s.scoreSurfaceWidth, s.scoreSurfaceHeight = s.scoreSurface.get_size()
  723.             s.x = W - SCORE_SPACING - s.scoreSurfaceWidth
  724.             s.y = H - SCORE_SPACING - s.scoreSurfaceHeight
  725.  
  726.         DS.blit(s.scoreSurface, (s.x, s.y))
  727.  
  728. def imgUnzip(z64, colors):
  729.     colorList = [(colors[0][0] << 16) + (colors[0][1] << 8) + colors[0][2], (colors[1][0] << 16) + (colors[1][1] << 8) + colors[1][2]]
  730.     data = zlib.decompress(base64.b64decode(z64))
  731.     w = int.from_bytes(data[0:2], "big")
  732.     h = int.from_bytes(data[2:4], "big")
  733.  
  734.     surface = pygame.Surface((w, h))
  735.     pixelArray = pygame.PixelArray(surface)
  736.     pixelOffset = 0
  737.     colorIndex = 0
  738.  
  739.     for byteIndex in range(4, len(data)):
  740.         colorLength = data[byteIndex]
  741.         for index in range(colorLength + 1):
  742.             x = pixelOffset % w
  743.             y = int(pixelOffset / w)
  744.             pixelOffset += 1
  745.             pixelArray[x][y] = colorList[colorIndex]
  746.        
  747.         if colorLength != 255:
  748.             colorIndex = 1 - colorIndex
  749.  
  750.     pixelArray.close()
  751.  
  752.     return surface
  753. def fallIn(frameIndex, offset, target, duration):
  754.     frameIndex /= duration
  755.     frameIndex -= 1
  756.     return target * (frameIndex * frameIndex * frameIndex * frameIndex * frameIndex + 1) + offset
  757.  
  758. def dropOut(frameIndex, offset, target, duration):
  759.     frameIndex /= duration
  760.     return target * frameIndex * frameIndex + offset
  761.  
  762. def drawDashedVLine(surface, color, x, y, height, dashLength):
  763.     for lineY in range(0, height, dashLength * 2):
  764.         pygame.draw.line(surface, color, (x, y + lineY), (x, y + lineY + dashLength), 1)
  765.  
  766. def drawDashedHLine(surface, color, x, y, width, dashLength):
  767.     for lineX in range(0, width, dashLength * 2):
  768.         pygame.draw.line(surface, color, (x + lineX, y), (x + lineX + dashLength, y), 1)
  769.  
  770. def events():
  771.     for event in pygame.event.get():
  772.         if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
  773.             pygame.quit()
  774.             sys.exit()
  775.  
  776. def drawPlatformCursor():
  777.     global DS
  778.     global GRAY
  779.     global PLATFORM_WIDTH, PLATFORM_HEIGHT, PLATFORM_WIDTH_HALF, PLATFORM_HEIGHT_HALF
  780.  
  781.     mx, my = pygame.mouse.get_pos()
  782.  
  783.     drawDashedHLine(DS, GRAY, mx - PLATFORM_WIDTH_HALF,  my - PLATFORM_HEIGHT_HALF, PLATFORM_WIDTH, 4)
  784.     drawDashedHLine(DS, GRAY, mx - PLATFORM_WIDTH_HALF,  my + PLATFORM_HEIGHT_HALF, PLATFORM_WIDTH, 4)
  785.     drawDashedVLine(DS, GRAY, mx - PLATFORM_WIDTH_HALF, my - PLATFORM_HEIGHT_HALF, PLATFORM_HEIGHT, 4)
  786.     drawDashedVLine(DS, GRAY, mx + PLATFORM_WIDTH_HALF, my - PLATFORM_HEIGHT_HALF, PLATFORM_HEIGHT, 4)
  787.  
  788. def title():
  789.     global BACKGROUND, TITLE, CLOCK
  790.     events()
  791.     BACKGROUND.do()
  792.     TITLE.do()
  793.     pygame.display.update()
  794.     CLOCK.tick(FPS)    
  795.  
  796. # Initialise screen centering
  797. if sys.platform == 'win32' or sys.platform == 'win64':
  798.     os.environ['SDL_VIDEO_CENTERED'] = '1'    
  799.  
  800. # Initialise Pygame
  801. pygame.init()
  802. DS = pygame.display.set_mode((W, H), pygame.NOFRAME)
  803. CLOCK = pygame.time.Clock()
  804.  
  805. # set random seed
  806. random.seed(3767) # 3767 = DROP on telephone keypad
  807.  
  808. # Set up game entities
  809. FONT_SURFACE = imgUnzip(FONT_DATA, (BLACK, WHITE))
  810. FONT = font(FONT_SURFACE, FONT_CHARMAP, 1)
  811.  
  812. SCORE = score()
  813. PLATFORMS = platforms()
  814. PLAYER = player()
  815. BACKGROUND = background()
  816. TITLE = titleBlocks()
  817. FOOD = foods()
  818. LIVES = lives()
  819. BEACONS = beacons()
  820.  
  821. # Game variables
  822. mouseClick = False
  823. game_over = False
  824.  
  825. # Main loop
  826. while True:
  827.     while not pygame.mouse.get_pressed()[0]:
  828.         title()
  829.     while pygame.mouse.get_pressed()[0]:
  830.         title()
  831.    
  832.     FOOD.add()
  833.  
  834.     while not game_over or len(LIVES.lives):
  835.         events()
  836.         mb = pygame.mouse.get_pressed()
  837.         if mb[0] and not mouseClick:
  838.             PLATFORMS.add(pygame.mouse.get_pos())
  839.             SCORE.score -= 0.1
  840.             mouseClick = True
  841.         if not mb[0] and mouseClick:
  842.             mouseClick = False
  843.  
  844.         BACKGROUND.do()
  845.         SCORE.draw()
  846.         BEACONS.do()
  847.         drawPlatformCursor()
  848.         PLATFORMS.do()
  849.         LIVES.do()
  850.         PLAYER.do()
  851.         FOOD.do()
  852.        
  853.         PLATFORMS.doCollision()
  854.         FOOD.doCollision()
  855.  
  856.         pygame.display.update()
  857.         CLOCK.tick(FPS)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement