欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python 基于pygame实现俄罗斯方块

程序员文章站 2022-03-07 23:39:14
一、简单说明80、90后的小伙伴都玩过“俄罗斯方块”,那种“叱咤风云”场景 偶尔闪现在脑海 真的是太爽了;如果没有来得及玩过的同学,这次可以真正的自己做一个了本实例用的是python3(当然了pyth...

一、简单说明

80、90后的小伙伴都玩过“俄罗斯方块”,那种“叱咤风云”场景 偶尔闪现在脑海 真的是太爽了;如果没有来得及玩过的同学,这次可以真正的自己做一个了

本实例用的是python3(当然了python3.5 3.6 3.7....都行 )+ pygame实现的

运行之前需要安装pygame模块,安装命令如下

pip install pygame -i https://mirrors.aliyun.com/pypi/simple/

二、运行效果

python 基于pygame实现俄罗斯方块

python 基于pygame实现俄罗斯方块

三、完整代码

文件main.py代码如下:

"""
作者:it项目实例网
更多项目实例,请访问:www.itprojects.cn
"""

import random
import sys
import time

import pygame

from blocks import block_s, block_i, block_j, block_l, block_o, block_t, block_z

screen_width, screen_height = 450, 750
bg_color = (40, 40, 60) # 背景色
block_col_num = 10 # 每行的方格数
size = 30 # 每个小方格大小
block_row_num = 25 # 每列的方个数
border_width = 4 # 游戏区边框宽度
red = (200, 30, 30) # 红色,game over 的字体颜色


def judge_game_over(stop_all_block_list):
 """
 判断游戏是否结束
 """
 if "o" in stop_all_block_list[0]:
  return true


def change_speed(score):
 speed_level = [("1", 0.5, 0, 20), ("2", 0.4, 21, 50), ("3", 0.3, 51, 100), ("4", 0.2, 101, 200), ("5", 0.1, 201, none)]
 for speed_info, speed, score_start, score_stop in speed_level:
  if score_stop and score_start <= score <= score_stop:
   return speed_info, speed
  elif score_stop is none and score >= score_start:
   return speed_info, speed


def judge_lines(stop_all_block_list):
 """
 判断是否有同一行的方格,如果有则消除
 """
 # 记录刚刚消除的行数
 move_row_list = list()
 # 消除满格的行
 for row, line in enumerate(stop_all_block_list):
  if "." not in line:
   # 如果这一行没有. 那么就意味着全部是o,则消除这一行
   stop_all_block_list[row] = ['.' for _ in range(len(line))]
   move_row_list.append(row)

 # 如果没有满格的行,则结束此函数
 if not move_row_list:
  return 0

 # 移动剩余的行到下一行
 for row in move_row_list:
  stop_all_block_list.pop(row)
  stop_all_block_list.insert(0, ['.' for _ in range(len(line))])

 return len(move_row_list) * 10


def add_to_stop_all_block_list(stop_all_block_list, current_block, current_block_start_row, current_block_start_col):
 """
 将当前已经停止移动的block添加到列表中
 """
 for row, line in enumerate(current_block):
  for col, block in enumerate(line):
   if block != '.':
    stop_all_block_list[current_block_start_row + row][current_block_start_col + col] = "o"


def change_current_block_style(current_block):
 """
 改变图形的样式
 """
 # 计算出,当前图形样式属于哪个图形
 current_block_style_list = none
 for block_style_list in [block_s, block_i, block_j, block_l, block_o, block_t, block_z]:
  if current_block in block_style_list:
   current_block_style_list = block_style_list

 # 得到当前正在用的图形的索引(下标)
 index = current_block_style_list.index(current_block)
 # 它的下一个图形的索引
 index += 1
 # 防止越界
 index = index % len(current_block_style_list)
 # 返回下一个图形
 return current_block_style_list[index]


def judge_move_right(current_block, current_block_start_col):
 """
 判断是否可以向右移动
 """
 # 先判断列的方式是从右到左
 for col in range(len(current_block[0]) - 1, -1, -1):
  # 得到1列的所有元素
  col_list = [line[col] for line in current_block]
  # 判断是否碰到右边界
  if 'o' in col_list and current_block_start_col + col >= block_col_num:
   return false
 return true


def judge_move_left(current_block, current_block_start_col):
 """
 判断是否可以向左移动
 """
 # 先判断列的方式是从左到右
 for col in range(len(current_block[0])):
  # 得到1列的所有元素
  col_list = [line[col] for line in current_block]
  # 判断是否碰到右边界
  if 'o' in col_list and current_block_start_col + col < 0:
   return false
 return true


def judge_move_down(current_block, current_block_start_row, current_block_start_col, stop_all_block_list):
 """
 判断是否碰撞到其它图形或者底边界
 """
 # 得到其它图形所有的坐标
 stop_all_block_position = list()
 for row, line in enumerate(stop_all_block_list):
  for col, block in enumerate(line):
   if block != ".":
    stop_all_block_position.append((row, col))
 # print(stop_all_block_position)

 # 判断碰撞
 for row, line in enumerate(current_block):
  if 'o' in line and current_block_start_row + row >= block_row_num:
   # 如果当前行有0,且从起始行开始算+当前显示的行,超过了总行数,那么就认为碰到了底部
   return false
  for col, block in enumerate(line):
   if block != "." and (current_block_start_row + row, current_block_start_col + col) in stop_all_block_position:
    return false

 return true


def get_block():
 """
 创建一个图形
 """
 block_style_list = random.choice([block_s, block_i, block_j, block_l, block_o, block_t, block_z])
 return random.choice(block_style_list)


def main():
 pygame.init()
 screen = pygame.display.set_mode((screen_width, screen_height))
 pygame.display.set_caption('俄罗斯方块')

 current_block = get_block() # 当前图形
 current_block_start_row = -2 # 当前图片从哪一行开始显示图形
 current_block_start_col = 4 # 当前图形从哪一列开始显示
 next_block = get_block() # 下一个图形
 last_time = time.time()
 speed = 0.5 # 降落的速度
 speed_info = '1' # 显示的速度等级

 # 定义一个列表,用来存储所有的已经停止移动的形状
 stop_all_block_list = [['.' for i in range(block_col_num)] for j in range(block_row_num)]

 # 字体
 font = pygame.font.font('yh.ttf', 24) # 黑体24
 game_over_font = pygame.font.font("yh.ttf", 72)
 game_over_font_width, game_over_font_height = game_over_font.size('game over')
 game_again_font_width, game_again_font_height = font.size('鼠标点击任意位置,再来一局')

 # 得分
 score = 0

 # 标记游戏是否结束
 game_over = false

 # 创建计时器(防止while循环过快,占用太多cpu的问题)
 clock = pygame.time.clock()
 while true:
  for event in pygame.event.get():
   if event.type == pygame.quit:
    sys.exit()
   elif event.type == pygame.keydown:
    if event.key == pygame.k_left:
     if judge_move_left(current_block, current_block_start_col - 1):
      current_block_start_col -= 1
    elif event.key == pygame.k_right:
     if judge_move_right(current_block, current_block_start_col + 1):
      current_block_start_col += 1
    elif event.key == pygame.k_up:
     current_block_next_style = change_current_block_style(current_block)
     if judge_move_left(current_block_next_style, current_block_start_col) and \
       judge_move_right(current_block_next_style, current_block_start_col) and \
       judge_move_down(current_block, current_block_start_row, current_block_start_col, stop_all_block_list):
      # 判断新的样式没有越界
      current_block = current_block_next_style
    elif event.key == pygame.k_down:
     # 判断是否可以向下移动,如果碰到底部或者其它的图形就不能移动了
     if judge_move_down(current_block, current_block_start_row + 1, current_block_start_col, stop_all_block_list):
      current_block_start_row += 1
   elif event.type == pygame.mousebuttondown and event.button:
    if game_over:
     # 重置游戏用到的变量
     current_block = get_block() # 当前图形
     current_block_start_row = -2 # 当前图片从哪一行开始显示图形
     current_block_start_col = 4 # 当前图形从哪一列开始显示
     next_block = get_block() # 下一个图形
     stop_all_block_list = [['.' for i in range(block_col_num)] for j in range(block_row_num)]
     score = 0
     game_over = false

  # 判断是否修改当前图形显示的起始行
  if not game_over and time.time() - last_time > speed:
   last_time = time.time()
   # 判断是否可以向下移动,如果碰到底部或者其它的图形就不能移动了
   if judge_move_down(current_block, current_block_start_row + 1, current_block_start_col, stop_all_block_list):
    current_block_start_row += 1
   else:
    # 将这个图形存储到统一的列表中,这样便于判断是否成为一行
    add_to_stop_all_block_list(stop_all_block_list, current_block, current_block_start_row, current_block_start_col)
    # 判断是否有同一行的,如果有就消除,且加上分数
    score += judge_lines(stop_all_block_list)
    # 判断游戏是否结束(如果第一行中间有o那么就表示游戏结束)
    game_over = judge_game_over(stop_all_block_list)
    # 调整速度
    speed_info, speed = change_speed(score)
    # 创建新的图形
    current_block = next_block
    next_block = get_block()
    # 重置数据
    current_block_start_col = 4
    current_block_start_row = -2

  # 画背景(填充背景色)
  screen.fill(bg_color)

  # 画游戏区域分隔线
  pygame.draw.line(screen, (100, 40, 200), (size * block_col_num, 0), (size * block_col_num, screen_height), border_width)

  # 显示当前图形
  for row, line in enumerate(current_block):
   for col, block in enumerate(line):
    if block != '.':
     pygame.draw.rect(screen, (20, 128, 200), ((current_block_start_col + col) * size, (current_block_start_row + row) * size, size, size), 0)

  # 显示所有停止移动的图形
  for row, line in enumerate(stop_all_block_list):
   for col, block in enumerate(line):
    if block != '.':
     pygame.draw.rect(screen, (20, 128, 200), (col * size, row * size, size, size), 0)

  # 画网格线 竖线
  for x in range(block_col_num):
   pygame.draw.line(screen, (0, 0, 0), (x * size, 0), (x * size, screen_height), 1)
  # 画网格线 横线
  for y in range(block_row_num):
   pygame.draw.line(screen, (0, 0, 0), (0, y * size), (block_col_num * size, y * size), 1)

  # 显示右侧(得分、速度、下一行图形)
  # 得分
  score_show_msg = font.render('得分: ', true, (255, 255, 255))
  screen.blit(score_show_msg, (block_col_num * size + 10, 10))
  score_show_msg = font.render(str(score), true, (255, 255, 255))
  screen.blit(score_show_msg, (block_col_num * size + 10, 50))
  # 速度
  speed_show_msg = font.render('速度: ', true, (255, 255, 255))
  screen.blit(speed_show_msg, (block_col_num * size + 10, 100))
  speed_show_msg = font.render(speed_info, true, (255, 255, 255))
  screen.blit(speed_show_msg, (block_col_num * size + 10, 150))
  # 下一个图形(文字提示)
  next_style_msg = font.render('下一个: ', true, (255, 255, 255))
  screen.blit(next_style_msg, (block_col_num * size + 10, 200))
  # 下一个图形(图形)
  for row, line in enumerate(next_block):
   for col, block in enumerate(line):
    if block != '.':
     pygame.draw.rect(screen, (20, 128, 200), (320 + size * col, (block_col_num + row) * size, size, size), 0)
     # 显示这个方格的4个边的颜色
     # 左
     pygame.draw.line(screen, (0, 0, 0), (320 + size * col, (block_col_num + row) * size), (320 + size * col, (block_col_num + row + 1) * size), 1)
     # 上
     pygame.draw.line(screen, (0, 0, 0), (320 + size * col, (block_col_num + row) * size), (320 + size * (col + 1), (block_col_num + row) * size), 1)
     # 下
     pygame.draw.line(screen, (0, 0, 0), (320 + size * col, (block_col_num + row + 1) * size), (320 + size * (col + 1), (block_col_num + row + 1) * size), 1)
     # 右
     pygame.draw.line(screen, (0, 0, 0), (320 + size * (col + 1), (block_col_num + row) * size), (320 + size * (col + 1), (block_col_num + row + 1) * size), 1)

  # 显示游戏结束画面
  if game_over:
   game_over_tips = game_over_font.render('game over', true, red)
   screen.blit(game_over_tips, ((screen_width - game_over_font_width) // 2, (screen_height - game_over_font_height) // 2))
   # 显示"鼠标点击任意位置,再来一局"
   game_again = font.render('鼠标点击任意位置,再来一局', true, red)
   screen.blit(game_again, ((screen_width - game_again_font_width) // 2, (screen_height - game_again_font_height) // 2 + 80))

  # 刷新显示(此时窗口才会真正的显示)
  pygame.display.update()
  # fps(每秒钟显示画面的次数)
  clock.tick(60) # 通过一定的延时,实现1秒钟能够循环60次


if __name__ == '__main__':
 main()

文件blocks.py代码如下:

# s形方块
block_s = [['.oo',
   'oo.',
   '...'],
   ['o..',
   'oo.',
   '.o.']]
# z形方块
block_z = [['oo.',
   '.oo',
   '...'],
   ['.o.',
   'oo.',
   'o..']]
# i型方块
block_i = [['.o..',
   '.o..',
   '.o..',
   '.o..'],
   ['....',
   '....',
   'oooo',
   '....']]
# o型方块
block_o = [['oo',
   'oo']]
# j型方块
block_j = [['o..',
   'ooo',
   '...'],
   ['.oo',
   '.o.',
   '.o.'],
   ['...',
   'ooo',
   '..o'],
   ['.o.',
   '.o.',
   'oo.']]
# l型方块
block_l = [['..o',
   'ooo',
   '...'],
   ['.o.',
   '.o.',
   '.oo'],
   ['...',
   'ooo',
   'o..'],
   ['oo.',
   '.o.',
   '.o.']]
# t型方块
block_t = [['.o.',
   'ooo',
   '...'],
   ['.o.',
   '.oo',
   '.o.'],
   ['...',
   'ooo',
   '.o.'],
   ['.o.',
   'oo.',
   '.o.']]

以上就是python 基于pygame实现俄罗斯方块的详细内容,更多关于python 俄罗斯方块的资料请关注其它相关文章!