用pygame寫了個俄羅斯方塊
阿新 • • 發佈:2019-02-15
最近在學習pygame,就寫了個俄羅斯方塊玩玩,完成了基本的功能,後續在加入
需要安裝pygame,ubuntu使用者 sudo apt-get install python-pygame
程式碼入下
#-* coding:UTF-8 -* #!/usr/bin/env python import copy import pygame import random ALL_BLOCKS = [ [ [0, 0, 0, 0, 0], [1, 1, 1, 1, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ], [ [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ], [ [0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 1, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ], [ [0, 0, 0, 0, 0], [0, 1, 1, 0, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ], [ [0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0] ], [ [0, 0, 0, 0, 0], [0, 1, 1, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0] ], [ [0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ] ] def get_block(): return random.choice(ALL_BLOCKS) def get_line_block(): return ALL_BLOCKS[0] def rorate_block(block): ''' 90度旋轉方塊 ''' new_block = [[0 for col in range(5)] for row in range(5)] for x in range(5): for y in range(4, -1, -1): new_block[y][x] = block[x][4 - y] return new_block def print_block(block): for line in block: print '%s \n' % line def init_map(max_x, max_y, wall_widith, wall_height): ''' 初始化地圖,上左右加入牆壁 ''' maps = [[0 for col in range(max_x)]for cell in range(max_y)] for y in range(max_y): for x in range(max_x): if x < wall_widith or x > max_x - wall_widith - 1 or y > max_y - wall_height: maps[y][x] = 1 return maps SCREEN_SIZE = WIDTH, HEIGHT = [480, 660] BACKGROUND_COLOR = (123, 22, 33) BLOCK_COLOR = (33, 124, 33) WALL_COLOR = (14, 233, 4) WALL_WIDTH = 3 WALL_HEIGHT = 4 #地圖從(0,0)座標開始畫 MAP_BEGIN_POINT = [0, 0] #地圖的最大行數和列數 MAX_X, MAX_Y = 16, 22 #方塊的邊長 RECT_SIZE = [WIDTH/MAX_X, HEIGHT/MAX_Y] #螢幕中央的x座標 CENTER_X = int(MAX_X / 2) - 3 #地圖的資料 MAP_DATA = init_map(MAX_X, MAX_Y, WALL_WIDTH, WALL_HEIGHT) #方塊的起始位置 BLOCK_START_POINT = [CENTER_X, -1] #每秒的幀數 FPS = 40 #方塊的下落速度 SPEED = 1 #方塊自由體積下落的時間間隔 FALL_PER_SECONDS = 1 def draw(block_data, start_point, map_data, screen): ''' 將方塊的資料畫到地圖上,二維陣列的傳遞是傳址的 一維陣列使用[:]複製,二維陣列使用deepcopy ''' _map_data = copy.deepcopy(map_data) _map_start_point = MAP_BEGIN_POINT[:] #更新地圖 update_map(block_data, start_point, _map_data) #print_block(_map_data) begin_x = _map_start_point[0] #畫含有方塊的地圖 for line in _map_data: for block in line: #print 'draw at %s,%s' % (_start_point[0],_start_point[1]) rect = pygame.Rect(_map_start_point, RECT_SIZE) if block == 0: pygame.draw.rect(screen, BLOCK_COLOR, rect) if block == 1: pygame.draw.rect(screen, WALL_COLOR, rect, 1) _map_start_point[0] += RECT_SIZE[0] _map_start_point[1] += RECT_SIZE[1] _map_start_point[0] = begin_x def update_map(block_data, start_point, map_data): ''' 將方塊的陣列畫到地圖的數組裡面去 ''' _start_point_x = start_point[0] _start_point_y = start_point[1] for y in range(5): for x in range(5): #防止畫到牆外面 #print '_start_point_x is %s' % _start_point_x #print 'map_data[%s][%s] % s' % (_start_point_y+y,_start_point_x+x,map_data[_start_point_y+y][_start_point_x+x]) if _start_point_x + x <= WALL_WIDTH - 1 or _start_point_x + x >= MAX_X - WALL_WIDTH: continue if map_data[_start_point_y + y][_start_point_x + x] != 1: map_data[_start_point_y + y][_start_point_x + x] = block_data[y][x] def can_move(block_data, start_point, map_data): ''' 判斷方塊在地圖裡面是否發生相撞 ''' _start_point_x = start_point[0] _start_point_y = start_point[1] for y in range(5): for x in range(5): #print 'map_data[%s][%s] is: %s' % (_start_point_y + y, _start_point_x + x, map_data[_start_point_y + y][_start_point_x + x]) #到達兩側,不能移動 if block_data[y][x] and map_data[_start_point_y + y][_start_point_x + x]: return False return True def get_clear_lines(map_data): ''' 判斷哪些行可以進行消除,返回可以消除的行的y座標集合 ''' #記錄滿行的行的y座標 full_line_y_list = [] #如果整行都被1覆蓋,則認為可以消除 #從最底部開始向上掃描,如果發現可以消除,只需要再掃描往上三行即可 for y in range(-WALL_HEIGHT, -MAX_Y + 1, -1): if len([x for x in map_data[y] if x == 1]) == MAX_X: full_line_y_list.append(y) for y2 in range(1, 4): if len([x for x in map_data[y - y2] if x == 1]) == MAX_X: full_line_y_list.append(y - y2) break; return full_line_y_list def clear_lines(map_data): ''' 迴圈滿行的行,將陣列依次下移 ''' full_line_y_list = get_clear_lines(map_data) while full_line_y_list: for full_line_y in full_line_y_list: print 'full_line_y: %s' % full_line_y for y in range(full_line_y, -MAX_Y + 1, -1): for x in range(WALL_WIDTH, MAX_X - WALL_WIDTH): #print 'map_data[%s][%s] = map_data[%s][%s]' % (y,x,y-1,x) map_data[y][x] = map_data[y - 1][x] #print_block(map_data) full_line_y_list = get_clear_lines(map_data) print 'full_line_y_list is %s' % full_line_y_list def reach_bottom(block_data,block_left_top,map_data): ''' 讓方塊移動到最底部 ''' _block_left_top_x = block_left_top[0] _block_left_top_y = block_left_top[1] max_move_y = 0 for y in range(1,MAX_Y-WALL_HEIGHT+1): if can_move(block_data, [_block_left_top_x, _block_left_top_y + y], map_data): max_move_y += 1 else: break if max_move_y: block_left_top[1] += max_move_y update_map(block_data, block_left_top, map_data) clear_lines(map_data) print 'max_move_y is %s' % max_move_y return max_move_y def main(): pygame.init() clock = pygame.time.Clock() time_passed = 0 screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32) screen.fill(BACKGROUND_COLOR) map_data = copy.deepcopy(MAP_DATA) block_data = get_block() block_left_top = BLOCK_START_POINT[:] draw(block_data, block_left_top, map_data, screen) #print 'can_move: %s' % can_move(block_data,block_left_top,map_data) pygame.display.flip() running = True try: while running: time_passed_seconds = clock.tick(FPS) / 1000.0 time_passed += time_passed_seconds #print 'moved: %s' % moved #到達重新整理的時間間隔 if int(round(time_passed))/FALL_PER_SECONDS == 1: #移動一個距離,不能移動的時候,更新地圖,獲得新方塊,清除行 _block_left_top_x = block_left_top[0] _block_left_top_y = block_left_top[1] _block_left_top_y += SPEED if can_move(block_data,[_block_left_top_x,_block_left_top_y],map_data): block_left_top[1] = _block_left_top_y else: update_map(block_data, block_left_top, map_data) clear_lines(map_data) block_data = get_block() block_left_top = BLOCK_START_POINT[:] #重置時間間隔 time_passed = 0 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.KEYDOWN: _block_left_top_x = block_left_top[0] _block_left_top_y = block_left_top[1] if event.key == pygame.K_UP: pass elif event.key == pygame.K_DOWN: if not reach_bottom(block_data,block_left_top,map_data): print 'game over' block_data = get_block() block_left_top = BLOCK_START_POINT[:] elif event.key == pygame.K_LEFT: if can_move(block_data, [_block_left_top_x - 1, _block_left_top_y], map_data): block_left_top[0] -= 1 elif event.key == pygame.K_RIGHT: if can_move(block_data, [_block_left_top_x + 1, _block_left_top_y], map_data): block_left_top[0] += 1 elif event.key == pygame.K_SPACE: test_rorate = rorate_block(block_data) #print_block(test_rorate) if can_move(test_rorate, block_left_top, map_data): block_data = test_rorate #print 'can_move: %s' % can_move(block_data,block_left_top,map_data) #print_block(map_data) screen.fill(BACKGROUND_COLOR) draw(block_data, block_left_top, map_data, screen) pygame.display.update() finally: pygame.quit() if __name__ == '__main__': main()