如何利用 python 制作俄罗斯方块?

发布时间:
2024-10-08 00:29
阅读量:
18

Python编写游戏是把好手,但是我一直尝试很多次都没有成功编写出俄罗斯方块。这是一款经典的游戏,里面的设置比较复杂,即使是用人工智能工具写出来了,但是也会出各种各样的bug,今天我们看到网上有一款不错的俄罗斯方块代码,虽然界面比较简易,但是运行起来但没有什么报错,很流畅。

一、俄罗斯方块代码

这是在csdn上看到一款俄罗斯方块程序,运行后显示如下:

代码运行后如下所示:

import sys import pygame from pygame.locals import * import random class Block: blk_color = [(255, 255, 255),(255, 255, 0),(255, 0, 255),(0, 255, 255),(255, 0, 0),(0, 255, 0),(0, 0, 255),(32,32,32)] BLANK = 7 type_coord=[[[-1,0],[0,0],[1,0],[2,0]]\ ,[[-1,0],[0,0],[1,0],[0,1]]\ ,[[-1,0],[0,0],[-1,1],[0,1]]\ ,[[-1,0],[0,0],[0,1],[1,1]]\ ,[[0,0],[1,0],[-1,1],[0,1]]\ ,[[-1,0],[0,0],[1,0],[1,1]]\ ,[[-1,0],[0,0],[1,0],[-1,1]]] type_rotate = [] def __init__(self,x,y,blk,angle): self.x = x self.y = y self.blk = blk self.angle = angle @staticmethod def rotate(no): rt_all = [] rt = Block.type_coord[no][:] cx,cy=0,0 for b in range(4): rt[b][0],rt[b][1] = rt[b][0]*4,rt[b][1]*4 cx += rt[b][0] cy += rt[b][1] cx = (cx)//8*2 if no !=6 else (cx+4)//8*2 cy = (cy)//8*2 if no !=6 else (cy-4)//8*2 rt_all.append(rt) for r in range(3): rt_new = [] for b in range(4): rt_new.append([cx + (cy-rt[b][1]),cy-(cx-rt[b][0])]) rt_all.append(rt_new) rt = rt_new for r in range(4): for b in range(4): rt_all[r][b][0] //= 4 rt_all[r][b][1] //= 4 return rt_all @staticmethod def init_rotate(): for r in range(7): Block.type_rotate.append(Block.rotate(r)) class TRS: screen = None map = [[Block.BLANK]*10 for i in range(20)] STATUS = 0 cbk = None def __init__(self,screen): TRS.screen = screen @staticmethod def action(key_pressed): if(key_pressed[K_LEFT] and TRS.check_action(TRS.cbk.x-1,TRS.cbk.y,TRS.cbk.blk,TRS.cbk.angle)): TRS.cbk.x -= 1 elif (key_pressed[K_RIGHT] and TRS.check_action(TRS.cbk.x+1,TRS.cbk.y,TRS.cbk.blk,TRS.cbk.angle)): TRS.cbk.x += 1 elif (key_pressed[K_UP] and TRS.check_action(TRS.cbk.x,TRS.cbk.y,TRS.cbk.blk,TRS.cbk.angle+1)): TRS.cbk.angle += 1 elif (key_pressed[K_DOWN] and TRS.check_action(TRS.cbk.x,TRS.cbk.y+1,TRS.cbk.blk,TRS.cbk.angle)): TRS.cbk.y += 1 @staticmethod def new_blk(): TRS.cbk = Block(5,0,random.randint(0,6),0) @staticmethod def check_action(x,y,blk,angle): tr = Block.type_rotate[blk][angle%4] for b in range(4): bx,by = x + tr[b][0],y + tr[b][1] if(bx<0 or bx>9 or by <0 or by>19 or TRS.map[by][bx]!=Block.BLANK): return False return True @staticmethod def check_drop(): if TRS.check_action(TRS.cbk.x,TRS.cbk.y+1,TRS.cbk.blk,TRS.cbk.angle): TRS.cbk.y += 1 else: TRS.STATUS = 2 @staticmethod def check_clear(): blk = Block.type_rotate[TRS.cbk.blk][TRS.cbk.angle%4] row = list({TRS.cbk.y + blk[i][1] for i in range(4)}) row.sort() row.reverse() for b in range(4): TRS.map[TRS.cbk.y + blk[b][1]][TRS.cbk.x + blk[b][0]] = TRS.cbk.blk del_rows = 0 for r in row: if not (Block.BLANK in TRS.map[r]): TRS.map.pop(r) del_rows += 1 for d in range(del_rows): TRS.map.insert(0,[Block.BLANK for i in range(10)]) @staticmethod def print_game(): TRS.screen.fill((0, 0, 0)) for row in range(20): for col in range(10): pygame.draw.rect(TRS.screen, Block.blk_color[TRS.map[row][col]], ((col*21,row*21), (20, 20)), 0) blk = Block.type_rotate[TRS.cbk.blk][TRS.cbk.angle%4] for b in range(4): pygame.draw.rect(TRS.screen, Block.blk_color[TRS.cbk.blk], (((TRS.cbk.x+blk[b][0])*21,(TRS.cbk.y+blk[b][1])*21), (20, 20)), 0) class App: def __init__(self): pygame.init() screen = pygame.display.set_mode((300,430)) Block.init_rotate() TRS(screen) def main(self): clock = pygame.time.Clock() # 创建游戏时钟 count = 1 # 进入游戏循环 while True: # 设置刷新帧率 clock.tick(15) # 事件检测 for event in pygame.event.get(): if event.type == pygame.QUIT: # 退出事件 sys.exit() if TRS.STATUS == 0: TRS.new_blk() if TRS.check_action(TRS.cbk.x,TRS.cbk.y,TRS.cbk.blk,TRS.cbk.angle): TRS.STATUS = 1 else: TRS.STATUS = 3 print("GAME OVER") elif TRS.STATUS == 1: TRS.action(pygame.key.get_pressed()) if count % 10 == 0: TRS.check_drop() elif TRS.STATUS == 2: TRS.check_clear() TRS.STATUS = 0 TRS.print_game() pygame.display.update() #刷新屏幕 count += 1 App().main()

二、修改后的俄罗斯方块

上述代码没有计分功能,我又给它增加了一个计分功能,修改后如下:

修改后的俄罗斯方块

修改后的代码如下:

import sys import pygame from pygame.locals import * import random class Block: blk_color = [(255, 255, 255),(255, 255, 0),(255, 0, 255),(0, 255, 255),(255, 0, 0),(0, 255, 0),(0, 0, 255),(32,32,32)] BLANK = 7 type_coord=[[[-1,0],[0,0],[1,0],[2,0]], [[-1,0],[0,0],[1,0],[0,1]], [[-1,0],[0,0],[-1,1],[0,1]], [[-1,0],[0,0],[0,1],[1,1]], [[0,0],[1,0],[-1,1],[0,1]], [[-1,0],[0,0],[1,0],[1,1]], [[-1,0],[0,0],[1,0],[-1,1]]] type_rotate = [] def __init__(self,x,y,blk,angle): self.x = x self.y = y self.blk = blk self.angle = angle @staticmethod def rotate(no): rt_all = [] rt = Block.type_coord[no][:] cx,cy=0,0 for b in range(4): rt[b][0],rt[b][1] = rt[b][0]*4,rt[b][1]*4 cx += rt[b][0] cy += rt[b][1] cx = (cx)//8*2 if no !=6 else (cx+4)//8*2 cy = (cy)//8*2 if no !=6 else (cy-4)//8*2 rt_all.append(rt) for r in range(3): rt_new = [] for b in range(4): rt_new.append([cx + (cy-rt[b][1]),cy-(cx-rt[b][0])]) rt_all.append(rt_new) rt = rt_new for r in range(4): for b in range(4): rt_all[r][b][0] //= 4 rt_all[r][b][1] //= 4 return rt_all @staticmethod def init_rotate(): for r in range(7): Block.type_rotate.append(Block.rotate(r)) class TRS: screen = None map = [[Block.BLANK]*10 for i in range(20)] STATUS = 0 cbk = None score = 0 def __init__(self,screen): TRS.screen = screen @staticmethod def action(key_pressed): if key_pressed[K_LEFT] and TRS.check_action(TRS.cbk.x - 1, TRS.cbk.y, TRS.cbk.blk, TRS.cbk.angle): TRS.cbk.x -= 1 elif key_pressed[K_RIGHT] and TRS.check_action(TRS.cbk.x + 1, TRS.cbk.y, TRS.cbk.blk, TRS.cbk.angle): TRS.cbk.x += 1 elif key_pressed[K_DOWN] and TRS.check_action(TRS.cbk.x, TRS.cbk.y + 1, TRS.cbk.blk, TRS.cbk.angle): TRS.cbk.y += 1 elif key_pressed[K_UP]: new_angle = (TRS.cbk.angle + 1) % 4 if TRS.check_action(TRS.cbk.x, TRS.cbk.y, TRS.cbk.blk, new_angle): TRS.cbk.angle = new_angle @staticmethod def new_blk(): TRS.cbk = Block(5,0,random.randint(0,6),0) @staticmethod def check_action(x,y,blk,angle): tr = Block.type_rotate[blk][angle%4] for b in range(4): bx,by = x + tr[b][0],y + tr[b][1] if(bx<0 or bx>9 or by <0 or by>19 or TRS.map[by][bx]!=Block.BLANK): return False return True @staticmethod def check_drop(): if TRS.check_action(TRS.cbk.x,TRS.cbk.y+1,TRS.cbk.blk,TRS.cbk.angle): TRS.cbk.y += 1 else: TRS.STATUS = 2 @staticmethod def check_clear(): blk = Block.type_rotate[TRS.cbk.blk][TRS.cbk.angle%4] row = list({TRS.cbk.y + blk[i][1] for i in range(4)}) row.sort() row.reverse() for b in range(4): TRS.map[TRS.cbk.y + blk[b][1]][TRS.cbk.x + blk[b][0]] = TRS.cbk.blk del_rows = 0 for r in row: if not (Block.BLANK in TRS.map[r]): TRS.map.pop(r) del_rows += 1 for d in range(del_rows): TRS.map.insert(0,[Block.BLANK for i in range(10)]) TRS.score += del_rows * 10 @staticmethod def print_game(): TRS.screen.fill((0, 0, 0)) font = pygame.font.Font(None, 24) score_text = font.render(f'Score: {TRS.score}', True, (255, 255, 255)) TRS.screen.blit(score_text, (220, 10)) for row in range(20): for col in range(10): pygame.draw.rect(TRS.screen, Block.blk_color[TRS.map[row][col]], ((col*21,row*21), (20, 20)), 0) blk = Block.type_rotate[TRS.cbk.blk][TRS.cbk.angle%4] for b in range(4): pygame.draw.rect(TRS.screen, Block.blk_color[TRS.cbk.blk], (((TRS.cbk.x+blk[b][0])*21,(TRS.cbk.y+blk[b][1])*21), (20, 20)), 0) class App: def __init__(self): pygame.init() screen = pygame.display.set_mode((300,430)) pygame.display.set_caption("俄罗斯方块") Block.init_rotate() TRS(screen) def main(self): clock = pygame.time.Clock() count = 1 while True: clock.tick(15) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if TRS.STATUS == 0: TRS.new_blk() if TRS.check_action(TRS.cbk.x,TRS.cbk.y,TRS.cbk.blk,TRS.cbk.angle): TRS.STATUS = 1 else: TRS.STATUS = 3 print("GAME OVER") font = pygame.font.Font(None, 48) game_over_text = font.render("GAME OVER", True, (255, 0, 0)) TRS.screen.blit(game_over_text, (75, 200)) pygame.display.update() pygame.time.wait(3000) pygame.quit() sys.exit() elif TRS.STATUS == 1: TRS.action(pygame.key.get_pressed()) if count % 10 == 0: TRS.check_drop() elif TRS.STATUS == 2: TRS.check_clear() TRS.STATUS = 0 TRS.print_game() pygame.display.update() count += 1 if __name__ == "__main__": App().main()

三、学后反思

游戏考虑的问题比较多,极易出现各种问题。但是,作为编程过程中的调节,可以适当参考学习。

END