Skip to content

Instantly share code, notes, and snippets.

@roger35972134
Created June 16, 2015 10:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roger35972134/5a46d4b218d660b58d52 to your computer and use it in GitHub Desktop.
Save roger35972134/5a46d4b218d660b58d52 to your computer and use it in GitHub Desktop.
# Tetromino for Idiots
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
import random, time, pygame, sys
from pygame.locals import *
偵數 = 25
視窗寬度 = 640
視窗高度 = 480
盒子大小 = 20
板寬 = 10
板高 = 20
空白 = '.'
平移速度頻率 = 0.15
落下速度頻率 = 0.1
水平邊界 = int((視窗寬度 - 板寬 * 盒子大小) / 2)
上邊界 = 視窗高度 - (板高 * 盒子大小) - 5
# R G B
WHITE = (255, 255, 255)
GRAY = (185, 185, 185)
BLACK = ( 0, 0, 0)
RED = (155, 0, 0)
LIGHTRED = (175, 20, 20)
GREEN = ( 0, 155, 0)
LIGHTGREEN = ( 20, 175, 20)
BLUE = ( 0, 0, 155)
LIGHTBLUE = ( 20, 20, 175)
YELLOW = (155, 155, 0)
LIGHTYELLOW = (175, 175, 20)
版面顏色 = BLUE
背景顏色 = BLACK
文字顏色 = WHITE
文字陰影顏色 = GRAY
顏色 = ( BLUE, GREEN, RED, YELLOW)
亮色系顏色 = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW)
assert len(顏色) == len(亮色系顏色) # each color must have light color
TEMPLATEWIDTH = 5
TEMPLATEHEIGHT = 5
SHAPE_TEMPLATE = [['.....',
'.....',
'..O..',
'.....',
'.....']]
方塊 = {'A': SHAPE_TEMPLATE}
def main():
global 偵數時鐘, 顯示畫面, 基本字型, 大字型
pygame.init()
偵數時鐘 = pygame.time.Clock()
顯示畫面 = pygame.display.set_mode((視窗寬度, 視窗高度))
基本字型 = pygame.font.Font('freesansbold.ttf', 18)
大字型 = pygame.font.Font('freesansbold.ttf', 60)
pygame.display.set_caption('Tetromino for Idiots')
顯示文字('Tetromino for Idiots')
while True: # game loop
if random.randint(0, 1) == 0:
pygame.mixer.music.load('tetrisb.mid')
else:
pygame.mixer.music.load('tetrisc.mid')
pygame.mixer.music.play(-1, 0.0)
執行遊戲()
pygame.mixer.music.stop()
顯示文字('Game Over')
def 執行遊戲():
# setup variables for the start of the game
版面 = 做板子()
最後下移時間 = time.time()
最後平移時間 = time.time()
最後落下時間 = time.time()
下移 = False # note: there is no movingUp variable
左移 = False
右移 = False
分數 = 0
等級, 落下頻率 = 等級與落下頻率(分數)
落下中的方塊 = 取得新方塊()
下個方塊 = 取得新方塊()
while True: # game loop
if 落下中的方塊 == None:
# No falling piece in play, so start a new piece at the top
落下中的方塊 = 下個方塊
下個方塊 = 取得新方塊()
最後落下時間 = time.time() # reset lastFallTime
if not isValidPosition(版面, 落下中的方塊):
return # can't fit a new piece on the board, so game over
退出()
for event in pygame.event.get(): # event handling loop
if event.type == KEYUP:
if (event.key == K_p):
# Pausing the game
顯示畫面.fill(背景顏色)
pygame.mixer.music.stop()
顯示文字('Paused') # pause until a key press
pygame.mixer.music.play(-1, 0.0)
最後落下時間 = time.time()
最後下移時間 = time.time()
最後平移時間 = time.time()
elif (event.key == K_LEFT or event.key == K_a):
左移 = False
elif (event.key == K_RIGHT or event.key == K_d):
右移 = False
elif (event.key == K_DOWN or event.key == K_s):
下移 = False
elif event.type == KEYDOWN:
# moving the piece sideways
if (event.key == K_LEFT or event.key == K_a) and isValidPosition(版面, 落下中的方塊, adjX=-1):
落下中的方塊['x'] -= 1
左移 = True
右移 = False
最後平移時間 = time.time()
elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(版面, 落下中的方塊, adjX=1):
落下中的方塊['x'] += 1
右移 = True
左移 = False
最後平移時間 = time.time()
# rotating the piece (if there is room to rotate)
elif (event.key == K_UP or event.key == K_w):
落下中的方塊['rotation'] = (落下中的方塊['rotation'] + 1) % len(方塊[落下中的方塊['shape']])
if not isValidPosition(版面, 落下中的方塊):
落下中的方塊['rotation'] = (落下中的方塊['rotation'] - 1) % len(方塊[落下中的方塊['shape']])
elif (event.key == K_q): # rotate the other direction
落下中的方塊['rotation'] = (落下中的方塊['rotation'] - 1) % len(方塊[落下中的方塊['shape']])
if not isValidPosition(版面, 落下中的方塊):
落下中的方塊['rotation'] = (落下中的方塊['rotation'] + 1) % len(方塊[落下中的方塊['shape']])
# making the piece fall faster with the down key
elif (event.key == K_DOWN or event.key == K_s):
下移 = True
if isValidPosition(版面, 落下中的方塊, adjY=1):
落下中的方塊['y'] += 1
最後下移時間 = time.time()
# move the current piece all the way down
elif event.key == K_SPACE:
下移 = False
左移 = False
右移 = False
for i in range(1, 板高):
if not isValidPosition(版面, 落下中的方塊, adjY=i):
break
落下中的方塊['y'] += i - 1
# handle moving the piece because of user input
if (左移 or 右移) and time.time() - 最後平移時間 > 平移速度頻率:
if 左移 and isValidPosition(版面, 落下中的方塊, adjX=-1):
落下中的方塊['x'] -= 1
elif 右移 and isValidPosition(版面, 落下中的方塊, adjX=1):
落下中的方塊['x'] += 1
最後平移時間 = time.time()
if 下移 and time.time() - 最後下移時間 > 落下速度頻率 and isValidPosition(版面, 落下中的方塊, adjY=1):
落下中的方塊['y'] += 1
最後下移時間 = time.time()
# let the piece fall if it is time to fall
if time.time() - 最後落下時間 > 落下頻率:
# see if the piece has landed
if not isValidPosition(版面, 落下中的方塊, adjY=1):
# falling piece has landed, set it on the board
addTo版面(版面, 落下中的方塊)
分數 += 移除完滿行(版面)
等級, 落下頻率 = 等級與落下頻率(分數)
落下中的方塊 = None
else:
# piece did not land, just move the piece down
落下中的方塊['y'] += 1
最後落下時間 = time.time()
# drawing everything on the screen
顯示畫面.fill(背景顏色)
版面設計(版面)
顯示資訊(分數, 等級)
顯示下個方塊(下個方塊)
if 落下中的方塊 != None:
顯示方塊(落下中的方塊)
pygame.display.update()
偵數時鐘.tick(偵數)
def 製作文字物件(text, font, color):
surf = font.render(text, True, color)
return surf, surf.get_rect()
def 檔案結束():
pygame.quit()
sys.exit()
def 檢查按鍵輸入():
# Go through event queue looking for a KEYUP event.
# Grab KEYDOWN events to remove them from the event queue.
退出()
for event in pygame.event.get([KEYDOWN, KEYUP]):
if event.type == KEYDOWN:
continue
return event.key
return None
def 顯示文字(text):
# This function displays large text in the
# center of the screen until a key is pressed.
# Draw the text drop shadow
titleSurf, titleRect = 製作文字物件(text, 大字型, 文字陰影顏色)
titleRect.center = (int(視窗寬度 / 2), int(視窗高度 / 2))
顯示畫面.blit(titleSurf, titleRect)
# Draw the text
titleSurf, titleRect = 製作文字物件(text, 大字型, 文字顏色)
titleRect.center = (int(視窗寬度 / 2) - 2, int(視窗高度 / 2) - 2)
顯示畫面.blit(titleSurf, titleRect)
# Draw the additional "Press a key to play." text.
pressKeySurf, pressKeyRect = 製作文字物件('Press a key to play.', 基本字型, 文字顏色)
pressKeyRect.center = (int(視窗寬度 / 2), int(視窗高度 / 2) + 100)
顯示畫面.blit(pressKeySurf, pressKeyRect)
while 檢查按鍵輸入() == None:
pygame.display.update()
偵數時鐘.tick()
def 退出():
for event in pygame.event.get(QUIT): # get all the QUIT events
檔案結束() # terminate if any QUIT events are present
for event in pygame.event.get(KEYUP): # get all the KEYUP events
if event.key == K_ESCAPE:
檔案結束() # terminate if the KEYUP event was for the Esc key
pygame.event.post(event) # put the other KEYUP event objects back
def 等級與落下頻率(分數):
# Based on the 分數, return the level the player is on and
# how many seconds pass until a falling piece falls one space.
等級 = int(分數 / 10) + 1
落下頻率 = 0.27 - (等級 * 0.02)
return 等級, 落下頻率
def 取得新方塊():
# return a random new piece in a random rotation and color
shape = random.choice(list(方塊.keys()))
newPiece = {'shape': shape,
'rotation': random.randint(0, len(方塊[shape]) - 1),
'x': int(板寬 / 2) - int(TEMPLATEWIDTH / 2),
'y': -2, # start it above the board (i.e. less than 0)
'color': random.randint(0, len(顏色)-1)}
return newPiece
def 新增至版面(版面, piece):
# fill in the board based on piece's location, shape, and rotation
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if 方塊[piece['shape']][piece['rotation']][y][x] != 空白:
版面[x + piece['x']][y + piece['y']] = piece['color']
def 做板子():
# create and return a new blank board data structure
版面 = []
for i in range(板寬):
版面.append([空白] * 板高)
return 版面
def 在版面上(x, y):
return x >= 0 and x < 板寬 and y < 板高
def isValidPosition(版面, piece, adjX=0, adjY=0):
# Return True if the piece is within the board and not colliding
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
isAboveBoard = y + piece['y'] + adjY < 0
if isAboveBoard or 方塊[piece['shape']][piece['rotation']][y][x] == 空白:
continue
if not 在版面上(x + piece['x'] + adjX, y + piece['y'] + adjY):
return False
if 版面[x + piece['x'] + adjX][y + piece['y'] + adjY] != 空白:
return False
return True
def 是否為完滿行(版面, y):
# Return True if the line filled with boxes with no gaps.
for x in range(板寬):
if 版面[x][y] == 空白:
return False
return True
def 移除完滿行(版面):
# Remove any completed lines on the board, move everything above them down, and return the number of complete lines.
numLinesRemoved = 0
y = 板高 - 1 # start y at the bottom of the board
while y >= 0:
if 是否為完滿行(版面, y):
# Remove the line and pull boxes down by one line.
for pullDownY in range(y, 0, -1):
for x in range(板寬):
版面[x][pullDownY] = 版面[x][pullDownY-1]
# Set very top line to blank.
for x in range(板寬):
版面[x][0] = 空白
numLinesRemoved += 1
# Note on the next iteration of the loop, y is the same.
# This is so that if the line that was pulled down is also
# complete, it will be removed.
else:
y -= 1 # move on to check next row up
return numLinesRemoved
def convertToPixelCoords(boxx, boxy):
# Convert the given xy coordinates of the board to xy
# coordinates of the location on the screen.
return (水平邊界 + (boxx * 盒子大小)), (上邊界 + (boxy * 盒子大小))
def drawBox(boxx, boxy, color, pixelx=None, pixely=None):
# draw a single box (each tetromino piece has four boxes)
# at xy coordinates on the board. Or, if pixelx & pixely
# are specified, draw to the pixel coordinates stored in
# pixelx & pixely (this is used for the "Next" piece).
if color == 空白:
return
if pixelx == None and pixely == None:
pixelx, pixely = convertToPixelCoords(boxx, boxy)
pygame.draw.rect(顯示畫面, 顏色[color], (pixelx + 1, pixely + 1, 盒子大小 - 1, 盒子大小 - 1))
pygame.draw.rect(顯示畫面, 亮色系顏色[color], (pixelx + 1, pixely + 1, 盒子大小 - 4, 盒子大小 - 4))
def 版面設計(版面):
# draw the border around the board
pygame.draw.rect(顯示畫面, 版面顏色, (水平邊界 - 3, 上邊界 - 7, (板寬 * 盒子大小) + 8, (板高 * 盒子大小) + 8), 5)
# fill the background of the board
pygame.draw.rect(顯示畫面, 背景顏色, (水平邊界, 上邊界, 盒子大小 * 板寬, 盒子大小 * 板高))
# draw the individual boxes on the board
for x in range(板寬):
for y in range(板高):
drawBox(x, y, 版面[x][y])
def 顯示資訊(分數, 等級):
# draw the score text
scoreSurf = 基本字型.render('Score: %s' % 分數, True, 文字顏色)
scoreRect = scoreSurf.get_rect()
scoreRect.topleft = (視窗寬度 - 150, 20)
顯示畫面.blit(scoreSurf, scoreRect)
# draw the level text
levelSurf = 基本字型.render('Level: %s' % 等級, True, 文字顏色)
levelRect = levelSurf.get_rect()
levelRect.topleft = (視窗寬度 - 150, 50)
顯示畫面.blit(levelSurf, levelRect)
def 顯示方塊(piece, pixelx=None, pixely=None):
shapeToDraw = 方塊[piece['shape']][piece['rotation']]
if pixelx == None and pixely == None:
# if pixelx & pixely hasn't been specified, use the location stored in the piece data structure
pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])
# draw each of the boxes that make up the piece
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if shapeToDraw[y][x] != 空白:
drawBox(None, None, piece['color'], pixelx + (x * 盒子大小), pixely + (y * 盒子大小))
def 顯示下個方塊(piece):
# draw the "next" text
nextSurf = 基本字型.render('Next:', True, 文字顏色)
nextRect = nextSurf.get_rect()
nextRect.topleft = (視窗寬度 - 120, 80)
顯示畫面.blit(nextSurf, nextRect)
# draw the "next" piece
顯示方塊(piece, pixelx=視窗寬度-120, pixely=100)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment