Advertisement
cookertron

Drop Out! Version 0.7

Jan 28th, 2020
327
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 54.44 KB | None | 0 0
  1. # Code by Anthony Cook
  2. # fb.com/groups/pygame
  3.  
  4. # TESTER NOTES:
  5. # use 'a' and 'd' to more the character left and right
  6. # 'space' to jump
  7. # mouse and left mouse button to place platforms
  8.  
  9. import pygame
  10. import pygame.gfxdraw
  11. import sys, os, time, math, random
  12. import collections
  13. import lzma, base64
  14.  
  15. # Pygame contants
  16. W = 1280
  17. H = 720
  18. HW = int(W / 2)
  19. HH = int(H / 2)
  20. FPS = 60
  21.  
  22. # Define some colors
  23. FUCHSIA = [255,   0, 255]
  24. PURPLE  = [128,   0, 128]
  25. TEAL    = [  0, 128, 128]
  26. LIME    = [  0, 255,   0]
  27. GREEN   = [  0, 128,   0]
  28. OLIVE   = [128, 128,   0]
  29. DOLIVE  = [ 64,  64,   0]
  30. YELLOW  = [255, 255,   0]
  31. ORANGE  = [255, 165,   0]
  32. RED     = [255,   0,   0]
  33. MAROON  = [128,   0,   0]
  34. SILVER  = [192, 192, 192]
  35. GRAY    = [128, 128, 128]
  36. BLUE    = [  0,   0, 255]
  37. NAVY    = [  0,   0, 128]
  38. AQUA    = [  0, 255, 255]
  39. WHITE   = [255, 255, 255]
  40. BLACK   = [  0,   0,   0]
  41.  
  42. FONT_DATA = b'/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4Aw9AW5dAACO8kOjEfa2JjD81EffSaUPknD93Eph1Fsy7hNTgvcZJxKO8vuqgc3XN\
  43. 3Lz2F/+rT9w9iuzsmBXzqTvbkREQ7Io0T/ALfy6MU/6BR7cC0iyLG9bk6y+A7e4DJDb86aloX9r2qeu1DnBUOu7ie8Y+Z8hOQg9rNd4bu5wlIPL\
  44. UIejdSo0RcIJiS5w1xmTlmFEI8n7isSpL+Zl3NNk/Hgrd+ajfx+dJ2r/+ENsaRYWNLJ8ZRkUMl3ECYmC9pzK5cMH9EZ/CTJLhNIFZq3EpapLc7+\
  45. dRZOMN3uxtEshysWcJJHip5CTAkjAoFbu4Tl0J8gtke66of1u/gv69rGbru0lbd0eY5MdQfHs1U1WtrBgJ7Di9mSu7h1YHvm07W8DhcOkb26+NG\
  46. 0/kV7JyQMczTE6VV6qN2FAK8JnjpkCh40xg63Dxi2m7N3JiKvl1tE/gPOvSJkGQIus7HQFHXjc6DouLaw3zh81ra8HDg4ZRQAvLAAAALI4wzJkk\
  47. ZgtAAGKA74YAADSUkbUscRn+wIAAAAABFla'
  48. FONT_CHARMAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.!-"
  49.  
  50. GRAVITY = 0.5
  51.  
  52. def gradient(rgb1, rgb2, frames):
  53.     rStep = (rgb2[0] - rgb1[0]) / frames
  54.     gStep = (rgb2[1] - rgb1[1]) / frames
  55.     bStep = (rgb2[2] - rgb1[2]) / frames
  56.     return [[int(rgb1[0] + rStep * i), int(rgb1[1] + gStep * i), int(rgb1[2] + bStep * i)] for i in range(frames)] + [rgb2]
  57.  
  58. def imgUnzip(lz64):
  59.     data = lzma.decompress(base64.b64decode(lz64))
  60.  
  61.     imageW = int.from_bytes(data[0:2], "big")
  62.     imageH = int.from_bytes(data[2:4], "big")
  63.     paletteLength = int.from_bytes(data[4:5], "big")
  64.     palette = [int.from_bytes(data[5 + index * 3:8 + index * 3], "big") for index in range(paletteLength)]
  65.     pixelDataStart = 5 + paletteLength * 3    
  66.  
  67.     surface = pygame.Surface((imageW, imageH))    
  68.     pixelArray = pygame.PixelArray(surface)
  69.    
  70.     for index in range(0, len(data) - pixelDataStart):
  71.         pixelArray[index % imageW][int(index / imageW)] = palette[data[pixelDataStart + index]]
  72.  
  73.     pixelArray.close()
  74.     del pixelArray
  75.     return surface
  76.  
  77. class gameTime:
  78.     def __init__(s, fps):
  79.         s.timeStamp = time.time()
  80.         s.time = 0
  81.         s.fps = fps
  82.         s.tpf = 1 / fps
  83.         s.paused = False
  84.    
  85.     def secs(s, seconds):
  86.         return s.fps * seconds
  87.  
  88.     def tick(s):
  89.         while time.time() - s.timeStamp < s.tpf:
  90.             pass
  91.         s.timeStamp = time.time()
  92.         if not s.paused:
  93.             s.time += 1
  94.  
  95. class event:
  96.     def __init__(s, obj, start, interval, maxCount):
  97.         s.obj = obj
  98.         s.start = start
  99.         s.interval = interval
  100.         s.maxCount = maxCount
  101.         s.count = 0
  102.  
  103. class rect:
  104.     def __init__(s, rect, active = True):
  105.         s.x = rect[0]
  106.         s.y = rect[1]
  107.         s.w = rect[2]
  108.         s.h = rect[3]
  109.         s.active = active
  110.         s.collisionActive = True
  111.         s.dead = False
  112.  
  113.     def setXY(s, coords):
  114.         s.x = coords[0]
  115.         s.y = coords[1]
  116.  
  117.     def testObj(s, obj):
  118.         if s.x <= obj.RECT.x2() and s.x2() >= obj.RECT.x and s.y <= obj.RECT.y2() and s.y2() >= obj.RECT.y:
  119.             return True
  120.         return False
  121.  
  122.     def testRect(s, rect):
  123.         if s.x <= rect[0] + rect[2] and s.x2() >= rect[0] and s.y <= rect[1] + rect[3] and s.y2() >= rect[1]:
  124.             return True
  125.         return False
  126.  
  127.     def testEdges(s, obj, fXY):
  128.         for edgeIndex in range(4):
  129.             if not obj.EDGE_COLLISION[edgeIndex]: continue
  130.             if edgeIndex == 0:
  131.                 if s.y2() <= obj.RECT.y and fXY[1] + s.h >= obj.RECT.y and s.x2() >= obj.RECT.x and s.x <= obj.RECT.x2():
  132.                     return 0
  133.             elif edgeIndex == 1:
  134.                 if s.x >= obj.RECT.x2() and fXY[0] < obj.RECT.x2() and s.y2() >= obj.RECT.y and s.y <= obj.RECT.y2():
  135.                     return 1
  136.             elif edgeIndex == 2:
  137.                 if s.y >= obj.RECT.y2() and fXY[1] <= obj.RECT.y2() and s.x2() >= obj.RECT.x and s.x <= obj.RECT.x2():
  138.                     return 2
  139.             elif edgeIndex == 3:
  140.                 if s.x2() <= obj.RECT.x and fXY[0] + s.w >= obj.RECT.x and s.y2() >= obj.RECT.y and s.y <= obj.RECT.y2():
  141.                     return 3
  142.         return None
  143.  
  144.     def intRect(s):
  145.         return [int(s.x), int(s.y), int(s.w), int(s.h)]
  146.    
  147.     def intXY(s):
  148.         return [int(s.x), int(s.y)]
  149.  
  150.     def x1(s):
  151.         return int(s.x)
  152.    
  153.     def y1(s):
  154.         return int(s.y)
  155.  
  156.     def x2(s):
  157.         return int(s.x + s.w)
  158.  
  159.     def y2(s):
  160.         return int(s.y + s.h)
  161.  
  162.     def intXYOffset(s, x, y):
  163.         return [int(s.x + x), int(s.y + y)]
  164.    
  165.     def center(s):
  166.         return [int(s.x + s.w / 2), int(s.y + s.h / 2)]
  167.    
  168.     def xCenter(s):
  169.         return int(s.x + s.w / 2)
  170.    
  171.     def yCenter(s):
  172.         return int(s.y + s.h / 2)
  173.    
  174. class stage:
  175.     class placeHolder:
  176.         ID = "placeholder"
  177.         def __init__(s, r, ownID):
  178.             s.RECT = rect(r)
  179.             s.ownerID = ownID
  180.  
  181.     def reset(s):
  182.         s.timeStamp = s.time.time
  183.         s.paused = False
  184.         s.score = 0
  185.         s.previousScore = 0
  186.         s.lives = 0
  187.         s.gameOver = False        
  188.  
  189.         s.tempAddObjects = []
  190.         s.tempRemoveObjects = []
  191.  
  192.         s.container = []
  193.         s.objectCounts = {}
  194.         s.timeEvents = []
  195.         s.scoreEvents = []
  196.         s.layers = collections.OrderedDict()
  197.  
  198.         s.setupLayers()
  199.         s.setupObjects()
  200.  
  201.     def setupLayers(s):
  202.         for name in s.layerNames:
  203.             s.layers[name] = []
  204.  
  205.     def setupObjects(s):
  206.         for obj in s.objects:
  207.             if hasattr(obj, "LAYER") and hasattr(obj, "ADD_IMMEDIATELY"):
  208.                 newObj = obj(s)
  209.                 s.layers[obj.LAYER].append(newObj)
  210.                 s.container.append(newObj)
  211.                 s.objectCounts[newObj.ID] = 1
  212.             if hasattr(obj, "TIME_EVENT"):
  213.                 s.timeEvents.append(event(obj, obj.EVENT_START, obj.EVENT_INTERVAL, obj.EVENT_MAXCOUNT))
  214.             if hasattr(obj, "SCORE_EVENT"):
  215.                 s.scoreEvents.append(event(obj, obj.EVENT_START, obj.EVENT_INTERVAL, obj.EVENT_MAXCOUNT))
  216.  
  217.     def setFont(s, font):
  218.         s.font = font
  219.    
  220.     def setObjects(s, objects):
  221.         s.objects = objects
  222.  
  223.     def setTimer(s, gameTimeObject):
  224.         s.time = gameTimeObject
  225.  
  226.     def setLayers(s, layerNames):
  227.         s.layerNames = layerNames
  228.  
  229.     def setAllVars(s, font, layerNames, objects, gameTimeObject):
  230.         s.font = font
  231.         s.layerNames = layerNames
  232.         s.objects = objects
  233.         s.time = gameTimeObject
  234.  
  235.     def do(s):
  236.         s.draw()
  237.         s.time.tick()
  238.         s.move()
  239.         s.purgeObjects()
  240.         s.collisions()
  241.         s.events()
  242.         s.addObjects()
  243.  
  244.     def draw(s):
  245.         for layer in s.layers:
  246.             for obj in s.layers[layer]:
  247.                 if obj.RECT.active:
  248.                     obj.draw()
  249.         pygame.display.update()
  250.  
  251.     def move(s):
  252.         for layer in s.layers:
  253.             for obj in s.layers[layer]:
  254.                 if obj.RECT.active:
  255.                     if not s.paused:
  256.                         obj.do(s)
  257.                     elif hasattr(obj, "DO_WHILE_PAUSED"):
  258.                         obj.do(s)
  259.                     if obj.RECT.dead: s.tempRemoveObjects += [obj]
  260.  
  261.     def collisions(s):
  262.         for obj in s.container:
  263.             if obj.RECT.active and obj.RECT.collisionActive and not obj.RECT.dead and hasattr(obj, 'COLLISION_DETECTION'):
  264.                 for colObj in s.container:
  265.                     if obj != colObj and colObj.RECT.active and not colObj.RECT.dead and colObj.RECT.collisionActive:
  266.                         if hasattr(colObj, 'EDGE_COLLISION'):
  267.                             edgeIndex = obj.RECT.testEdges(colObj, obj.futureMove())
  268.                             if edgeIndex != None:
  269.                                 obj.collision(s, colObj, edgeIndex)
  270.                         else:
  271.                             if obj.RECT.testObj(colObj):
  272.                                 obj.collision(s, colObj)                        
  273.  
  274.     def events(s):
  275.         now = s.time.time
  276.         for timeEvent in s.timeEvents:
  277.             if now < timeEvent.start: continue
  278.             if now == timeEvent.start or (now - timeEvent.start) % timeEvent.interval == timeEvent.interval - 1:
  279.                 if s.objectCounts[timeEvent.obj.ID] < timeEvent.maxCount:
  280.                     s.addObject(timeEvent.obj(s))
  281.  
  282.         for scoreEvent in s.scoreEvents:
  283.             if s.score < scoreEvent.start: continue
  284.             if s.score >= scoreEvent.start and not scoreEvent.count:
  285.                 scoreEvent.count += 1
  286.                 s.addObject(scoreEvent.obj(s))
  287.             elif (s.score - scoreEvent.start) >= scoreEvent.interval * scoreEvent.count and s.objectCounts[scoreEvent.obj.ID] < scoreEvent.maxCount:
  288.                 s.addObject(scoreEvent.obj(s))
  289.                 scoreEvent.count += 1
  290.  
  291.     def purgeObjects(s):
  292.         while s.tempRemoveObjects:
  293.             obj = s.tempRemoveObjects.pop()
  294.             s.container.remove(obj)
  295.             s.objectCounts[obj.ID] -= 1
  296.             if hasattr(obj, "LAYER"):
  297.                 s.layers[obj.LAYER].remove(obj)
  298.  
  299.     def addObjects(s):
  300.         while s.tempAddObjects:
  301.             obj = s.tempAddObjects.pop()
  302.             s.container.append(obj)
  303.             if obj.ID in s.objectCounts:
  304.                 s.objectCounts[obj.ID] += 1
  305.             else:
  306.                 s.objectCounts[obj.ID] = 1
  307.             if hasattr(obj, "LAYER"):
  308.                 s.layers[obj.LAYER].append(obj)
  309.  
  310.     def addObject(s, obj):
  311.         s.tempAddObjects.append(obj)
  312.         return obj
  313.    
  314.     def addPlaceHolder(s, rect, id):
  315.         obj = s.placeHolder(rect, id)
  316.         s.tempAddObjects.append(obj)
  317.         return obj
  318.    
  319.     def delPlaceHolder(s, ph):
  320.         s.tempRemoveObjects.append(ph)
  321.  
  322.     # rect is potential location for object s = stage
  323.     def testAllRect(s, rect, invalidIDs = [], validIDs = []):
  324.         for colObj in s.container:
  325.             if colObj.ID in invalidIDs or not colObj.RECT.active or colObj.RECT.dead or not colObj.RECT.collisionActive: continue
  326.             if validIDs:
  327.                 if colObj.ID in validIDs:
  328.                     if colObj.RECT.testRect(rect): return True
  329.             else:
  330.                 if colObj.RECT.testRect(rect): return True
  331.         return False
  332.  
  333. class font:
  334.     def __init__(s, img, charMap, spacing):
  335.         s.surfaceWidth, s.surfaceHeight = img.get_size()
  336.  
  337.         s.fontSurface = img.copy()
  338.         s.monochromeFonts = {}
  339.  
  340.         s.cols = len(charMap)
  341.         s.charWidth = int(s.surfaceWidth / s.cols)
  342.  
  343.         s.spacing = spacing
  344.  
  345.         s.charMap = charMap
  346.  
  347.     def text(s, text, scale = None, colorName = None):
  348.         surfaceWidth = len(text) * s.charWidth + s.spacing * (len(text) - 1)
  349.         surface = pygame.Surface((surfaceWidth, s.surfaceHeight))
  350.        
  351.         charPosX = 0
  352.         for c in text:
  353.             charIndex = s.charMap.find(c)
  354.             if charIndex == -1:
  355.                 charPosX += s.charWidth + s.spacing
  356.                 continue
  357.            
  358.             charOffsetX = charIndex * s.charWidth
  359.  
  360.             if colorName:
  361.                 surface.blit(s.monochromeFonts[colorName], (charPosX, 0), (charOffsetX, 0, s.charWidth, s.surfaceHeight))
  362.             else:
  363.                 surface.blit(s.fontSurface, (charPosX, 0), (charOffsetX, 0, s.charWidth, s.surfaceHeight))
  364.             charPosX += s.charWidth + s.spacing
  365.  
  366.         if scale != None:
  367.             return pygame.transform.scale(surface, (surfaceWidth * scale, s.surfaceHeight * scale))
  368.        
  369.         return surface
  370.  
  371.     def newMonochromeFont(s, name, color):
  372.         global DS
  373.         monochromeSurface = s.fontSurface.copy()
  374.         monochromePA = pygame.PixelArray(monochromeSurface)
  375.         for x in range(s.surfaceWidth):
  376.             for y in range(s.surfaceHeight):
  377.                 if monochromePA[x][y] != 0: monochromePA[x][y] = DS.map_rgb(color)
  378.         monochromePA.close()
  379.         del monochromePA
  380.         s.monochromeFonts[name] = monochromeSurface
  381.  
  382.     def size(s, text, scale = 1):
  383.         w = len(text) * s.charWidth + s.spacing * (len(text) - 1)
  384.         h = s.surfaceHeight
  385.         return [w * scale, h * scale]
  386.  
  387. BACKGROUND_COLOR_TOP = [0, 35, 35]
  388. BACKGROUND_COLOR_BOTTOM = [0, 32, 32]
  389.  
  390. class background:
  391.     ID = "background"
  392.     LAYER = "background"
  393.     ADD_IMMEDIATELY = True
  394.  
  395.     class backgroundPoint:
  396.         def __init__(s, x):
  397.             global HH
  398.             s.p = [x, 0]
  399.             s.r = random.randint(50, HH - 50)
  400.             s.a = random.uniform(0, 6.283185307179586)
  401.             s.s = random.uniform(0.01, 0.035)
  402.  
  403.         def calc(s):
  404.             global HH
  405.             s.p[1] = HH + int(math.cos(s.a) * s.r)
  406.             s.a += s.s
  407.  
  408.     def __init__(s, S):
  409.         global W, H
  410.         s.RECT = rect((0, 0, W, H))
  411.         s.RECT.collisionActive = False
  412.  
  413.         s.points = [s.backgroundPoint(x) for x in range(0, W, int(W / 10))] + [s.backgroundPoint(W)]
  414.         s.poly1 = [[W, 0], [0, 0]] + [bp.p for bp in s.points]
  415.         s.poly2 = [[W, H], [0, H]] + [bp.p for bp in s.points]
  416.  
  417.     def draw(s):
  418.         global DS
  419.         global BACKGROUND_COLOR_TOP, BACKGROUND_COLOR_BOTTOM
  420.  
  421.         pygame.draw.polygon(DS, BACKGROUND_COLOR_TOP, s.poly1)
  422.         pygame.draw.polygon(DS, BACKGROUND_COLOR_BOTTOM, s.poly2)
  423.  
  424.     def do(s, S):
  425.         for bp in s.points: bp.calc()
  426.         s.draw()            
  427.  
  428. PLATFORM_BLOCK_SIZE = 10
  429. PLATFORM_BLOCK_MAX_STATIC_TIME = 0.5 # secs
  430. PLATFORM_BLOCK_MAX_STATIC_FRAMES = int(FPS * PLATFORM_BLOCK_MAX_STATIC_TIME)
  431. PLATFORM_BLOCK_FALL_TIME = 0.25 # secs
  432. PLATFORM_BLOCK_FALL_FRAMES = int(FPS * PLATFORM_BLOCK_FALL_TIME)
  433. PLATFORM_BLOCK_GRAVITY = GRAVITY * 1.25
  434. PLATFORM_WIDTH_IN_BLOCKS = 10
  435. PLATFORM_HEIGHT_IN_BLOCKS = 3
  436. PLATFORM_WIDTH = PLATFORM_BLOCK_SIZE * PLATFORM_WIDTH_IN_BLOCKS
  437. PLATFORM_HALF_WIDTH = int(PLATFORM_WIDTH / 2)
  438. PLATFORM_HEIGHT = PLATFORM_BLOCK_SIZE * PLATFORM_HEIGHT_IN_BLOCKS
  439. PLATFORM_HALF_HEIGHT = int(PLATFORM_HEIGHT / 2)
  440. PLATFORM_STATIC_POS = [10, H - PLATFORM_HEIGHT - 10]
  441. PLATFORM_COLOR = DOLIVE
  442. PLATFORM_SOLID_TIME = 3 # secs before desintergration starts
  443. PLATFORM_SOLID_FRAMES = int(FPS * PLATFORM_SOLID_TIME)
  444.  
  445. class platform:
  446.     ID = "platform"
  447.     LAYER = "platforms"
  448.     EDGE_COLLISION = [True, True, True ,True] # edges = [top, right, bottom, left]
  449.     ADD_IMMEDIATELY = True
  450.  
  451.     class block:
  452.         def __init__(s, S, x, y, w, instantFall = False):
  453.             global PLATFORM_BLOCK_SIZE
  454.             global PLATFORM_BLOCK_MAX_STATIC_FRAMES
  455.  
  456.             s.timeStamp = S.time.time
  457.  
  458.             if not instantFall:
  459.                 s.staticTime = random.randint(0, PLATFORM_BLOCK_MAX_STATIC_FRAMES)
  460.             else:
  461.                 s.staticTime = 0
  462.            
  463.             s.x = x
  464.             s.y = y
  465.             s.w = w
  466.             s.yv = 0 # y velocity
  467.            
  468.             s.opacity = 255
  469.             s.dead = False
  470.  
  471.         def draw(s):
  472.             global PLATFORM_BLOCK_SIZE
  473.             global PLATFORM_COLOR
  474.             global DS
  475.             pygame.gfxdraw.box(DS, [s.x, int(s.y), s.w, PLATFORM_BLOCK_SIZE], PLATFORM_COLOR + [int(s.opacity)])
  476.  
  477.  
  478.         def do(s, S):
  479.             global PLATFORM_BLOCK_GRAVITY, PLATFORM_BLOCK_FALL_TIME
  480.  
  481.             now = S.time.time
  482.             if now >= s.timeStamp + s.staticTime:
  483.                 fallingTime = now - (s.timeStamp + s.staticTime)
  484.                 if fallingTime >= PLATFORM_BLOCK_FALL_FRAMES:
  485.                     s.dead = True
  486.                     return
  487.  
  488.                 percentage = fallingTime / PLATFORM_BLOCK_FALL_FRAMES
  489.                 s.opacity = 255 - percentage * 255
  490.                
  491.                 s.y += s.yv
  492.                 s.yv += PLATFORM_BLOCK_GRAVITY
  493.  
  494.     def __init__(s, S):
  495.         global PLATFORM_WIDTH, PLATFORM_HEIGHT, PLATFORM_HEIGHT_IN_BLOCKS, PLATFORM_HALF_WIDTH, PLATFORM_HALF_HEIGHT
  496.  
  497.         if len(S.layers[s.LAYER]):
  498.             mx, my = pygame.mouse.get_pos()
  499.             s.RECT = rect([mx - PLATFORM_HALF_WIDTH, my - PLATFORM_HALF_HEIGHT, PLATFORM_WIDTH, PLATFORM_HEIGHT])
  500.             s.staticPlatform = False # Platform will not dissintergrate if True
  501.         else:
  502.             s.RECT = rect([10, H - 10 - PLATFORM_HEIGHT, PLATFORM_WIDTH, PLATFORM_HEIGHT])
  503.             s.staticPlatform = True
  504.  
  505.         s.blockHeight = PLATFORM_HEIGHT_IN_BLOCKS
  506.        
  507.         s.blockContainer = []
  508.  
  509.         s.timeStamp = S.time.time
  510.        
  511.         s.dead = False
  512.    
  513.     def draw(s):
  514.         global PLATFORM_COLOR
  515.         global DS
  516.         if not s.dead:
  517.             pygame.gfxdraw.box(DS, s.RECT.intRect(), PLATFORM_COLOR)
  518.         for block in s.blockContainer:
  519.             block.draw()
  520.  
  521.     def do(s, S):
  522.         global PLATFORM_BLOCK_SIZE
  523.         global PLATFORM_SOLID_FRAMES, PLATFORM_WIDTH
  524.  
  525.         s.RECT.h = s.blockHeight * PLATFORM_BLOCK_SIZE
  526.         if s.staticPlatform: return
  527.  
  528.         deadBlocks = []
  529.         for block in s.blockContainer:
  530.             block.do(S)
  531.             if block.dead: deadBlocks.append(block)
  532.         for thisBlock in deadBlocks:
  533.             s.blockContainer.remove(thisBlock)
  534.        
  535.         now = S.time.time
  536.         if now - s.timeStamp >= PLATFORM_SOLID_FRAMES:
  537.             if not s.blockContainer:
  538.                 if s.blockHeight > 1:
  539.                     s.blockContainer = [s.block(S, s.RECT.x + index * PLATFORM_BLOCK_SIZE, s.RECT.y2() - PLATFORM_BLOCK_SIZE, PLATFORM_BLOCK_SIZE) for index in range(PLATFORM_WIDTH_IN_BLOCKS)]
  540.                     s.blockHeight -= 1
  541.                 else:
  542.                     if not s.dead:
  543.                         s.blockContainer = [s.block(S, s.RECT.x, s.RECT.y, PLATFORM_WIDTH, True)]
  544.                         s.dead = True
  545.                         s.RECT.collisionActive = False
  546.                     else:
  547.                         s.RECT.dead = True
  548.     def die(s):
  549.         s.timeStamp = 0
  550.        
  551. PLATFORM_POINTER_COLOR = WHITE
  552. PLATFORM_POINTER_OPACITY = 128 # 0 - 255; 0 = invisible
  553.  
  554. class platformPointer:
  555.     ID = "pointer"
  556.     LAYER = ID
  557.     ADD_IMMEDIATELY = True
  558.     DO_WHILE_PAUSED = True
  559.  
  560.     def __init__(s, S):
  561.         global PLATFORM_WIDTH, PLATFORM_HEIGHT
  562.        
  563.         s.RECT = rect([0, 0, PLATFORM_WIDTH + 1, PLATFORM_HEIGHT + 1])
  564.         s.RECT.collisionActive = False
  565.  
  566.         s.mousePressed = False
  567.  
  568.     def draw(s):
  569.         global PLATFORM_POINTER_COLOR, PLATFORM_POINTER_OPACITY
  570.         global DS
  571.         pygame.gfxdraw.rectangle(DS, s.RECT.intRect(), PLATFORM_POINTER_COLOR + [PLATFORM_POINTER_OPACITY])
  572.  
  573.  
  574.     def do(s, S):
  575.         global PLATFORM_HALF_WIDTH, PLATFORM_HALF_HEIGHT
  576.  
  577.         mx, my = pygame.mouse.get_pos()
  578.         s.RECT.setXY([mx - PLATFORM_HALF_WIDTH, my - PLATFORM_HALF_HEIGHT])
  579.  
  580.         if not S.paused:
  581.             mb = pygame.mouse.get_pressed()[0]
  582.             if mb and not s.mousePressed:
  583.                 S.addObject(platform(S))
  584.                 s.mousePressed = True
  585.             elif not mb and s.mousePressed:
  586.                 s.mousePressed = False
  587.  
  588. PLAYER_SIZE = 10
  589. PLAYER_SIZE_HALF = int(PLAYER_SIZE / 2)
  590. PLAYER_SIZE_QUARTER = int(PLAYER_SIZE / 4)
  591. PLAYER_RESPAWN_POS = [10 + PLATFORM_HALF_WIDTH - PLAYER_SIZE_HALF, -PLAYER_SIZE]
  592. PLAYER_GOT_FOOD_COLOR = gradient(ORANGE, RED, FPS)
  593. PLAYER_DEAD_COLOR = gradient(WHITE, ORANGE, FPS)
  594. PLAYER_X_VELOCITY = 3 # pixels
  595. PLAYER_JUMP_HEIGHT = 100 # pixels
  596. PLAYER_JUMP_TIME = 0.75 # secs
  597. PLAYER_JUMP_FRAMES = int(FPS * PLAYER_JUMP_TIME / 2)
  598. PLAYER_JUMP_GRAVITY = 2 * PLAYER_JUMP_HEIGHT / (PLAYER_JUMP_FRAMES * (PLAYER_JUMP_FRAMES - 1))
  599. PLAYER_JUMP_VELOCITY = -(PLAYER_JUMP_GRAVITY * (PLAYER_JUMP_FRAMES - 1))
  600. PLAYER_DEAD_GRAVITY = 0.1
  601. PLAYER_LEG_SHOW_PERCENTAGE = 0.9 # pecentage of upward velocity
  602. PLAYER_HAT_WIDTH = 20 # pixels
  603. PLAYER_HAT_COLOR = RED
  604. PLAYER_HAT_X_OFFSET = int((PLAYER_SIZE - PLAYER_HAT_WIDTH) / 2) # ideally the hat should bigger than PLAYER_SIZE
  605. PLAYER_HAT_RIM_HEIGHT = 2 # pixels
  606. PLAYER_HAT_CROWN_HEIGHT = 5 # pixels
  607.  
  608. class player:
  609.     ID = "player"
  610.     LAYER = ID
  611.     ADD_IMMEDIATELY = True
  612.     COLLISION_DETECTION = True
  613.  
  614.     def __init__(s, S):
  615.         global PLAYER_SIZE
  616.         s.RECT = rect([0, 0, PLAYER_SIZE, PLAYER_SIZE])
  617.         s.reset()
  618.    
  619.     def reset(s):
  620.         global PLAYER_RESPAWN_POS
  621.         global PLAYER_GOT_FOOD_COLOR
  622.         s.RECT.setXY(PLAYER_RESPAWN_POS)
  623.         s.RECT.collisionActive = True
  624.  
  625.         s.yv = 0.00001 # falling velocity
  626.         s.xv = 0 # horizontal velocity
  627.        
  628.         s.hatPosY = 0
  629.         s.hatOffsetY = 0
  630.  
  631.         s.dead = False
  632.  
  633.         s.colorIndex = 0
  634.         s.color = PLAYER_GOT_FOOD_COLOR[0]
  635.         s.colorGradient = PLAYER_GOT_FOOD_COLOR
  636.  
  637.         s.legDirection = 0
  638.         s.legRect = None
  639.         s.bodyRect = s.RECT.intRect()
  640.  
  641.     def draw(s):
  642.         global PLAYER_HAT_WIDTH, PLAYER_HAT_RIM_HEIGHT, PLAYER_HAT_CROWN_HEIGHT # dimensions
  643.         global PLAYER_HAT_X_OFFSET # position
  644.         global PLAYER_HAT_COLOR # color
  645.         global DS
  646.        
  647.         hx, hy = s.bodyRect[0:2]
  648.        
  649.         # Player's hat
  650.         pygame.gfxdraw.box(DS, (hx + PLAYER_HAT_X_OFFSET, hy - PLAYER_HAT_RIM_HEIGHT + s.hatOffsetY, PLAYER_HAT_WIDTH, PLAYER_HAT_RIM_HEIGHT), PLAYER_HAT_COLOR)
  651.         pygame.gfxdraw.box(DS, (hx, hy - PLAYER_HAT_RIM_HEIGHT - PLAYER_HAT_CROWN_HEIGHT + s.hatOffsetY, 10, PLAYER_HAT_CROWN_HEIGHT), PLAYER_HAT_COLOR)
  652.  
  653.         # Player's body
  654.         pygame.gfxdraw.box(DS, s.bodyRect, s.color)
  655.  
  656.         # player's leg
  657.         if s.legRect:
  658.             pygame.gfxdraw.box(DS, s.legRect, s.color)
  659.  
  660.    
  661.     def do(s, S):
  662.         global PLAYER_SIZE, PLAYER_SIZE_HALF, PLAYER_SIZE_QUARTER
  663.         global PLAYER_X_VELOCITY, PLAYER_JUMP_VELOCITY, PLAYER_JUMP_GRAVITY, PLAYER_DEAD_GRAVITY
  664.         global PLAYER_LEG_SHOW_PERCENTAGE
  665.         global W, H
  666.        
  667.         # position the player's hat
  668.         if s.yv > 0:
  669.             s.hatOffsetY = int((s.hatPosY - s.RECT.y) / 0.8)
  670.         else:
  671.             s.hatOffsetY = 0
  672.         s.hatPosY = s.RECT.y
  673.  
  674.         # if gradient is active
  675.         if s.colorIndex:
  676.             s.colorIndex -= 1
  677.             s.color = s.colorGradient[s.colorIndex]
  678.  
  679.         # moving body parts
  680.         if not s.dead:
  681.             if s.yv < 0 and s.yv >= PLAYER_JUMP_VELOCITY * PLAYER_LEG_SHOW_PERCENTAGE:
  682.                 s.legRect = [s.RECT.x1() + (s.legDirection * PLAYER_SIZE_HALF), s.RECT.y2(), PLAYER_SIZE_HALF, PLAYER_SIZE_HALF]
  683.             else:
  684.                 if s.yv == 0:
  685.                     if s.xv > 0:
  686.                         s.legRect = [s.RECT.x1() - PLAYER_SIZE_QUARTER, s.RECT.yCenter(), PLAYER_SIZE_QUARTER, PLAYER_SIZE_HALF]
  687.                     elif s.xv < 0:
  688.                         s.legRect = [s.RECT.x2(), s.RECT.yCenter(), PLAYER_SIZE_QUARTER, PLAYER_SIZE_HALF]
  689.                     else:
  690.                         s.legRect = [s.RECT.x1() - PLAYER_SIZE_QUARTER, s.RECT.yCenter(), PLAYER_SIZE + PLAYER_SIZE_HALF - 1, PLAYER_SIZE_HALF]
  691.                 else:
  692.                     s.legRect = None
  693.         else:
  694.             s.legRect = [s.RECT.x1() + int(PLAYER_SIZE_HALF / 2), s.RECT.y2(), PLAYER_SIZE_HALF, int(PLAYER_SIZE_HALF / 2)]
  695.        
  696.         # body
  697.         s.bodyRect = s.RECT.intRect()
  698.  
  699.         # keys
  700.         k = pygame.key.get_pressed()
  701.         if k[pygame.K_a]:
  702.             if s.xv > -PLAYER_X_VELOCITY:
  703.                 s.xv -= GRAVITY
  704.             s.legDirection = 1
  705.         elif k[pygame.K_d]:
  706.             if s.xv < PLAYER_X_VELOCITY:
  707.                 s.xv += GRAVITY
  708.             s.legDirection = 0
  709.         else:
  710.             if s.xv < 0: s.xv += GRAVITY
  711.             elif s.xv > 0: s.xv -= GRAVITY
  712.  
  713.         if k[pygame.K_SPACE] and s.yv == 0:
  714.             s.yv = PLAYER_JUMP_VELOCITY
  715.  
  716.         # movement
  717.         reset = False
  718.         s.RECT.x += s.xv
  719.         if s.RECT.x >= W or s.RECT.x <= -PLAYER_SIZE:
  720.             reset = True
  721.  
  722.         s.RECT.y += s.yv
  723.         if not s.dead:
  724.             s.yv += PLAYER_JUMP_GRAVITY
  725.         else:
  726.             s.yv -= PLAYER_DEAD_GRAVITY
  727.         if s.RECT.y > H:
  728.             S.score -= 1000
  729.             if S.score < 0:
  730.                 S.score = 0
  731.             reset = True
  732.         if s.RECT.y + PLAYER_SIZE <= 0 and s.dead:
  733.             reset = True
  734.         if reset:
  735.             s.reset()
  736.            
  737.     def futureMove(s):
  738.         return [s.RECT.x + s.xv, s.RECT.y + s.yv]
  739.  
  740.     def collision(s, S, obj, edgeIndex = None):
  741.         global PLAYER_SIZE, PLAYER_X_VELOCITY
  742.         global PLAYER_GOT_FOOD_COLOR
  743.         global FOOD_EXISTS_FRAMES
  744.  
  745.         if obj.ID == "platform":
  746.             if edgeIndex == 0 and s.yv >= 0:
  747.                 s.RECT.y = obj.RECT.y - PLAYER_SIZE
  748.                 s.yv = 0
  749.         if obj.ID == "food":
  750.             s.colorIndex = len(PLAYER_GOT_FOOD_COLOR) - 1
  751.             obj.RECT.dead = True
  752.             if S.time.time - obj.timeStamp <= FOOD_EXISTS_FRAMES * 0.25:
  753.                 S.addObject(star(s, s.xv))
  754.                 S.score += FOOD_EXISTS_FRAMES - (S.time.time - obj.timeStamp)
  755.             else:
  756.                 S.score += int((FOOD_EXISTS_FRAMES - (S.time.time - obj.timeStamp)) / 2)
  757.             S.addObject(food(S))
  758.         if obj.ID == "wall":
  759.             if edgeIndex == 0 and s.yv >= 0:
  760.                 s.RECT.y = obj.RECT.y - PLAYER_SIZE
  761.                 s.yv = 0
  762.             elif edgeIndex == 1:
  763.                 s.RECT.x = obj.RECT.x2() + PLAYER_X_VELOCITY# + 1
  764.                 s.xv = 0
  765.             elif edgeIndex == 2 and s.yv < 0:
  766.                 s.RECT.y = obj.RECT.y2()
  767.                 s.yv = 0.00001
  768.             elif edgeIndex == 3:
  769.                 s.RECT.x = obj.RECT.x - PLAYER_SIZE - PLAYER_X_VELOCITY # - 1
  770.                 s.xv = 0
  771.         if obj.ID == "bumper":
  772.             if edgeIndex == 0:
  773.                 s.yv = -20
  774.             if edgeIndex == 1:
  775.                 s.xv = 20
  776.             if edgeIndex == 2:
  777.                 s.yv = 20
  778.             if edgeIndex == 3:
  779.                 s.xv = -20      
  780.             obj.shake()
  781.  
  782.     def die(s):
  783.         global PLAYER_DEAD_COLOR
  784.  
  785.         s.dead = True
  786.         s.RECT.collisionActive = False
  787.         s.yv = 0.00001
  788.         s.colorGradient = PLAYER_DEAD_COLOR
  789.         s.colorIndex = len(PLAYER_DEAD_COLOR) - 1
  790.        
  791.  
  792. STAR_POINTS = [[10, 0], [13, 7], [20, 7], [15, 13], [18, 20], [10, 15], [2, 20], [5, 13], [0, 7], [7, 7]]
  793. STAR_SIZE = 20
  794. STAR_SIZE_HALF = int(STAR_SIZE / 2)
  795. STAR_JUMP_VELOCITY = -10
  796. STAR_X_VELOCITY = 4
  797. STAR_DIRECTION_POLARITY = [-1, 1]
  798. STAR_FADE_TIME = 0.5
  799. STAR_FADE_FRAMES = int(FPS * STAR_FADE_TIME)
  800. STAR_OPACITY_CHUNK = 255 / STAR_FADE_FRAMES
  801. STAR_COLOR = YELLOW
  802.  
  803. class star:
  804.     ID = "star"
  805.     LAYER = "stars"
  806.    
  807.     def __init__(s, obj, velocity):
  808.         global STAR_SIZE, STAR_SIZE_HALF
  809.         global STAR_DIRECTION_POLARITY, STAR_JUMP_VELOCITY
  810.  
  811.         s.RECT = rect([obj.RECT.xCenter() - STAR_SIZE_HALF, obj.RECT.yCenter() - STAR_SIZE_HALF, STAR_SIZE, STAR_SIZE])
  812.         s.RECT.collisionActive = False
  813.  
  814.         if velocity != 0:
  815.             direction = velocity / abs(velocity)
  816.         else:
  817.             direction = STAR_DIRECTION_POLARITY[random.randint(0, 1)]
  818.         s.xv = STAR_X_VELOCITY * direction
  819.         s.yv = STAR_JUMP_VELOCITY
  820.  
  821.         s.opacity = 255
  822.  
  823.     def makePoints(s):
  824.         global STAR_POINTS
  825.         return [[p[0] + s.RECT.x1(), p[1] + s.RECT.y1()] for p in STAR_POINTS]
  826.  
  827.     def draw(s):
  828.         global STAR_COLOR
  829.         global DS
  830.         pygame.gfxdraw.filled_polygon(DS, s.makePoints(), STAR_COLOR + [int(s.opacity)])
  831.        
  832.     def do(s, S):
  833.         global STAR_OPACITY_CHUNK
  834.         global GRAVITY
  835.  
  836.         s.RECT.x += s.xv
  837.         s.RECT.y += s.yv
  838.         s.yv += GRAVITY
  839.  
  840.         if s.opacity:
  841.             s.opacity -= STAR_OPACITY_CHUNK
  842.             if s.opacity < 0:
  843.                 s.RECT.dead = True
  844.  
  845.  
  846. FOOD_SIZE = 10
  847. FOOD_SIZE_HALF = int(FOOD_SIZE / 2)
  848. FOOD_SPAWN_BORDER = 30 # pixels
  849. FOOD_SPAWN_AREA = [FOOD_SPAWN_BORDER, FOOD_SPAWN_BORDER, W - FOOD_SPAWN_BORDER -FOOD_SIZE, H - FOOD_SPAWN_BORDER - FOOD_SIZE]
  850. FOOD_DROP_TIME = 1 # second
  851. FOOD_DROP_FRAMES = int(FPS * FOOD_DROP_TIME)
  852. FOOD_EXISTS_TIME = 20 # secs
  853. FOOD_EXISTS_FRAMES = (FPS * FOOD_EXISTS_TIME)
  854. FOOD_WARNING_FRAMES = (FPS * 3) # frames
  855. FOOD_MAX_SHAKE_DISTANCE = 3 # pixels
  856. FOOD_SHAKE_CHUNK = FOOD_MAX_SHAKE_DISTANCE / FOOD_WARNING_FRAMES
  857. FOOD_COLOR = RED
  858. FOOD_CLOCK_SIZE = FOOD_SIZE + FOOD_SIZE_HALF
  859. FOOD_CLOCK_TICK_CHUNK = 360 / (FPS * FOOD_EXISTS_TIME)
  860. FOOD_CLOCK_OPACITY_TIME = 1 # secs
  861. FOOD_CLOCK_OPACITY_FRAMES = int(FPS * FOOD_CLOCK_OPACITY_TIME)
  862. FOOD_CLOCK_OPACITY_CHUNK = 255 / FOOD_CLOCK_OPACITY_FRAMES
  863. FOOD_CLOCK_COLOR = GRAY
  864.  
  865. class food:
  866.     global FPS
  867.     ID = "food"
  868.     LAYER = "objects"
  869.     ADD_IMMEDIATELY = True
  870.     TIME_EVENT = True
  871.     EVENT_START = 5 * 60 * FPS
  872.     EVENT_INTERVAL = EVENT_START
  873.     EVENT_MAXCOUNT = 3
  874.  
  875.     def __init__(s, S):
  876.         s.reset(S)
  877.    
  878.     def reset(s, S):
  879.         global FOOD_SIZE # dimensions
  880.         global FOOD_SPAWN_AREA # position
  881.         global FOOD_DROP_FRAMES, FOOD_CLOCK_OPACITY_FRAMES, FOOD_CLOCK_TICK_CHUNK # time
  882.  
  883.         noSpaceFoundYet = True
  884.         attempts = 25
  885.         while noSpaceFoundYet and attempts:
  886.             s.x = random.randint(FOOD_SPAWN_AREA[0], FOOD_SPAWN_AREA[2])
  887.             s.y = random.randint(FOOD_SPAWN_AREA[1], FOOD_SPAWN_AREA[3])
  888.             newRect = [s.x, s.y, FOOD_SIZE, FOOD_SIZE]
  889.             noSpaceFoundYet = S.testAllRect(newRect, ["platform"])
  890.             attempts -= 1 # if attempts to find a space for the food fails then place it anywhere
  891.         s.RECT = rect([s.x, -FOOD_SIZE, FOOD_SIZE, FOOD_SIZE])
  892.         s.placeHolder = S.addPlaceHolder(newRect, s.ID)
  893.  
  894.         s.gravity = 2 * (s.y + FOOD_SIZE) / (FOOD_DROP_FRAMES * (FOOD_DROP_FRAMES - 1))
  895.         s.yv = s.gravity * (FOOD_DROP_FRAMES - 1)
  896.  
  897.         s.clockOpacity = 0
  898.         s.clockTime = 360 - FOOD_CLOCK_TICK_CHUNK * FOOD_DROP_FRAMES
  899.  
  900.         s.stopped = False
  901.         s.warning = False
  902.         s.dead = False
  903.  
  904.         s.timeStamp = S.time.time
  905.    
  906.     def draw(s):
  907.         global FOOD_CLOCK_SIZE
  908.         global FOOD_COLOR, FOOD_CLOCK_COLOR
  909.         global DS
  910.         pygame.gfxdraw.box(DS, s.RECT.intRect(), FOOD_COLOR)
  911.         pygame.gfxdraw.arc(DS, s.RECT.xCenter(), s.RECT.yCenter(), FOOD_CLOCK_SIZE, 270 - int(s.clockTime), -90, FOOD_CLOCK_COLOR + [int(s.clockOpacity)])
  912.  
  913.     def do(s, S):
  914.         global FOOD_EXISTS_FRAMES, FOOD_WARNING_FRAMES # time
  915.         global FOOD_COLOR, FOOD_CLOCK_OPACITY_CHUNK # color
  916.         global FOOD_CLOCK_TICK_CHUNK # movement
  917.         global GRAVITY
  918.         global H
  919.  
  920.         if not s.stopped:
  921.             s.RECT.y += s.yv
  922.             s.yv -= s.gravity
  923.            
  924.             if s.RECT.y1() == s.y - 1:
  925.                 s.yv = 0
  926.                 s.stopped = True
  927.                 S.delPlaceHolder(s.placeHolder)
  928.                 S.addObject(beacon(s, FOOD_COLOR))
  929.        
  930.         now = S.time.time
  931.         if s.stopped:
  932.             if s.clockOpacity < 255:
  933.                 s.clockOpacity += FOOD_CLOCK_OPACITY_CHUNK
  934.                 if s.clockOpacity > 255: s.clockOpacity = 255
  935.             if s.clockTime:
  936.                 s.clockTime -= FOOD_CLOCK_TICK_CHUNK
  937.                 if s.clockTime < 0:
  938.                     s.clockTime = 0
  939.             if now - s.timeStamp >= FOOD_EXISTS_FRAMES - FOOD_WARNING_FRAMES and not s.dead:
  940.                 if not s.warning:
  941.                     S.addObject(beacon(s, FOOD_COLOR))
  942.                     s.warning = True
  943.                 distance = FOOD_SHAKE_CHUNK * (now - s.timeStamp - FOOD_EXISTS_FRAMES + FOOD_WARNING_FRAMES)
  944.                 s.RECT.setXY([s.x + random.uniform(-distance, distance), s.y + random.uniform(-distance, distance)])
  945.             if now - s.timeStamp >= FOOD_EXISTS_FRAMES:
  946.                 if not s.dead:
  947.                     s.RECT.setXY((s.x, s.y))
  948.                     s.dead = True
  949.                 s.RECT.y += s.yv
  950.                 s.yv += GRAVITY
  951.  
  952.                 if s.RECT.y >= H:
  953.                     S.lives -= 1
  954.                     s.reset(S)
  955.  
  956. WALL_WIDTH = 30 # pixels
  957. WALL_HEIGHT = HH - 25
  958. WALL_BORDER = 30
  959. WALL_SPAWN_AREA = [10 + PLATFORM_WIDTH + 10, W - WALL_BORDER - WALL_WIDTH]
  960. WALL_STARTING_POSY = [-WALL_HEIGHT, H]
  961. WALL_EXISTS_TIME = 20 # secs
  962. WALL_EXISTS_FRAMES = WALL_EXISTS_TIME * FPS
  963. WALL_DROP_TIME = 1 # sec
  964. WALL_DROP_FRAMES = int(FPS * WALL_DROP_TIME)
  965. WALL_GRAVITY = 2 * WALL_HEIGHT / (WALL_DROP_FRAMES * (WALL_DROP_FRAMES - 1))
  966. WALL_VELOCITY = WALL_GRAVITY * (WALL_DROP_FRAMES - 1)
  967. WALL_VELOCITY_POLARITY = [1, -1]
  968. WALL_COLOR = PURPLE
  969.  
  970. class wall:
  971.     ID = "wall"
  972.     LAYER = "objects"
  973.     EDGE_COLLISION = [True, True, True, True]
  974.     SCORE_EVENT = True
  975.     EVENT_START = 10000
  976.     EVENT_INTERVAL = 10000
  977.     EVENT_MAXCOUNT = 5
  978.  
  979.     def __init__(s, S):
  980.         s.reset(S)
  981.  
  982.     def reset(s, S):
  983.         global WALL_WIDTH, WALL_HEIGHT # dimensions
  984.         global WALL_SPAWN_AREA, WALL_STARTING_POSY # position
  985.         global WALL_DROP_FRAMES # time
  986.         global WALL_VELOCITY_POLARITY, WALL_GRAVITY # movement
  987.         global H
  988.  
  989.         noSpaceFoundYet = True
  990.         attempts = 25
  991.         while noSpaceFoundYet and attempts:
  992.             x = random.randint(WALL_SPAWN_AREA[0], WALL_SPAWN_AREA[1])        
  993.             s.alignment = random.randint(0, 1) # 0 = top, 1 = bottom
  994.             s.y = (H - WALL_HEIGHT) * s.alignment    
  995.             newRect = [x, s.y, WALL_WIDTH, WALL_HEIGHT]
  996.  
  997.             noSpaceFoundYet = S.testAllRect(newRect, ["platform"])
  998.            
  999.             attempts -= 1
  1000.        
  1001.         s.placeHolder = S.addPlaceHolder(newRect, s.ID)
  1002.         s.RECT = rect([x, WALL_STARTING_POSY[s.alignment], WALL_WIDTH, WALL_HEIGHT])
  1003.  
  1004.         s.yv = WALL_VELOCITY * WALL_VELOCITY_POLARITY[s.alignment]
  1005.         s.gravity = WALL_GRAVITY * WALL_VELOCITY_POLARITY[s.alignment]
  1006.  
  1007.         s.stopped = False
  1008.         s.timeStamp = S.time.time
  1009.  
  1010.     def draw(s):
  1011.         global WALL_COLOR # color
  1012.         global DS
  1013.         pygame.gfxdraw.box(DS, s.RECT.intRect(), WALL_COLOR)
  1014.  
  1015.     def do(s, S):
  1016.         global WALL_HEIGHT # dimensions
  1017.         global WALL_EXISTS_FRAMES # time
  1018.         global WALL_GRAVITY, WALL_VELOCITY_POLARITY # movement
  1019.         global H
  1020.  
  1021.         if not s.stopped:
  1022.             s.RECT.y += s.yv
  1023.             s.yv -= s.gravity
  1024.  
  1025.             if s.RECT.y1() == s.y:
  1026.                 s.yv = 0
  1027.                 s.stopped = True
  1028.                 S.delPlaceHolder(s.placeHolder)
  1029.                 S.addObject(beacon(s, WALL_COLOR))
  1030.  
  1031.         now = S.time.time
  1032.         if s.stopped and now - s.timeStamp >= WALL_EXISTS_FRAMES:
  1033.             s.RECT.y += s.yv
  1034.             s.yv += -s.gravity
  1035.             if s.RECT.y1() == WALL_STARTING_POSY[s.alignment]:
  1036.                 s.reset(S)
  1037.  
  1038. BOUNCER_SIZE = 25
  1039. BOUNCER_SPEED = 3
  1040. BOUNCER_BORDER_SIZE = 30
  1041. BOUNCER_SPAWN_AREA = [10 + PLATFORM_WIDTH + 10, BOUNCER_BORDER_SIZE, W - BOUNCER_BORDER_SIZE - BOUNCER_SIZE, H - BOUNCER_BORDER_SIZE - BOUNCER_SIZE]
  1042. BOUNCER_APPEAR_TIME = 0.5 # seconds
  1043. BOUNCER_APPEAR_FRAMES = int(FPS * BOUNCER_APPEAR_TIME)
  1044. BOUNCER_APPEAR_OPACITY_CHUNK = 255 / BOUNCER_APPEAR_FRAMES
  1045. BOUNCER_COLOR = TEAL
  1046.  
  1047. class bouncer:
  1048.     ID = "bouncer"
  1049.     LAYER = "objects"
  1050.     COLLISION_DETECTION = True
  1051.     SCORE_EVENT = True
  1052.     EVENT_START = 65000
  1053.     EVENT_INTERVAL = 100000
  1054.     EVENT_MAXCOUNT = 5
  1055.  
  1056.     def __init__(s, S):
  1057.         global BOUNCER_SIZE, BOUNCER_SPEED, BOUNCER_SPAWN_AREA
  1058.         global W, H
  1059.  
  1060.         noSpaceFoundYet = True
  1061.         attempts = 25
  1062.         while noSpaceFoundYet and attempts:
  1063.             x = random.randint(BOUNCER_SPAWN_AREA[0], BOUNCER_SPAWN_AREA[2])
  1064.             y = random.randint(BOUNCER_SPAWN_AREA[1], BOUNCER_SPAWN_AREA[3])
  1065.             noSpaceFoundYet = S.testAllRect([x, y, BOUNCER_SIZE, BOUNCER_SIZE], ["platform"])
  1066.             attempts -= 1 # if attempts to find a space for the food fails then place it anywhere
  1067.         s.RECT = rect([x, y, BOUNCER_SIZE, BOUNCER_SIZE])
  1068.        
  1069.         r = math.radians(random.randint(0, 360))
  1070.         s.dx = math.cos(r) * BOUNCER_SPEED
  1071.         s.dy = math.sin(r) * BOUNCER_SPEED
  1072.  
  1073.         s.opacity = 0
  1074.  
  1075.     def draw(s):
  1076.         global BOUNCER_COLOR
  1077.         global DS
  1078.         pygame.gfxdraw.box(DS, s.RECT.intRect(), BOUNCER_COLOR + [s.opacity])
  1079.  
  1080.     def do(s, S):
  1081.         global BOUNCER_SIZE
  1082.         global BOUNCER_APPEAR_OPACITY_CHUNK
  1083.         global W, H
  1084.  
  1085.         if s.opacity < 255:
  1086.             s.opacity += BOUNCER_APPEAR_OPACITY_CHUNK
  1087.             if s.opacity > 255: s.opacity = 255
  1088.  
  1089.         s.RECT.x += s.dx
  1090.         s.RECT.y += s.dy
  1091.         if s.RECT.x2() > W:
  1092.             s.RECT.x = W - BOUNCER_SIZE
  1093.             s.dx = -s.dx
  1094.         elif s.RECT.x < 0:
  1095.             s.RECT.x = 0
  1096.             s.dx = -s.dx
  1097.         if s.RECT.y2() > H:
  1098.             s.RECT.y = H - BOUNCER_SIZE
  1099.             s.dy = -s.dy
  1100.         elif s.RECT.y < 0:
  1101.             s.RECT.y = 0
  1102.             s.dy = -s.dy
  1103.  
  1104.     def futureMove(s):
  1105.         return([s.RECT.x + s.dx, s.RECT.y + s.dy])
  1106.        
  1107.     def collision(s, S, obj, edgeIndex = None):
  1108.         global BOUNCER_SIZE, BOUNCER_COLOR
  1109.  
  1110.         if obj.ID == "wall" or obj.ID == "bumper":
  1111.             if edgeIndex == 0:
  1112.                 s.RECT.y = obj.RECT.y - BOUNCER_SIZE
  1113.                 s.dy = -s.dy
  1114.             elif edgeIndex == 1:
  1115.                 s.RECT.x = obj.RECT.x2()
  1116.                 s.dx = -s.dx
  1117.             elif edgeIndex == 2:
  1118.                 s.RECT.y = obj.RECT.y2()
  1119.                 s.dy = -s.dy
  1120.             elif edgeIndex == 3:
  1121.                 s.RECT.x = obj.RECT.x - BOUNCER_SIZE
  1122.                 s.dx = -s.dx
  1123.             S.addObject(beacon(s, BOUNCER_COLOR))
  1124.         if obj.ID == "platform":
  1125.             if not obj.dead: obj.die()
  1126.         if obj.ID == "player":
  1127.             if not obj.dead:
  1128.                 S.lives -= 1
  1129.                 S.addObject(beacon(s, BOUNCER_COLOR))
  1130.  
  1131. BUMPER_SIZE = 100
  1132. BUMPER_SPAWN_BORDER = 30
  1133. BUMPER_SPAWN_AREA = [10 + PLATFORM_WIDTH + 10, BUMPER_SPAWN_BORDER, W - BUMPER_SIZE - BUMPER_SPAWN_BORDER, H - BUMPER_SIZE - BUMPER_SPAWN_BORDER]
  1134. BUMPER_DROP_TIME = 1 # secs
  1135. BUMPER_DROP_FRAMES = int(FPS * BUMPER_DROP_TIME)
  1136. BUMPER_COLOR = gradient(GRAY, WHITE, int(FPS / 2))
  1137. BUMPER_COLOR_MAX_INDEX = len(BUMPER_COLOR) - 1
  1138. BUMPER_EXIST_TIME = 20 # secs
  1139. BUMPER_EXIST_FRAMES = BUMPER_EXIST_TIME * FPS
  1140.  
  1141. class bumper:
  1142.     ID = "bumper"
  1143.     LAYER = "objects"
  1144.     EDGE_COLLISION = [True, True, True, True]
  1145.     SCORE_EVENT = True
  1146.     EVENT_START = 50000
  1147.     EVENT_INTERVAL = 50000
  1148.     EVENT_MAXCOUNT = 5
  1149.  
  1150.     def __init__(s, S):
  1151.         s.reset(S)
  1152.  
  1153.     def reset(s, S):
  1154.         global BUMPER_SIZE, BUMPER_SPAWN_AREA
  1155.         global BUMPER_COLOR_MAX_INDEX
  1156.         global BUMPER_DROP_FRAMES
  1157.  
  1158.         noSpaceFoundYet = True
  1159.         attempts = 25
  1160.         while noSpaceFoundYet and attempts:
  1161.             s.x = random.randint(BUMPER_SPAWN_AREA[0], BUMPER_SPAWN_AREA[2])
  1162.             s.y = random.randint(BUMPER_SPAWN_AREA[1], BUMPER_SPAWN_AREA[3])
  1163.             newRect = [s.x, s.y, BUMPER_SIZE, BUMPER_SIZE]
  1164.             noSpaceFoundYet = S.testAllRect(newRect, ["platform"])
  1165.             attempts -= 1
  1166.         s.placeHolder = S.addPlaceHolder(newRect, s.ID)
  1167.         s.RECT = rect([s.x, -BUMPER_SIZE, BUMPER_SIZE, BUMPER_SIZE])
  1168.         s.RECT.collisionActive = False
  1169.  
  1170.         s.gravity = 2 * (s.y + BUMPER_SIZE) / (BUMPER_DROP_FRAMES * (BUMPER_DROP_FRAMES - 1))
  1171.         s.yv = s.gravity * (BUMPER_DROP_FRAMES - 1)
  1172.  
  1173.         s.colorIndex = 0
  1174.  
  1175.         s.stopped = False
  1176.         s.dead = False
  1177.         s.timeStamp = S.time.time
  1178.  
  1179.     def draw(s):
  1180.         global BUMPER_COLOR
  1181.         global DS
  1182.         pygame.gfxdraw.box(DS, s.RECT.intRect(), BUMPER_COLOR[s.colorIndex])
  1183.  
  1184.     def do(s, S):
  1185.         global BUMPER_EXIST_FRAMES
  1186.         global BUMPER_COLOR
  1187.         global GRAVITY
  1188.         global H
  1189.  
  1190.         if s.colorIndex:
  1191.             s.colorIndex -= 1
  1192.             s.RECT.setXY([s.x + random.randint(-5, 5), s.y + random.randint(-5, 5)])
  1193.            
  1194.         if not s.stopped:
  1195.             s.RECT.y += s.yv
  1196.             s.yv -= s.gravity
  1197.  
  1198.             if s.RECT.y1() == s.y - 1:
  1199.                 s.yv = 0
  1200.                 s.RECT.collisionActive = True
  1201.                 s.stopped = True
  1202.                 S.delPlaceHolder(s.placeHolder)
  1203.                 S.addObject(beacon(s, BUMPER_COLOR[0]))
  1204.  
  1205.         now = S.time.time
  1206.         if s.stopped:
  1207.             if now - s.timeStamp >= BUMPER_EXIST_FRAMES:
  1208.                 s.RECT.y += s.yv
  1209.                 s.yv += GRAVITY
  1210.                 if s.RECT.y >= H:
  1211.                     s.reset(S)
  1212.                 if not s.dead:
  1213.                     s.dead = True
  1214.                     s.RECT.collisionActive = False
  1215.  
  1216.     def shake(s):
  1217.         global BUMPER_COLOR, BUMPER_COLOR_MAX_INDEX
  1218.         s.colorIndex = BUMPER_COLOR_MAX_INDEX
  1219.  
  1220. FIRE_SIZE = 4
  1221. FIRE_SIZE_HALF = int(FIRE_SIZE / 2)
  1222. FIRE_SPEED = 1.3
  1223. FIRE_COLOR = RED
  1224. FIRE_BURN_TIME = 0.5 # secs
  1225. FIRE_FRAMES = int(FPS * FIRE_BURN_TIME)
  1226. FIRE_OPACITY_CHUNK = 255 / FIRE_FRAMES
  1227.  
  1228. BULLET_SIZE = 6
  1229. BULLET_SIZE_HALF = int(BULLET_SIZE / 2)
  1230. BULLET_SPEED = 5
  1231. BULLET_COLOR = SILVER
  1232.  
  1233. class bullet:
  1234.     ID = "bullet"
  1235.     LAYER = "bullets"
  1236.     COLLISION_DETECTION = True
  1237.  
  1238.     class fire:
  1239.         ID = "fire"
  1240.         LAYER = ID
  1241.  
  1242.         def __init__(s, b):
  1243.             global FIRE_SIZE, FIRE_SIZE_HALF
  1244.             global FIRE_SPEED
  1245.  
  1246.             s.xv = b.xv / FIRE_SPEED
  1247.             s.yv = b.yv / FIRE_SPEED
  1248.  
  1249.             bx, by = b.RECT.center()
  1250.             s.RECT = rect([bx - FIRE_SIZE_HALF, by - FIRE_SIZE_HALF, FIRE_SIZE, FIRE_SIZE])
  1251.             s.RECT.collisionActive = False
  1252.  
  1253.             s.opacity = 255
  1254.        
  1255.         def draw(s):
  1256.             global FIRE_COLOR
  1257.             global DS
  1258.             pygame.gfxdraw.box(DS, s.RECT.intRect(), FIRE_COLOR + [int(s.opacity)])
  1259.  
  1260.         def do(s, S):
  1261.             global FIRE_SIZE, FIRE_SIZE_HALF
  1262.             global W, H
  1263.             global DS
  1264.  
  1265.             if s.opacity:
  1266.                 s.opacity -= FIRE_OPACITY_CHUNK
  1267.                 if s.opacity < 0:
  1268.                     s.RECT.dead = True                    
  1269.  
  1270.             s.RECT.x += s.xv
  1271.             s.RECT.y += s.yv
  1272.             if s.RECT.x <= -FIRE_SIZE or s.RECT.y <= -FIRE_SIZE or s.RECT.x >= W or s.RECT.y >= H:
  1273.                 s.RECT.dead = True
  1274.                 return
  1275.  
  1276.     def __init__(s, gun, victim):
  1277.         global BULLET_SIZE, BULLET_SIZE_HALF
  1278.         global BULLET_SPEED
  1279.        
  1280.         s.gun = gun
  1281.  
  1282.         tx, ty = victim.RECT.center()
  1283.         gx, gy = gun.RECT.center()
  1284.  
  1285.         angle = math.atan2(ty - gy, tx - gx)
  1286.         s.xv = math.cos(angle) * BULLET_SPEED
  1287.         s.yv = math.sin(angle) * BULLET_SPEED
  1288.  
  1289.         x = gx + math.cos(angle) * gun.RECT.w / 2
  1290.         y = gy + math.sin(angle) * gun.RECT.h / 2
  1291.  
  1292.         s.RECT = rect([x - BULLET_SIZE_HALF, y - BULLET_SIZE_HALF, BULLET_SIZE, BULLET_SIZE])
  1293.  
  1294.         s.fireFlames = None
  1295.  
  1296.     def draw(s):
  1297.         global BULLET_COLOR
  1298.         global DS
  1299.         pygame.gfxdraw.box(DS, s.RECT.intRect(), BULLET_COLOR)
  1300.  
  1301.  
  1302.     def do(s, S):
  1303.         global FIRE_FRAMES
  1304.         global BULLET_SIZE
  1305.         global BULLET_COLOR
  1306.         global W, H
  1307.         global DS
  1308.  
  1309.         if s.fireFlames == None:
  1310.             s.fireFlames = S.addObject(s.fire(s))
  1311.         elif s.fireFlames.opacity <= 128:
  1312.             s.fireFlames = S.addObject(s.fire(s))
  1313.  
  1314.         s.RECT.x += s.xv
  1315.         s.RECT.y += s.yv
  1316.         if s.RECT.x <= -BULLET_SIZE or s.RECT.y <= -BULLET_SIZE or s.RECT.x >= W or s.RECT.y >= H:
  1317.             s.RECT.dead = True
  1318.             return
  1319.  
  1320.     def futureMove(s):
  1321.         return [s.RECT.x + s.xv, s.RECT.y + s.yv]
  1322.  
  1323.     def collision(s, S, obj, edgeIndex = None):
  1324.         global BULLET_SIZE
  1325.         global ORANGE
  1326.  
  1327.         if obj.ID == "player":
  1328.             S.lives -= 1
  1329.             s.RECT.dead = True
  1330.             s.gun.dead = True
  1331.             S.addObject(beacon(s, ORANGE))
  1332.  
  1333.  
  1334. SHOOTER_SIZE = 25
  1335. SHOOTER_SPAWN_BORDER = 30
  1336. SHOOTER_SPAWN_AREA = [10 + PLATFORM_WIDTH + 10, SHOOTER_SPAWN_BORDER, W - SHOOTER_SPAWN_BORDER - SHOOTER_SIZE, H - SHOOTER_SPAWN_BORDER - SHOOTER_SIZE]
  1337. SHOOTER_DROP_TIME = 2 #secs
  1338. SHOOTER_DROP_FRAMES = int(FPS * SHOOTER_DROP_TIME)
  1339. SHOOTER_FIRE_DELAY = (2 * FPS) #frames
  1340. SHOOTER_COLOR = GREEN
  1341.  
  1342. class shooter:
  1343.     ID = "shooter"
  1344.     LAYER = "objects"
  1345.     SCORE_EVENT = True
  1346.     EVENT_START = 100000
  1347.     EVENT_INTERVAL = 100000
  1348.     EVENT_MAXCOUNT = 5
  1349.  
  1350.     def __init__(s, S):
  1351.         global SHOOTER_SIZE # dimensions
  1352.         global SHOOTER_SPAWN_AREA # position
  1353.         global SHOOTER_DROP_FRAMES # time
  1354.  
  1355.         noSpaceFoundYet = True
  1356.         attempts = 25
  1357.         while noSpaceFoundYet and attempts:
  1358.             s.x = random.randint(SHOOTER_SPAWN_AREA[0], SHOOTER_SPAWN_AREA[2])
  1359.             s.y = random.randint(SHOOTER_SPAWN_AREA[1], SHOOTER_SPAWN_AREA[3])
  1360.             newRect = [s.x, s.y, SHOOTER_SIZE, SHOOTER_SIZE]
  1361.             noSpaceFoundYet = S.testAllRect(newRect, ["platform"])
  1362.             attempts -= 1
  1363.         s.placeHolder = S.addPlaceHolder(newRect, s.ID)
  1364.         s.RECT = rect([s.x, -SHOOTER_SIZE, SHOOTER_SIZE, SHOOTER_SIZE])
  1365.  
  1366.         s.gravity = 2 * (s.y + SHOOTER_SIZE) / (SHOOTER_DROP_FRAMES * (SHOOTER_DROP_FRAMES - 1))
  1367.         s.yv = s.gravity * (SHOOTER_DROP_FRAMES - 1)
  1368.  
  1369.         s.stopped = False
  1370.         s.timeStamp = S.time.time
  1371.        
  1372.         s.bulletCount = 3
  1373.         s.bulletTimeStamp = 0
  1374.  
  1375.     def draw(s):
  1376.         global SHOOTER_COLOR
  1377.         global DS
  1378.         pygame.gfxdraw.box(DS, s.RECT.intRect(), SHOOTER_COLOR)
  1379.  
  1380.     def fireBullet(s, S):
  1381.         S.addObject(bullet(s, S.layers["player"][0]))
  1382.         s.bulletTimeStamp = S.time.time
  1383.         s.bulletCount -= 1
  1384.    
  1385.     def die(s):
  1386.         s.bulletCount = 0
  1387.  
  1388.     def do(s, S):
  1389.         global SHOOTER_COLOR
  1390.         global SHOOTER_FIRE_DELAY
  1391.         global GRAVITY
  1392.  
  1393.         if not s.stopped:
  1394.             s.RECT.y += s.yv
  1395.             s.yv -= s.gravity
  1396.  
  1397.             if s.RECT.y1() == s.y - 1:
  1398.                 s.yv = 0
  1399.                 s.stopped = True
  1400.  
  1401.                 S.delPlaceHolder(s.placeHolder)
  1402.                 S.addObject(beacon(s, SHOOTER_COLOR))
  1403.  
  1404.                 s.fireBullet(S)
  1405.  
  1406.         now = S.time.time
  1407.         if s.stopped:
  1408.             if now - s.bulletTimeStamp >= SHOOTER_FIRE_DELAY and s.bulletCount:
  1409.                 s.fireBullet(S)
  1410.             elif not s.bulletCount:
  1411.                 s.RECT.y += s.yv
  1412.                 s.yv += GRAVITY
  1413.                 if s.RECT.y >= H:
  1414.                     s.RECT.dead = True
  1415.            
  1416. BEACON_MAX_SIZE = 100
  1417. BEACON_DURATION = 0.5 # secs
  1418. BEACON_FRAMES = int(FPS * BEACON_DURATION)
  1419. BEACON_GROW_PER_FRAME = int(BEACON_MAX_SIZE / BEACON_FRAMES)
  1420. BEACON_OPACITY_CHUNK = 128 / BEACON_FRAMES
  1421.  
  1422. class beacon:
  1423.     ID = "beacon"
  1424.     LAYER = "beacons"
  1425.  
  1426.     def __init__(s, obj, color):
  1427.         s.RECT = rect(obj.RECT.intRect())
  1428.         s.RECT.collisionActive = False
  1429.         s.objRect = obj.RECT
  1430.  
  1431.         s.color = color
  1432.         s.opacity = 128
  1433.  
  1434.     def draw(s):
  1435.         global DS
  1436.         pygame.gfxdraw.box(DS, s.RECT.intRect(), s.color + [s.opacity])
  1437.  
  1438.     def do(s, S):
  1439.         global BEACON_GROW_PER_FRAME, BEACON_OPACITY_CHUNK
  1440.  
  1441.         s.RECT.x -= BEACON_GROW_PER_FRAME
  1442.         s.RECT.y -= BEACON_GROW_PER_FRAME
  1443.         s.RECT.w += BEACON_GROW_PER_FRAME * 2
  1444.         s.RECT.h += BEACON_GROW_PER_FRAME * 2
  1445.  
  1446.         if s.opacity > 0:
  1447.             s.opacity -= BEACON_OPACITY_CHUNK
  1448.             if s.opacity <= 0:
  1449.                 s.opacity = 0
  1450.                 s.RECT.dead = True        
  1451.  
  1452. SCORE_SCALE = 5
  1453. SCORE_SHAKE_SIZE = 3
  1454. SCORE_SHAKE_TIME = 0.5 # secs
  1455. SCORE_SHAKE_FRAMES = int(FPS * SCORE_SHAKE_TIME)
  1456. SCORE_BACKGROUND_COLOR = BLACK
  1457. SCORE_PREVIEW_DROP_HEIGHT = H - 100 # pixels
  1458. SCORE_PREVIEW_DROP_TIME = 1 # secs
  1459. SCORE_PREVIEW_DROP_FRAMES = int(FPS * SCORE_PREVIEW_DROP_TIME)
  1460. SCORE_PREVIEW_GRAVITY = 2 * SCORE_PREVIEW_DROP_HEIGHT / (SCORE_PREVIEW_DROP_FRAMES * (SCORE_PREVIEW_DROP_FRAMES - 1))
  1461. SCORE_PREVIEW_VELOCITY = SCORE_PREVIEW_GRAVITY * (SCORE_PREVIEW_DROP_FRAMES - 1)
  1462. SCORE_PREVIEW_OPACITY_CHUNK = 255 / SCORE_PREVIEW_DROP_FRAMES
  1463. SCORE_PREVIEW_SCALE = 3
  1464.  
  1465. class score:
  1466.     ID = "score"
  1467.     LAYER = ID
  1468.     ADD_IMMEDIATELY = True
  1469.  
  1470.     class preview:
  1471.         def __init__(s, S, value, score):
  1472.             global SCORE_SCALE
  1473.             global SCORE_PREVIEW_SCALE
  1474.             global SCORE_PREVIEW_DROP_HEIGHT, SCORE_PREVIEW_VELOCITY
  1475.             global SCORE_BACKGROUND_COLOR
  1476.             global W, H
  1477.  
  1478.             s.surface = S.font.text(str(value), SCORE_PREVIEW_SCALE) #.convert_alpha()
  1479.             s.surface.set_colorkey(SCORE_BACKGROUND_COLOR)
  1480.             #s.surface.set_alpha(0)
  1481.  
  1482.             s.w, s.h = s.surface.get_size()
  1483.             s.x = W - 10 - s.w
  1484.             s.y = H - 10 - (S.font.size("A", SCORE_SCALE)[1] / 2) - SCORE_PREVIEW_DROP_HEIGHT - s.h
  1485.             s.yv = 0
  1486.             s.opacity = 0
  1487.        
  1488.             s.score = score
  1489.  
  1490.             s.dead = False
  1491.  
  1492.         def draw(s):
  1493.             global DS
  1494.             DS.blit(s.surface, (s.x, int(s.y)))
  1495.  
  1496.         def do(s):
  1497.             global SCORE_PREVIEW_OPACITY_CHUNK, SCORE_PREVIEW_GRAVITY
  1498.  
  1499.             s.y += s.yv
  1500.             s.yv += SCORE_PREVIEW_GRAVITY
  1501.  
  1502.             s.opacity += SCORE_PREVIEW_OPACITY_CHUNK
  1503.             if s.opacity >= 255:
  1504.                 s.opacity = 255
  1505.                 s.dead = True
  1506.             s.surface.set_alpha(int(s.opacity))
  1507.  
  1508.     def __init__(s, S):
  1509.         global SCORE_SCALE
  1510.         global SCORE_BACKGROUND_COLOR
  1511.  
  1512.         s.RECT = rect([0, 0, 0 ,0])
  1513.         s.RECT.collisionActive = False
  1514.  
  1515.         s.previews = []
  1516.  
  1517.         s.shake = False
  1518.         s.shakeX = 0
  1519.         s.shakeY = 0
  1520.         s.shakeTimeStamp = 0
  1521.  
  1522.         s.prevScore = 0
  1523.         s.surface = S.font.text(str(S.score), SCORE_SCALE)
  1524.         s.width, s.height = s.surface.get_size()
  1525.         s.surface.set_colorkey(SCORE_BACKGROUND_COLOR)
  1526.  
  1527.     def draw(s):
  1528.         global W, H
  1529.         global DS
  1530.        
  1531.         DS.blit(s.surface, (W - 10 - s.width + s.shakeX, H - 10 - s.height + s.shakeY))
  1532.         for preview in s.previews:
  1533.             preview.draw()
  1534.    
  1535.     def do(s, S):
  1536.         global SCORE_SCALE
  1537.         global SCORE_SHAKE_FRAMES
  1538.         global SCORE_BACKGROUND_COLOR
  1539.  
  1540.         if S.score != s.prevScore:
  1541.             value = S.score - s.prevScore
  1542.             if value > 0:
  1543.                 s.previews.append(s.preview(S, value, S.score))
  1544.             else:
  1545.                 s.surface = S.font.text(str(S.score), SCORE_SCALE)
  1546.                 s.width, s.height = s.surface.get_size()
  1547.                 s.surface.set_colorkey(SCORE_BACKGROUND_COLOR)
  1548.             s.prevScore = S.score
  1549.         deadPreviews = []
  1550.         for preview in s.previews:
  1551.             preview.do()
  1552.             if preview.dead:
  1553.                 deadPreviews.append(preview)
  1554.                 s.surface = S.font.text(str(preview.score), SCORE_SCALE)
  1555.                 s.width, s.height = s.surface.get_size()
  1556.                 s.surface.set_colorkey(SCORE_BACKGROUND_COLOR)
  1557.                 s.shake = True
  1558.                 s.shakeTimeStamp = S.time.time
  1559.         for deleteThis in deadPreviews:
  1560.             s.previews.remove(deleteThis)
  1561.        
  1562.         if s.shake:
  1563.             if S.time.time - s.shakeTimeStamp < SCORE_SHAKE_FRAMES:
  1564.                 s.shakeX = random.randint(-SCORE_SHAKE_SIZE, SCORE_SHAKE_SIZE)
  1565.                 s.shakeY = random.randint(-SCORE_SHAKE_SIZE, SCORE_SHAKE_SIZE)
  1566.             else:
  1567.                 s.shake = False
  1568.                 s.shakeX, s.shakeY = 0, 0
  1569.  
  1570.        
  1571. LIFE_SIZE = 20
  1572. LIFE_COLOR = [255, 186, 97]
  1573. LIFE_FALL_TIME = 0.5 # seconds
  1574. LIFE_FALL_FRAMES = int(FPS * LIFE_FALL_TIME)
  1575. LIFE_FALL_HEIGHT = 100
  1576. LIFE_FALL_GRAVITY = 2 * LIFE_FALL_HEIGHT / (LIFE_FALL_FRAMES * (LIFE_FALL_FRAMES - 1))
  1577. LIFE_OPACITY_CHUNK = 255 / LIFE_FALL_FRAMES
  1578.  
  1579. LIVES_AT_START = 3
  1580.  
  1581. class lives:
  1582.     ID = "lives"
  1583.     LAYER = ID
  1584.     ADD_IMMEDIATELY = True
  1585.  
  1586.     class life:
  1587.         def __init__(s, x, y):
  1588.             global LIFE_SIZE
  1589.             s.RECT = rect([x, y, LIFE_SIZE, LIFE_SIZE])
  1590.            
  1591.             s.opactiy = 255
  1592.             s.yv = 0
  1593.             s.dead = False
  1594.            
  1595.         def draw(s):
  1596.             global LIFE_COLOR
  1597.             global DS
  1598.             pygame.gfxdraw.box(DS, s.RECT.intRect(), LIFE_COLOR + [int(s.opactiy)])
  1599.  
  1600.         def do(s):
  1601.             global GRAVITY
  1602.  
  1603.             s.RECT.y += s.yv
  1604.             s.yv += LIFE_FALL_GRAVITY
  1605.             if s.opactiy:
  1606.                 s.opactiy -= LIFE_OPACITY_CHUNK
  1607.                 if s.opactiy < 0:
  1608.                     s.dead = True
  1609.  
  1610.     def __init__(s, S):
  1611.         global LIFE_SIZE
  1612.         global LIVES_AT_START
  1613.         global W
  1614.  
  1615.         s.RECT = rect([0, 0, 0 ,0])
  1616.         s.RECT.collisionActive = False
  1617.  
  1618.         S.lives = LIVES_AT_START
  1619.         s.prevLives = LIVES_AT_START
  1620.  
  1621.         startPos = W - (LIFE_SIZE + 10) * LIVES_AT_START
  1622.         s.container = [s.life(startPos + index * (LIFE_SIZE + 10), 10) for index in range(0, LIVES_AT_START)]
  1623.         s.deadContainer = []
  1624.  
  1625.     def draw(s):
  1626.         global DS
  1627.         for life in s.container + s.deadContainer:
  1628.             life.draw()
  1629.  
  1630.     def do(s, S):
  1631.         if S.lives != s.prevLives:
  1632.             s.prevLives = S.lives
  1633.             s.deadContainer.append(s.container.pop(0))
  1634.             S.layers["player"][0].die()
  1635.        
  1636.         if not S.lives and not S.layers["player"][0].dead:
  1637.             S.gameOver = True
  1638.  
  1639.         deleteLives = []
  1640.         for deadLife in s.deadContainer:
  1641.             deadLife.do()
  1642.             if deadLife.dead: deleteLives.append(deadLife)
  1643.         for deleteThis in deleteLives:
  1644.             s.deadContainer.remove(deleteThis)
  1645.  
  1646. pygame.init()
  1647. DS = pygame.display.set_mode((W, H))
  1648.  
  1649. TIME = gameTime(FPS)
  1650. FONT = font(imgUnzip(FONT_DATA), FONT_CHARMAP, 1)
  1651.  
  1652. TITLE_LAYERS = ["background", "other"]
  1653.  
  1654. TITLE_OBJECT_LIST = [background]
  1655.  
  1656. GAME_STAGE_LAYERS = [
  1657.     "background",
  1658.     "beacons",
  1659.     "score",  
  1660.     "lives",      
  1661.     "platforms",
  1662.     "objects",
  1663.     "player",
  1664.     "fire",
  1665.     "bullets",
  1666.     "stars",
  1667.     "pointer"
  1668. ]
  1669.  
  1670. GAME_OBJECTS = [background, platform, player, platformPointer, score, lives, food, bouncer, bumper, shooter, wall]
  1671.  
  1672. GAME_STAGE = stage()
  1673. GAME_STAGE.setTimer(TIME)
  1674. GAME_STAGE.setLayers(GAME_STAGE_LAYERS)
  1675. GAME_STAGE.setObjects(GAME_OBJECTS)
  1676. GAME_STAGE.setFont(FONT)
  1677. GAME_STAGE.reset()
  1678.  
  1679. # Main loop
  1680. while not GAME_STAGE.gameOver:
  1681.     e = pygame.event.get()
  1682.     if pygame.key.get_pressed()[pygame.K_ESCAPE]: break
  1683.  
  1684.     GAME_STAGE.do()
  1685. pygame.quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement