基于Python-Pygame:200行代码实现完整的俄罗斯方块

源码:

  1 # coding : utf-8
  2 
  3 #: pip install pygame
  4 import random
  5 import sys
  6 import pygame
  7 
  8 #: 颜色定义
  9 COLOR_WHITE = (255, 255, 255)
 10 COLOR_BLACK = (0, 0, 0)
 11 
 12 class Block:
 13     """小块"""
 14     width = 24
 15     height = 24
 16 
 17     @staticmethod
 18     def draw(s, left, top, color, bg_color):
 19         pygame.draw.rect(s, bg_color, pygame.Rect(left, top, Block.width, Block.height))
 20         pygame.draw.rect(s, color, pygame.Rect(left, top, Block.width - 1, Block.height - 1))
 21 
 22 
 23 class Building:
 24     """积木"""
 25 
 26     def __init__(self):
 27         """
 28         方块的7种基本形状
 29         每次初始化随机选择一个形状
 30         @:return True / False
 31         """
 32         self.form = random.choice(
 33             [
 34                 [
 35                     [0, 0, 0, 0, 0],
 36                     [0, 0, 1, 0, 0],
 37                     [0, 1, 1, 1, 0],
 38                     [0, 0, 0, 0, 0],
 39                     [0, 0, 0, 0, 0]
 40                 ],
 41                 [
 42                     [0, 0, 0, 0, 0],
 43                     [0, 0, 0, 0, 0],
 44                     [1, 1, 1, 1, 0],
 45                     [0, 0, 0, 0, 0],
 46                     [0, 0, 0, 0, 0]
 47                 ],
 48                 [
 49                     [0, 0, 0, 0, 0],
 50                     [0, 1, 1, 0, 0],
 51                     [0, 0, 1, 1, 0],
 52                     [0, 0, 0, 0, 0],
 53                     [0, 0, 0, 0, 0]
 54                 ],
 55                 [
 56                     [0, 0, 0, 0, 0],
 57                     [0, 0, 1, 1, 0],
 58                     [0, 1, 1, 0, 0],
 59                     [0, 0, 0, 0, 0],
 60                     [0, 0, 0, 0, 0]
 61                 ],
 62                 [
 63                     [0, 0, 0, 0, 0],
 64                     [0, 1, 1, 0, 0],
 65                     [0, 0, 1, 0, 0],
 66                     [0, 0, 1, 0, 0],
 67                     [0, 0, 0, 0, 0]
 68                 ],
 69                 [
 70                     [0, 0, 0, 0, 0],
 71                     [0, 0, 1, 1, 0],
 72                     [0, 0, 1, 0, 0],
 73                     [0, 0, 1, 0, 0],
 74                     [0, 0, 0, 0, 0]
 75                 ],
 76                 [
 77                     [0, 0, 0, 0, 0],
 78                     [0, 1, 1, 0, 0],
 79                     [0, 1, 1, 0, 0],
 80                     [0, 0, 0, 0, 0],
 81                     [0, 0, 0, 0, 0]
 82                 ]
 83             ])
 84 
 85     def __getitem__(self, pos):
 86         return self.form[pos]
 87 
 88     def __setitem__(self, key, value):
 89         self.form[key] = value
 90 
 91 
 92 class Layout:
 93     """棋盘"""
 94 
 95     def __init__(self):
 96         self.block_x_count = 16;
 97         self.block_y_count = 22;
 98         self.layout = [[0 if 1 < i < self.block_x_count - 2 and j < self.block_y_count - 2 else 1
 99                         for i in range(self.block_x_count)] for j in range(self.block_y_count)]
100 
101     @property
102     def size(self):
103         """返回棋盘屏幕大小(width,height)"""
104         return (self.block_x_count * Block.width, self.block_y_count * Block.height)
105 
106     def create_new_building(self):
107         """
108         创建新的积木,初始化位置为第5,0格, 速度为4
109         :return: 返回是否无空间创建了
110         """
111         self.building = Building()
112         self.building_left, self.building_top = 5, 0  #
113         self.drop_speed = 3
114         print(self.test_building_touch_wall())
115         return self.test_building_touch_wall()
116     
117     @property
118     def speed(self):
119         return self.drop_speed
120 
121     def test_building_touch_wall(self, x_offset=0, y_offset=0):
122         """
123         积木是否已经触底/墙壁
124         具体操作:
125         判断积木最后一排的1,是否在当前棋牌对应的位置是也是1
126         @:param x_offset: x的偏移量  移动时可以传入1/-1来判断
127         @:param y_offset: y的偏移量  正常下落时可以传入1来判断
128         """
129         for i in range(4, -1, -1):
130             for j in range(5):
131                 if self.building[i][j]:
132                     if self.layout[i + self.building_top + y_offset][j + self.building_left + x_offset]:
133                         return True
134         return False
135 
136     def move_left_right(self, x):
137         """
138         左右移动
139         @:param x:  移动量 x_offset
140         """
141         #: 移动时不能撞墙
142         if not self.test_building_touch_wall(x_offset=x):
143             self.building_left += x
144 
145     def down_build(self):
146         """ 盒子的自动下移 """
147         self.building_top += 1
148 
149     def direct_down(self):
150         """ 手动快速降落 """
151         self.drop_speed = 50
152 
153     def convert_building(self):
154         """
155         * 扭转盒子的总方位 (右转)
156         具体操作:
157         把第一竖排的倒序给第一横排的
158         把第二竖排的倒序给第二横排的
159         后面同理.
160         """
161         new_box = [[0 for i in range(5)] for j in range(5)]
162         for i in range(5):
163             for j in range(4, -1, -1):
164                 new_box[i][j] = self.building[4 - j][i]
165         self.building = new_box
166 
167     def clear_full_lines(self):
168         """消除满行的所有行"""
169         new_layout = [[0 if 1 < i < self.block_x_count - 2 and j < self.block_y_count - 2 else 1
170                        for i in range(self.block_x_count)] for j in range(self.block_y_count)]
171 
172         row_len = self.block_x_count - 4
173         new_row = self.block_y_count - 2 - 1
174         for cur_row in range(self.block_y_count - 2 - 1, 0, -1):
175             if sum(self.layout[cur_row][2:self.block_x_count - 2]) < row_len:
176                 new_layout[new_row] = self.layout[cur_row]
177                 new_row -= 1
178         self.layout = new_layout
179 
180     def put_building_to_layout(self):
181         """将积木放到棋盘里"""
182         for i in range(4, -1, -1):
183             for j in range(5):
184                 if self.building[i][j]:
185                     self.layout[i + self.building_top][j + self.building_left] = 1
186         #: 这里会调用消除函数
187         self.clear_full_lines()
188 
189     def draw_building(self, s):
190         """
191         显示积木
192         @:param s : pygame = screen 
193         """
194         cur_left, cur_top = self.building_left * Block.width, self.building_top * Block.height
195         for i in range(5):
196             for j in range(5):
197                 # 只画积木实体,不管盒子本身
198                 if self.building[j][i]:
199                     Block.draw(s, cur_left + i * Block.width, cur_top + j * Block.height, COLOR_BLACK, COLOR_WHITE)
200 
201     def draw(self, s):
202         """
203         显示棋盘
204         @:param s : pygame = screen 
205         """
206         for i in range(self.block_x_count):
207             for j in range(self.block_y_count):
208                 if self.layout[j][i] == 0:
209                     Block.draw(s, i * Block.width, j * Block.height, COLOR_WHITE, COLOR_BLACK)
210                 else:
211                     Block.draw(s, i * Block.width, j * Block.height, COLOR_BLACK, COLOR_WHITE)
212 
213 
214 # -------------------------------------------------------------------
215 # Main
216 # -------------------------------------------------------------------
217 def main():
218     #: 初始化
219     while True:
220         layout = Layout()
221         layout.create_new_building()
222         pygame.init()
223         pygame.display.set_caption('俄罗斯方块')
224         screen = pygame.display.set_mode((layout.size), 0, 32)
225         is_over = False
226         #: 单局游戏循环开始 [结束后直接重新开始]
227         while not is_over:
228             #: 处理游戏消息
229             for e in pygame.event.get():
230                 if e.type == pygame.QUIT:
231                     sys.exit()
232                 #: 处理按键
233                 if e.type == pygame.KEYDOWN:
234                     if e.key == pygame.K_UP:
235                         layout.convert_building()
236                     if e.key == pygame.K_DOWN:
237                         layout.direct_down()
238                     if e.key == pygame.K_LEFT:
239                         layout.move_left_right(-1)
240                     if e.key == pygame.K_RIGHT:
241                         layout.move_left_right(1)
242             #: 是否碰触底部地面了,是 -> 融合背景   否 -> 继续下落
243             if layout.test_building_touch_wall(y_offset=1):
244                 layout.put_building_to_layout()
245                 is_over = layout.create_new_building()
246             else:
247                 layout.down_build()
248             #: 绘制
249             layout.draw(screen)
250             layout.draw_building(screen)
251             pygame.display.update()
252             #: 速度
253             pygame.time.Clock().tick(layout.speed)
254 
255 
256 if __name__ == '__main__':
257     main()

 

效果:

在这里插入图片描述

在这里插入图片描述

posted @ 2021-02-18 19:23  BugMiaowu2021  阅读(1210)  评论(0编辑  收藏  举报