python實現俄羅斯方塊小遊戲
阿新 • • 發佈:2020-04-26
回顧我們的python製作小遊戲之路,幾篇非常精彩的文章
我們用python實現了坦克大戰
python製作坦克大戰
我們用python實現了飛船大戰
python製作飛船大戰
我們用python實現了兩種不同的貪吃蛇遊戲
200行python程式碼實現貪吃蛇遊戲
150行程式碼實現貪吃蛇遊戲
我們用python實現了掃雷遊戲
python實現掃雷遊戲
我們用python實現了五子棋遊戲
python實現五子棋遊戲
今天我們用python來實現小時候玩過的俄羅斯方塊遊戲吧
具體程式碼與檔案可以訪問我的GitHub地址獲取
第一步——構建各種方塊
import random from collections import namedtuple Point = namedtuple('Point','X Y') Shape = namedtuple('Shape','X Y Width Height') Block = namedtuple('Block','template start_pos end_pos name next') # 方塊形狀的設計,我最初我是做成 4 × 4,因為長寬最長都是4,這樣旋轉的時候就不考慮怎麼轉了,就是從一個圖形替換成另一個 # 其實要實現這個功能,只需要固定左上角的座標就可以了 # S形方塊 S_BLOCK = [Block(['.OO','OO.','...'],Point(0,0),Point(2,1),'S',Block(['O..','.O.'],Point(1,2),0)] # Z形方塊 Z_BLOCK = [Block(['OO.','.OO','Z',Block(['.O.','O..'],0)] # I型方塊 I_BLOCK = [Block(['.O..','.O..','.O..'],3),'I',Block(['....','....','OOOO','....'],Point(3,0)] # O型方塊 O_BLOCK = [Block(['OO','OO'],'O',0)] # J型方塊 J_BLOCK = [Block(['O..','OOO','J',Block(['.OO','.O.',Block(['...','..O'],'OO.'],0)] # L型方塊 L_BLOCK = [Block(['..O','L','.OO'],Block(['OO.',0)] # T型方塊 T_BLOCK = [Block(['.O.','T',0)] BLOCKS = {'O': O_BLOCK,'I': I_BLOCK,'Z': Z_BLOCK,'T': T_BLOCK,'L': L_BLOCK,'S': S_BLOCK,'J': J_BLOCK} def get_block(): block_name = random.choice('OIZTLSJ') b = BLOCKS[block_name] idx = random.randint(0,len(b) - 1) return b[idx] def get_next_block(block): b = BLOCKS[block.name] return b[block.next]
第二部——構建主函式
import sys import time import pygame from pygame.locals import * import blocks SIZE = 30 # 每個小方格大小 BLOCK_HEIGHT = 25 # 遊戲區高度 BLOCK_WIDTH = 10 # 遊戲區寬度 BORDER_WIDTH = 4 # 遊戲區邊框寬度 BORDER_COLOR = (40,40,200) # 遊戲區邊框顏色 SCREEN_WIDTH = SIZE * (BLOCK_WIDTH + 5) # 遊戲螢幕的寬 SCREEN_HEIGHT = SIZE * BLOCK_HEIGHT # 遊戲螢幕的高 BG_COLOR = (40,60) # 背景色 BLOCK_COLOR = (20,128,200) # BLACK = (0,0) RED = (200,30,30) # GAME OVER 的字型顏色 def print_text(screen,font,x,y,text,fcolor=(255,255,255)): imgText = font.render(text,True,fcolor) screen.blit(imgText,(x,y)) def main(): pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT)) pygame.display.set_caption('俄羅斯方塊') font1 = pygame.font.SysFont('SimHei',24) # 黑體24 font2 = pygame.font.Font(None,72) # GAME OVER 的字型 font_pos_x = BLOCK_WIDTH * SIZE + BORDER_WIDTH + 10 # 右側資訊顯示區域字型位置的X座標 gameover_size = font2.size('GAME OVER') font1_height = int(font1.size('得分')[1]) cur_block = None # 當前下落方塊 next_block = None # 下一個方塊 cur_pos_x,cur_pos_y = 0,0 game_area = None # 整個遊戲區域 game_over = True start = False # 是否開始,當start = True,game_over = True 時,才顯示 GAME OVER score = 0 # 得分 orispeed = 0.5 # 原始速度 speed = orispeed # 當前速度 pause = False # 暫停 last_drop_time = None # 上次下落時間 last_press_time = None # 上次按鍵時間 def _dock(): nonlocal cur_block,next_block,game_area,cur_pos_x,cur_pos_y,game_over,score,speed for _i in range(cur_block.start_pos.Y,cur_block.end_pos.Y + 1): for _j in range(cur_block.start_pos.X,cur_block.end_pos.X + 1): if cur_block.template[_i][_j] != '.': game_area[cur_pos_y + _i][cur_pos_x + _j] = '0' if cur_pos_y + cur_block.start_pos.Y <= 0: game_over = True else: # 計算消除 remove_idxs = [] for _i in range(cur_block.start_pos.Y,cur_block.end_pos.Y + 1): if all(_x == '0' for _x in game_area[cur_pos_y + _i]): remove_idxs.append(cur_pos_y + _i) if remove_idxs: # 計算得分 remove_count = len(remove_idxs) if remove_count == 1: score += 100 elif remove_count == 2: score += 300 elif remove_count == 3: score += 700 elif remove_count == 4: score += 1500 speed = orispeed - 0.03 * (score // 10000) # 消除 _i = _j = remove_idxs[-1] while _i >= 0: while _j in remove_idxs: _j -= 1 if _j < 0: game_area[_i] = ['.'] * BLOCK_WIDTH else: game_area[_i] = game_area[_j] _i -= 1 _j -= 1 cur_block = next_block next_block = blocks.get_block() cur_pos_x,cur_pos_y = (BLOCK_WIDTH - cur_block.end_pos.X - 1) // 2,-1 - cur_block.end_pos.Y def _judge(pos_x,pos_y,block): nonlocal game_area for _i in range(block.start_pos.Y,block.end_pos.Y + 1): if pos_y + block.end_pos.Y >= BLOCK_HEIGHT: return False for _j in range(block.start_pos.X,block.end_pos.X + 1): if pos_y + _i >= 0 and block.template[_i][_j] != '.' and game_area[pos_y + _i][pos_x + _j] != '.': return False return True while True: for event in pygame.event.get(): if event.type == QUIT: sys.exit() elif event.type == KEYDOWN: if event.key == K_RETURN: if game_over: start = True game_over = False score = 0 last_drop_time = time.time() last_press_time = time.time() game_area = [['.'] * BLOCK_WIDTH for _ in range(BLOCK_HEIGHT)] cur_block = blocks.get_block() next_block = blocks.get_block() cur_pos_x,-1 - cur_block.end_pos.Y elif event.key == K_SPACE: if not game_over: pause = not pause elif event.key in (K_w,K_UP): # 旋轉 # 其實記得不是很清楚了,比如 # .0. # .00 # ..0 # 這個在最右邊靠邊的情況下是否可以旋轉,我試完了網上的俄羅斯方塊,是不能旋轉的,這裡我們就按不能旋轉來做 # 我們在形狀設計的時候做了很多的空白,這樣只需要規定整個形狀包括空白部分全部在遊戲區域內時才可以旋轉 if 0 <= cur_pos_x <= BLOCK_WIDTH - len(cur_block.template[0]): _next_block = blocks.get_next_block(cur_block) if _judge(cur_pos_x,_next_block): cur_block = _next_block if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: if not game_over and not pause: if time.time() - last_press_time > 0.1: last_press_time = time.time() if cur_pos_x > - cur_block.start_pos.X: if _judge(cur_pos_x - 1,cur_block): cur_pos_x -= 1 if event.key == pygame.K_RIGHT: if not game_over and not pause: if time.time() - last_press_time > 0.1: last_press_time = time.time() # 不能移除右邊框 if cur_pos_x + cur_block.end_pos.X + 1 < BLOCK_WIDTH: if _judge(cur_pos_x + 1,cur_block): cur_pos_x += 1 if event.key == pygame.K_DOWN: if not game_over and not pause: if time.time() - last_press_time > 0.1: last_press_time = time.time() if not _judge(cur_pos_x,cur_pos_y + 1,cur_block): _dock() else: last_drop_time = time.time() cur_pos_y += 1 _draw_background(screen) _draw_game_area(screen,game_area) _draw_gridlines(screen) _draw_info(screen,font1,font_pos_x,font1_height,score) # 畫顯示資訊中的下一個方塊 _draw_block(screen,30 + (font1_height + 6) * 5,0) if not game_over: cur_drop_time = time.time() if cur_drop_time - last_drop_time > speed: if not pause: # 不應該在下落的時候來判斷到底沒,我們玩俄羅斯方塊的時候,方塊落到底的瞬間是可以進行左右移動 if not _judge(cur_pos_x,cur_block): _dock() else: last_drop_time = cur_drop_time cur_pos_y += 1 else: if start: print_text(screen,font2,(SCREEN_WIDTH - gameover_size[0]) // 2,(SCREEN_HEIGHT - gameover_size[1]) // 2,'GAME OVER',RED) # 畫當前下落方塊 _draw_block(screen,cur_block,cur_pos_y) pygame.display.flip() # 畫背景 def _draw_background(screen): # 填充背景色 screen.fill(BG_COLOR) # 畫遊戲區域分隔線 pygame.draw.line(screen,BORDER_COLOR,(SIZE * BLOCK_WIDTH + BORDER_WIDTH // 2,SCREEN_HEIGHT),BORDER_WIDTH) # 畫網格線 def _draw_gridlines(screen): # 畫網格線 豎線 for x in range(BLOCK_WIDTH): pygame.draw.line(screen,BLACK,(x * SIZE,1) # 畫網格線 橫線 for y in range(BLOCK_HEIGHT): pygame.draw.line(screen,(0,y * SIZE),(BLOCK_WIDTH * SIZE,1) # 畫已經落下的方塊 def _draw_game_area(screen,game_area): if game_area: for i,row in enumerate(game_area): for j,cell in enumerate(row): if cell != '.': pygame.draw.rect(screen,BLOCK_COLOR,(j * SIZE,i * SIZE,SIZE,SIZE),0) # 畫單個方塊 def _draw_block(screen,block,offset_x,offset_y,pos_x,pos_y): if block: for i in range(block.start_pos.Y,block.end_pos.Y + 1): for j in range(block.start_pos.X,block.end_pos.X + 1): if block.template[i][j] != '.': pygame.draw.rect(screen,(offset_x + (pos_x + j) * SIZE,offset_y + (pos_y + i) * SIZE,0) # 畫得分等資訊 def _draw_info(screen,font_height,score): print_text(screen,10,f'得分: ') print_text(screen,10 + font_height + 6,f'{score}') print_text(screen,20 + (font_height + 6) * 2,f'速度: ') print_text(screen,20 + (font_height + 6) * 3,f'{score // 10000}') print_text(screen,30 + (font_height + 6) * 4,f'下一個:') if __name__ == '__main__': main()
遊戲截圖
執行效果
更多俄羅斯方塊精彩文章請點選專題:俄羅斯方塊遊戲集合 進行學習。
更多有趣的經典小遊戲實現專題,也分享給大家:
C++經典小遊戲彙總
python經典小遊戲彙總
python俄羅斯方塊遊戲集合
JavaScript經典遊戲 玩不停
java經典小遊戲彙總
javascript經典小遊戲彙總
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。