Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import sys, time, random, os, base64
- import pygame
- BLACK = (0, 0, 0)
- WHITE = (255, 255, 255)
- RED = (128, 0, 0)
- GREEN = (0, 128, 0)
- BLUE = (0, 0, 128)
- DARK_GRAY = (32, 32, 32)
- LOVELY_BLUE = (22, 54, 83)
- SPRITE_DATA_FILENAME = "blocks.png"
- SPRITE_DATA = b'iVBORw0KGgoAAAANSUhEUgAAACoAAAAGCAMAAACCc/wkAAAAAXNSR0IArs4c6QAAAGBQTFRFAAA\
- AIiA0RSg8Zjkxj1Y733Em2aBm7sOa+/I2meVQar4wN5RuS2kvUkskMjw5Pz90MGCCW27hY5v/X83k\
- y9v8////m623hH6HaWpqWVZSdkKKrDIy2Vdj13u6j5dKim8w+2O8zwAAACB0Uk5TAP///////////\
- /////////////////////////////+Smq12AAAAPklEQVQYlWMQJRowiDIAAYRGIxmgJEQVhIDwEB\
- KiUA1gBFYFUQYXYhBF0oBQCrMHyQEMokgkQgOSCxiI9xYACEgN8+zH0H8AAAAASUVORK5CYII='
- SHAPES = [
- [
- [
- [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0] # O
- ]
- ],
- [
- [
- [0, 0, 0, 0], [2, 2, 2, 2], [0, 0, 0, 0], [0, 0, 0, 0] # I
- ],
- [
- [0, 0, 2, 0], [0, 0, 2, 0], [0, 0, 2, 0], [0, 0, 2, 0]
- ]
- ],
- [
- [
- [0, 0, 0, 0], [0, 0, 3, 3], [0, 3, 3, 0], [0, 0, 0, 0] # S
- ],
- [
- [0, 0, 3, 0], [0, 0, 3, 3], [0, 0, 0, 3], [0, 0, 0, 0]
- ]
- ],
- [
- [
- [0, 0, 0, 0], [0, 4, 4, 0], [0, 0, 4, 4], [0, 0, 0, 0] # Z
- ],
- [
- [0, 0, 0, 4], [0, 0, 4, 4], [0, 0, 4, 0], [0, 0, 0, 0]
- ]
- ],
- [
- [
- [0, 0, 0, 0], [0, 5, 5, 5], [0, 5, 0, 0], [0, 0, 0, 0] # L
- ],
- [
- [0, 0, 5, 0], [0, 0, 5, 0], [0, 0, 5, 5], [0, 0, 0, 0]
- ],
- [
- [0, 0, 0, 5], [0, 5, 5, 5], [0, 0, 0, 0], [0, 0, 0, 0]
- ],
- [
- [0, 5, 5, 0], [0, 0, 5, 0], [0, 0, 5, 0], [0, 0, 0, 0]
- ]
- ],
- [
- [
- [0, 0, 0, 0], [0, 6, 6, 6], [0, 0, 0, 6], [0, 0, 0, 0] # J
- ],
- [
- [0, 0, 6, 6], [0, 0, 6, 0], [0, 0, 6, 0], [0, 0, 0, 0]
- ],
- [
- [0, 6, 0, 0], [0, 6, 6, 6], [0, 0, 0, 0], [0, 0, 0, 0]
- ],
- [
- [0, 0, 6, 0], [0, 0, 6, 0], [0, 6, 6, 0], [0, 0, 0, 0]
- ]
- ],
- [
- [
- [0, 0, 0, 0], [0, 7, 7, 7], [0, 0, 7, 0], [0, 0, 0, 0] # T
- ],
- [
- [0, 0, 7, 0], [0, 0, 7, 7], [0, 0, 7, 0], [0, 0, 0, 0]
- ],
- [
- [0, 0, 7, 0], [0, 7, 7, 7], [0, 0, 0, 0], [0, 0, 0, 0]
- ],
- [
- [0, 0, 7, 0], [0, 7, 7, 0], [0, 0, 7, 0], [0, 0, 0, 0]
- ]
- ],
- ]
- # handy way of working with coordinate integers
- class vect:
- def __init__(s, x, y = None):
- if type(x) is tuple:
- s.x = int(x[0])
- s.y = int(x[1])
- else:
- s.x = int(x)
- if y == None:
- s.y = s.x
- else:
- s.y = int(y)
- s.v = (s.x, s.y)
- def __add__(s, n):
- if type(n) is tuple:
- return vect(s.x + n[0], s.y + n[1])
- elif type(n) is vect:
- return vect(s.x + n.x, s.y + n.y)
- else:
- return vect(s.x + n, s.y + n)
- def __sub__(s, n):
- if type(n) is tuple:
- return vect(s.x - n[0], s.y - n[1])
- elif type(n) is vect:
- return vect(s.x - n.x, s.y - n.y)
- else:
- return vect(s.x - n, s.y - n)
- def __mul__(s, n):
- if type(n) is tuple:
- return vect(s.x * n[0], s.y * n[1])
- elif type(n) is vect:
- return vect(s.x * n.x, s.y * n.y)
- else:
- return vect(s.x * n, s.y * n)
- def __truediv__(s, n):
- if type(n) is tuple:
- return vect(s.x / n[0], s.y / n[1])
- elif type(n) is vect:
- return vect(s.x / n.x, s.y / n.y)
- else:
- return vect(s.x / n, s.y / n)
- def __str__(s):
- return "({}, {})".format(s.x, s.y)
- def setX(s, x):
- s.x = x
- s.v = (x, s.y)
- def setY(s, y):
- s.y = y
- s.v = (s.x, y)
- class spritesheet:
- def __init__(s, surface, cols, rows, colorkey = None):
- # sprite sheet surface
- s.sheet = surface
- # get width and height
- s.sheetSize = vect(surface.get_rect().size)
- # n rows and n columns
- s.grid = vect(cols, rows)
- # list to references the subsurfaces of the spritesheet.
- s.sprites = []
- # size of each individual sprite
- s.cellSize = s.sheetSize / s.grid
- # iterate through spritesheet to define individual subsurfaces
- for y in range(rows):
- for x in range(cols):
- # get position of each sprite
- pos = vect(x, y) * s.cellSize
- # add subsprite to the list
- s.sprites.append(surface.subsurface((pos.v, s.cellSize.v)))
- # return a sprite by id
- def get(s, id):
- return s.sprites[id]
- class shape:
- def __init__(s, id):
- global SHAPES
- # shape id
- s.id = id
- # rotation
- s.r = 0
- # maxium number of available shape rotations
- s.maxr = len(SHAPES[id])
- # if the top row of the shape is blank then y = -1
- if sum(SHAPES[id][0][0]):
- s.pos = vect(3, 0)
- else:
- s.pos = vect(3, -1)
- def draw(s, addBlur = False):
- global PAS # play area surface
- global SHAPES
- for y in range(4):
- for x in range(4):
- bid = SHAPES[s.id][s.r][y][x] # block sprite id
- # blit sprite to play area surface if bid > 0
- if bid:
- if addBlur:
- PAS.blit(SPRITES.get(7), ((s.pos + vect(x, y - 1)) * SPRITES.cellSize).v)
- PAS.blit(SPRITES.get(bid - 1), ((s.pos + vect(x, y)) * SPRITES.cellSize).v)
- def collision(s, offset, rOffset = None):
- global PLAY_AREA, PLAY_AREA_SIZE, SHAPES
- # check if collision involves shape rotation
- if rOffset == None:
- # grab a copy of the shape data if using current rotation value
- shapeData = SHAPES[s.id][s.r]
- else:
- # adjust rotation if it has gone out of bounds
- rotation = s.r + rOffset
- if rotation >= s.maxr: rotation = 0
- elif rotation < 0: rotation = s.maxr - 1
- # grab a copy of the shape data using new rotation value
- shapeData = SHAPES[s.id][rotation]
- # iterate throught the shape data to determine:
- # 1. has the shape collided with the wall?
- # 2. has the shape collided with the floor?
- # 3. does the shape rotate out of the ceiling?
- # 3. has the shape collided with the stack?
- for y in range(4):
- for x in range(4):
- # calculate the absolute position of each block within the shape.
- pos = s.pos + vect(x, y) + offset
- # if the shape data is a block ie has a value >0
- if shapeData[y][x]:
- if pos.x < 0 or pos.x > PLAY_AREA_SIZE.x - 1: return "WALL"
- if pos.y > PLAY_AREA_SIZE.y - 1: return "FLOOR"
- if pos.y < 0: return "CEILING"
- if PLAY_AREA[pos.y][pos.x]: return "STACK"
- # no collision detected
- return "OK"
- # add the shape to play areas data
- def solidify(s):
- global SHAPES, PLAY_AREA
- for y in range(4):
- for x in range(4):
- # get the block id from the shape data
- bid = SHAPES[s.id][s.r][y][x]
- # if the block data >0
- if bid:
- # get the absolution position of the shape's block in the play area
- pos = s.pos + (x, y)
- # copy the block data to the play area
- PLAY_AREA[pos.y][pos.x] = bid
- # increment the rotation clockwise by one
- def rotate(s):
- s.r += 1
- if s.r >= s.maxr: s.r = 0
- # start pygame and create primary display surface (PDS)
- pygame.init()
- PDR = pygame.Rect(0, 0, 1024, 720)
- PDS = pygame.display.set_mode(PDR.size)
- FPS = 30
- # check if the blocks.png exists. If not then create it
- if not os.path.exists(SPRITE_DATA_FILENAME):
- print("Writing title image...", end = "")
- data = base64.b64decode(SPRITE_DATA)
- r = open(SPRITE_DATA_FILENAME, "bw")
- r.write(data)
- r.close()
- print("Done!")
- # load the spritesheet
- BLOCK_SPRITES = pygame.image.load("blocks.png").convert_alpha()
- SPRITES = spritesheet(BLOCK_SPRITES, 8, 1)
- # define the scale of the graphics
- SCALE = vect(5)
- # define the size in blocks of the play area
- PLAY_AREA_SIZE = vect(10, 20)
- # define the play area data. A 2 dimensional list
- PLAY_AREA = [[0] * PLAY_AREA_SIZE.x for y in range(PLAY_AREA_SIZE.y)]
- # the size of play area surface in pixels
- PLAY_AREA_PIXEL_SIZE = PLAY_AREA_SIZE * SPRITES.cellSize
- # scaled size of the play area in pixels
- SCALED_PLAY_AREA_PIXEL_SIZE = PLAY_AREA_PIXEL_SIZE * SCALE
- SCALED_PLAY_AREA_PLACEMENT = (vect(PDR.size) - SCALED_PLAY_AREA_PIXEL_SIZE) / 2
- # create play area surface
- PAS = pygame.Surface(PLAY_AREA_PIXEL_SIZE.v)
- # define the shape
- currentShape = shape(random.randint(0, 6))
- # drop down one line timer
- TIMER_DURATION = 15
- timer = TIMER_DURATION
- # prevent the shape spining like a catherine wheel if the up key if held down
- rotateKeyDown = False
- # add blur lines if the player presses down key
- drawDropLines = False
- while True:
- events = pygame.event.get()
- for e in events:
- if e.type == pygame.QUIT: sys.exit()
- # clear the play area
- PAS.fill(LOVELY_BLUE)
- # draw the current shape
- currentShape.draw(drawDropLines)
- # translate the play area data into sprites IDs to blit of the play area surface
- for y in range(PLAY_AREA_SIZE.y):
- for x in range(PLAY_AREA_SIZE.x):
- # get data from the play area located at y,x
- id = PLAY_AREA[y][x]
- # if the data in the play area list is >0 then translate to sprite ID and blit
- if id:
- PAS.blit(SPRITES.get(id - 1), (vect(x, y) * SPRITES.cellSize).v)
- # update the display
- PDS.blit(pygame.transform.scale(PAS, SCALED_PLAY_AREA_PIXEL_SIZE.v), SCALED_PLAY_AREA_PLACEMENT.v)
- pygame.display.update()
- pygame.time.Clock().tick(FPS)
- # decrement the drop timer
- timer -= 1
- # if the drop timer reaches zero set the y velocity to 1 (ie drops one line)
- if timer <= 0:
- timer = TIMER_DURATION
- drawDropLines = False
- collisionResults = currentShape.collision((0, 1))
- if collisionResults == "FLOOR" or collisionResults == "STACK":
- # add the shape to the play area's data
- currentShape.solidify()
- currentShape = shape(random.randint(0, 6))
- """ STACKOVER FLOW QUESTION START """
- newPLAY_AREA = []
- fullRowsCount = 0
- for row in reversed(PLAY_AREA):
- rowBlockCount = sum(col > 0 for col in row)
- if rowBlockCount < PLAY_AREA_SIZE.x:
- newPLAY_AREA = [row] + newPLAY_AREA
- else:
- fullRowsCount += 1
- if fullRowsCount:
- newPLAY_AREA = [[0] * PLAY_AREA_SIZE.x] * fullRowsCount + newPLAY_AREA
- PLAY_AREA = newPLAY_AREA
- del newPLAY_AREA
- """ STACKOVER FLOW QUESTION END """
- continue
- # move the shape down if no collision with the stack
- currentShape.pos += (0, 1)
- # get key presses and move/rotate the current shape
- k = pygame.key.get_pressed()
- if k[pygame.K_RIGHT]:
- if currentShape.collision((1, 0)) == "OK":
- currentShape.pos += (1, 0)
- elif k[pygame.K_LEFT]:
- if currentShape.collision((-1, 0)) == "OK":
- currentShape.pos += (-1, 0)
- if k[pygame.K_UP] and not rotateKeyDown:
- rotateKeyDown = True
- if currentShape.collision((0, 0), 1) == "OK":
- currentShape.rotate()
- elif not k[pygame.K_UP] and rotateKeyDown:
- rotateKeyDown = False
- if k[pygame.K_DOWN]:
- timer = 0
- drawDropLines = True
- else:
- drawDropLines = False
- if k[pygame.K_SPACE]:
- pass
- pygame.quit()
- sys.exit()
Add Comment
Please, Sign In to add comment