当前位置:   article > 正文

python游戏1——俄罗斯方块_python 俄罗斯方块

python 俄罗斯方块

1.创造方块:

1.1使用string和vector去创造对象

  1. # creating assets
  2. tetromino = []
  3. object1 = "..X." \
  4. "..X." \
  5. "..X." \
  6. "..X."
  7. object2 = "..X." \
  8. ".XX." \
  9. ".X.." \
  10. "...."
  11. object3 = ".X.." \
  12. ".XX." \
  13. "..X." \
  14. "...."
  15. object4 = "...." \
  16. ".XX." \
  17. ".XX." \
  18. "...."
  19. object5 = "..X." \
  20. ".XX." \
  21. "..X." \
  22. "...."
  23. object6 = "...." \
  24. ".XX." \
  25. "..X." \
  26. "..X."
  27. object7 = "...." \
  28. ".XX." \
  29. ".X.." \
  30. ".X.."
  31. tetromino.append(object1)
  32. tetromino.append(object2)
  33. tetromino.append(object3)
  34. tetromino.append(object4)
  35. tetromino.append(object5)
  36. tetromino.append(object6)
  37. tetromino.append(object7)
'
运行

2.旋转方块

俄罗斯方块中,我们总是希望可以将方块旋转。

2.1使用一维向量来表示二维向量

比如有下图这样的二维向量:

可以很轻松的通过x和y两个参数来进行索引(a[x][y])。同样也可以使用一个参数来索引,只要我们给每个位置一个数字作为索引,正如上图所示。例如,我们可以通过i[10]来索引a[2][2]。这里的10可以表示为2*4+2. 即以左上角为坐标原点,y*width+x。

2.2旋转方块

现在旋转方块90°后:

如果我们还是想索引a[2][2]这个位置,如图易得现在需要用i[6]来索引。 

通过图片可以轻易的看出,每当横坐标增加1,一维索引的数字就减少4;每当纵坐标增加1,一维索引的数字就增加1。因此旋转90°,索引数字为12-4x+y。

同样的:

 旋转180°索引数字为15-4y-x。

 旋转270°,索引数字为3-y+4x。

  1. def rotate(px, py, r):
  2. if r == 0:
  3. return py*4+px
  4. elif r == 1:
  5. return 12+py-4*px
  6. elif r == 2:
  7. return 15-4*py-px
  8. elif r == 3:
  9. return 3-py+4*px

3.界面

在本节中,我将构建一个12*18字段。我会用9来表示边缘。

  1. # Field
  2. fieldwidth = 12
  3. fieldheight = 18
  4. pField = [0 for i in range(fieldwidth*fieldheight)]
  5. # print(len(pField))
  6. for x in range(fieldwidth):
  7. for y in range(fieldheight):
  8. # print(y*fieldwidth+x)
  9. pField[y*fieldwidth+x] = 9 if (x == 0 or x == fieldwidth-1 or y == fieldheight-1) else 0

在这个项目中,我使用pygame来实现输出。

  1. 1 import pygame
  2. 2 # game window
  3. 3 pygame.init()
  4. 4 window_width = 480
  5. 5 window_height = 720
  6. 6 window_title = "Tetris"
  7. 7
  8. 8 screen = pygame.display.set_mode((window_width, window_height))
  9. 9 pygame.display.set_caption(window_title)
  10. 10
  11. 11 running = True
  12. 12 while running:
  13. 13 for event in pygame.event.get():
  14. 14 if event.type == pygame.QUIT:
  15. 15 running = False
  16. 16
  17. 17 # fill in black background
  18. 18 screen.fill((0, 0, 0))
  19. 19 # implement the game interface and blocks here
  20. 20 for x in range(fieldwidth):
  21. 21 for y in range(fieldheight):
  22. 22 # print(y*fieldwidth+x)
  23. 23 if pField[y*fieldwidth+x] == 9:
  24. 24 pygame.draw.rect(screen, (255,255,255), (x*40, y*40, 40,
  25. 40))
  26. 25 else:
  27. 26 ...
  28. 27 pygame.display.update()
  29. 28 pygame.quit()

输出结果如下图:

 4.游戏循环

游戏循环是游戏引擎中最重要的部分。这些都是一切发生的顺序。像俄罗斯方块这样的简单游戏并不是大规模的事件驱动应用程序。它包括一些元素,如时间、用户输入、游戏逻辑的日期,然后将其绘制在屏幕上。它一直这样做,直到游戏结束或用户退出为止。

4.1判断位置是否正确

此函数有四个参数:

nTetromino:它代表块的类型

nrotation:表示旋转角度

positionX:表示四阶块的水平坐标

positionY:表示四阶块的垂直坐标

  1. # judge if the position of the piece fit the rule
  2. def doesPieceFit(nTetromino, nrotation, positionX, positionY):
  3. for px in range(4):
  4. for py in range(4):
  5. # get the index
  6. pi = rotate(px, py, nrotation)
  7. # print(pi)
  8. # exit(0)
  9. #get index into field
  10. fi = int((positionY+py)*12+positionX+px)
  11. # print(fi)
  12. # exit(0)
  13. if (positionX+px >= 0) and (positionX+px <= 11):
  14. if (positionY+py >= 0) and (positionY+py <= 18):
  15. if tetromino[nTetromino][pi] == 'X' and ((pField[fi] == 1) or (pField[fi] == 9)):
  16. return False
  17. return True

4.2输入和相应的操作

        俄罗斯方块中有四种类型的输入:左移、右移、下移和旋转在程序中,我使用左、右、下和z键来对应四种不同的操作。

  1. 1 for event in pygame.event.get():
  2. 2 if event.type == pygame.QUIT:
  3. 3 gameover = True
  4. 4 elif event.type == pygame.KEYDOWN:
  5. 5 if event.key == pygame.K_LEFT:
  6. 6 bKey = 1
  7. 7 elif event.key == pygame.K_RIGHT:
  8. 8 bKey = 2
  9. 9 elif event.key == pygame.K_DOWN:
  10. 10 bKey = 3
  11. 11 elif event.key == pygame.K_z:
  12. 12 bKey = 4
  13. 13 # Game logic ======================================================
  14. 14 if bKey == 1 and doesPieceFit(nCurrentPiece, nCurrentRotation,
  15. nCurrentX-1, nCurrentY):
  16. 15 nCurrentX = nCurrentX - 1
  17. 16 bKey = 0
  18. 17
  19. 18 if bKey == 2 and doesPieceFit(nCurrentPiece, nCurrentRotation,
  20. nCurrentX+1, nCurrentY):
  21. 19 nCurrentX = nCurrentX + 1
  22. 20 bKey = 0
  23. 21
  24. 22 if bKey == 3 and doesPieceFit(nCurrentPiece, nCurrentRotation,
  25. nCurrentX, nCurrentY+1):
  26. 23 nCurrentY = nCurrentY + 1
  27. 24 bKey = 0
  28. 25
  29. 26 if bKey == 4 and doesPieceFit(nCurrentPiece, (nCurrentRotation+1)%4,
  30. nCurrentX, nCurrentY):
  31. 27 nCurrentRotation += 1
  32. 28 nCurrentRotation %= 4
  33. 29 bKey = 0

但是,如果使用上述方法,每轮只能输入一个按钮,所以我使用了一个列表来保存每轮的输入。

  1. # input ===========================================================
  2. for event in pygame.event.get():
  3. if event.type == pygame.QUIT:
  4. gameover = True
  5. elif event.type == pygame.KEYDOWN:
  6. if event.key == pygame.K_LEFT:
  7. # 用户按下了左箭头键
  8. # print("左箭头键被按下")
  9. # bKey = 1
  10. bKey.append(1)
  11. elif event.key == pygame.K_RIGHT:
  12. # 用户按下了右箭头键
  13. # print("右箭头键被按下")
  14. # bKey = 2
  15. bKey.append(2)
  16. elif event.key == pygame.K_DOWN:
  17. # 用户按下了下箭头键
  18. # print("下箭头键被按下")
  19. # bKey = 3
  20. bKey.append(3)
  21. elif event.key == pygame.K_z:
  22. # 用户按下了上箭头键
  23. # print("上箭头键被按下")
  24. # bKey = 4
  25. bKey.append(4)
  26. # Game logic ======================================================
  27. if (1 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX-1, nCurrentY):
  28. nCurrentX = nCurrentX - 1
  29. bKey.remove(1)
  30. # bKey=0
  31. if (2 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX+1, nCurrentY):
  32. nCurrentX = nCurrentX + 1
  33. bKey.remove(2)
  34. # bKey=0
  35. if (3 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY+1):
  36. nCurrentY = nCurrentY + 1
  37. bKey.remove(3)
  38. # bKey=0
  39. if (4 in bKey) and doesPieceFit(nCurrentPiece, (nCurrentRotation+1)%4, nCurrentX, nCurrentY):
  40. nCurrentRotation += 1
  41. nCurrentRotation %= 4
  42. bKey.remove(4)
  43. # bKey=0

4.3物块下降

在俄罗斯方块中,方块会周期性地掉落。下落功能可以通过添加时间判断来容易地实现。

  1. fall_time = 0.5
  2. last_fall_time = time.time()
  3. if current_time - last_fall_time >= fall_time:
  4. if doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX,nCurrentY + 1):
  5. nCurrentY += 1
  6. last_fall_time = current_time

当然,我们还需要增加一个判断功能,看看方块是否可以继续下降。如果它不能下降,我们需要完成一系列的事情。

首先,我们需要将当前方块锁定到字段中。然后,检查我们是否有线路。最后,我们选择下一块,并检查它是否合适。

  1. else:
  2. 2 # lock the current piece into the field.
  3. 3 for px in range(4):
  4. 4 for py in range(4):
  5. 5 if tetromino[nCurrentPiece][rotate(px, py,
  6. nCurrentRotation)] == ’X’:
  7. 6 # print(len(pField))
  8. 7 #
  9. print(int((nCurrentY+py)*fieldwidth+nCurrentX+px))
  10. 8 pField[int((nCurrentY+py)*fieldwidth+nCurrentX+px)]= 1
  11. 9 # check if we get any lines.
  12. 10 for py in range(4):
  13. 11 if nCurrentY+py<fieldheight-1:
  14. 12 bline = True
  15. 13 for px in range(1, fieldwidth):
  16. 14 if pField[(nCurrentY+py)*fieldwidth+px] == 0:
  17. 15 bline = False
  18. 16 if bline:
  19. 17 # remove the line
  20. 18 for px in range(1, fieldwidth-1):
  21. 19 pField[(nCurrentY + py) * fieldwidth + px] = 8
  22. 20 vline.append(nCurrentY+py)
  23. 21 # Finally, we choose next piece
  24. 22 nCurrentX = fieldwidth//2
  25. 23 nCurrentY = 0
  26. 24 nCurrentRotation = 0
  27. 25 nCurrentPiece = random.randint(0, 6)
  28. 26 # check if piece fits.
  29. 27 gameover = not doesPieceFit(nCurrentPiece, nCurrentRotation,nCurrentX, nCurrentY)
  30. 1 if len(vline) != 0:
  31. 2 pField_copy = copy.deepcopy(pField)
  32. 3 for dy in vline:
  33. 4 for dx in range(1, fieldwidth-1):
  34. 5 pField[dy*fieldwidth+dx] = 0
  35. 6 for dy in range(0, vline[0]):
  36. 7 for dx in range(1, fieldwidth-1):
  37. 8 pField[(dy + len(vline)) * fieldwidth + dx] = 0
  38. 9 for dy in range(0, vline[0]):
  39. 10 for dx in range(1, fieldwidth-1):
  40. 11 if pField_copy[dy*fieldwidth+dx] == 1:
  41. 12 pField[(dy+len(vline))*fieldwidth+dx] = 1
  42. 13 vline = []

5.附加功能:增加难度和分数显示

很容易可以通过以下代码实现:

  1. 1 nPieceCount = 1
  2. 2 nscore = 0
  3. 3
  4. 4 for py in range(4):
  5. 5 if nCurrentY+py<fieldheight-1:
  6. 6 bline = True
  7. 7 for px in range(1, fieldwidth):
  8. 8 if pField[(nCurrentY+py)*fieldwidth+px] == 0:
  9. 9 bline = False
  10. 10 if bline:
  11. 11 # remove the line
  12. 12 for px in range(1, fieldwidth-1):
  13. 13 pField[(nCurrentY + py) * fieldwidth + px] = 8
  14. 14 vline.append(nCurrentY+py)
  15. 15 # Finally, we choose next piece
  16. 16 nCurrentX = fieldwidth//2
  17. 17 nCurrentY = 0
  18. 18 nCurrentRotation = 0
  19. 19 nCurrentPiece = random.randint(0, 6)
  20. 20 nPieceCount += 1
  21. 21 nscore += 100
  22. 22
  23. 23 font = pygame.font.Font(None, 36)
  24. 24 score_text = font.render("Score: " + str(nscore), True, (255, 135,207))
  25. 25 screen.blit(score_text, (10, 10))

全部的代码如下:

  1. import random
  2. import copy
  3. import pygame
  4. import time
  5. # creating assets
  6. tetromino = []
  7. object1 = "..X." \
  8. "..X." \
  9. "..X." \
  10. "..X."
  11. object2 = "..X." \
  12. ".XX." \
  13. ".X.." \
  14. "...."
  15. object3 = ".X.." \
  16. ".XX." \
  17. "..X." \
  18. "...."
  19. object4 = "...." \
  20. ".XX." \
  21. ".XX." \
  22. "...."
  23. object5 = "..X." \
  24. ".XX." \
  25. "..X." \
  26. "...."
  27. object6 = "...." \
  28. ".XX." \
  29. "..X." \
  30. "..X."
  31. object7 = "...." \
  32. ".XX." \
  33. ".X.." \
  34. ".X.."
  35. tetromino.append(object1)
  36. tetromino.append(object2)
  37. tetromino.append(object3)
  38. tetromino.append(object4)
  39. tetromino.append(object5)
  40. tetromino.append(object6)
  41. tetromino.append(object7)
  42. # print(tetromino[1])
  43. #
  44. # exit(0)
  45. # rotate
  46. def rotate(px, py, r):
  47. if r == 0:
  48. return py*4+px
  49. elif r == 1:
  50. return 12+py-4*px
  51. elif r == 2:
  52. return 15-4*py-px
  53. elif r == 3:
  54. return 3-py+4*px
  55. # Field
  56. fieldwidth = 12
  57. fieldheight = 18
  58. pField = [0 for i in range(fieldwidth*fieldheight)]
  59. # print(len(pField))
  60. for x in range(fieldwidth):
  61. for y in range(fieldheight):
  62. # print(y*fieldwidth+x)
  63. pField[y*fieldwidth+x] = 9 if (x == 0 or x == fieldwidth-1 or y == fieldheight-1) else 0
  64. # print(pField)
  65. # game window
  66. pygame.init()
  67. window_width = 480
  68. window_height = 720
  69. window_title = "Tetris"
  70. screen = pygame.display.set_mode((window_width, window_height))
  71. pygame.display.set_caption(window_title)
  72. # judge if the position of the piece fit the rule
  73. def doesPieceFit(nTetromino, nrotation, positionX, positionY):
  74. for px in range(4):
  75. for py in range(4):
  76. # get the index
  77. pi = rotate(px, py, nrotation)
  78. # print(pi)
  79. # exit(0)
  80. #get index into field
  81. fi = int((positionY+py)*12+positionX+px)
  82. # print(fi)
  83. # exit(0)
  84. if (positionX+px >= 0) and (positionX+px <= 11):
  85. if (positionY+py >= 0) and (positionY+py <= 18):
  86. if tetromino[nTetromino][pi] == 'X' and ((pField[fi] == 1) or (pField[fi] == 9)):
  87. return False
  88. return True
  89. # Game logic stuff======================================================
  90. gameover = False
  91. # which piece is falling
  92. nCurrentPiece = random.randint(0, 6)
  93. # is it rotate
  94. nCurrentRotation = 0
  95. nCurrentX = fieldwidth/2
  96. nCurrentY = 0
  97. bKey = []
  98. clock = pygame.time.Clock()
  99. fps = 60
  100. wait_time = 100
  101. fall_time = 0.5
  102. last_fall_time = time.time() # 初始化最后一次下降时间点
  103. vline = []
  104. nPieceCount = 1
  105. nscore = 0
  106. # Render output ===================================================
  107. while not gameover:
  108. # game timing =====================================================
  109. clock.tick(fps)
  110. current_time = time.time() # 当前时间
  111. # input ===========================================================
  112. for event in pygame.event.get():
  113. if event.type == pygame.QUIT:
  114. gameover = True
  115. elif event.type == pygame.KEYDOWN:
  116. if event.key == pygame.K_LEFT:
  117. # 用户按下了左箭头键
  118. # print("左箭头键被按下")
  119. # bKey = 1
  120. bKey.append(1)
  121. elif event.key == pygame.K_RIGHT:
  122. # 用户按下了右箭头键
  123. # print("右箭头键被按下")
  124. # bKey = 2
  125. bKey.append(2)
  126. elif event.key == pygame.K_DOWN:
  127. # 用户按下了下箭头键
  128. # print("下箭头键被按下")
  129. # bKey = 3
  130. bKey.append(3)
  131. elif event.key == pygame.K_z:
  132. # 用户按下了上箭头键
  133. # print("上箭头键被按下")
  134. # bKey = 4
  135. bKey.append(4)
  136. # Game logic ======================================================
  137. if (1 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX-1, nCurrentY):
  138. nCurrentX = nCurrentX - 1
  139. bKey.remove(1)
  140. # bKey=0
  141. if (2 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX+1, nCurrentY):
  142. nCurrentX = nCurrentX + 1
  143. bKey.remove(2)
  144. # bKey=0
  145. if (3 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY+1):
  146. nCurrentY = nCurrentY + 1
  147. bKey.remove(3)
  148. # bKey=0
  149. if (4 in bKey) and doesPieceFit(nCurrentPiece, (nCurrentRotation+1)%4, nCurrentX, nCurrentY):
  150. nCurrentRotation += 1
  151. nCurrentRotation %= 4
  152. bKey.remove(4)
  153. # bKey=0
  154. if current_time - last_fall_time >= fall_time:
  155. # 执行方块的下降操作
  156. if doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY + 1):
  157. nCurrentY += 1
  158. last_fall_time = current_time # 更新最后一次下降时间点
  159. else:
  160. # lock the current piece into the field.
  161. for px in range(4):
  162. for py in range(4):
  163. if tetromino[nCurrentPiece][rotate(px, py, nCurrentRotation)] == 'X':
  164. # print(len(pField))
  165. # print(int((nCurrentY+py)*fieldwidth+nCurrentX+px))
  166. pField[int((nCurrentY+py)*fieldwidth+nCurrentX+px)] = 1
  167. # check if we get any lines.
  168. for py in range(4):
  169. if nCurrentY+py<fieldheight-1:
  170. bline = True
  171. for px in range(1, fieldwidth):
  172. if pField[(nCurrentY+py)*fieldwidth+px] == 0:
  173. bline = False
  174. if bline:
  175. # remove the line
  176. for px in range(1, fieldwidth-1):
  177. pField[(nCurrentY + py) * fieldwidth + px] = 8
  178. vline.append(nCurrentY+py)
  179. # Finally, we choose next piece
  180. nCurrentX = fieldwidth//2
  181. nCurrentY = 0
  182. nCurrentRotation = 0
  183. nCurrentPiece = random.randint(0, 6)
  184. nPieceCount += 1
  185. nscore += 100
  186. # check if piece fits.
  187. gameover = not doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY)
  188. # Fill in black background
  189. screen.fill((0, 0, 0))
  190. # Draw field pygame.draw.rect(screen, (255, 0, 0), (block_x, block_y, block_size, block_size))
  191. # pygame.draw.rect(screen, (255, 0, 0), (0, 0, 10, 10))
  192. for x in range(fieldwidth):
  193. for y in range(fieldheight):
  194. # print(y*fieldwidth+x)
  195. if pField[y*fieldwidth+x] == 9:
  196. pygame.draw.rect(screen, (255, 255, 179), (x*40, y*40, 40, 40))
  197. if pField[y*fieldwidth+x] == 1:
  198. pygame.draw.rect(screen, (255, 255, 255), (x*40, y*40, 40, 40))
  199. if pField[y*fieldwidth+x] == 8:
  200. pygame.draw.rect(screen, (255, 209, 224), (x*40, y*40, 40, 40))
  201. # draw current piece
  202. else:
  203. for px in range(4):
  204. for py in range(4):
  205. if tetromino[nCurrentPiece][rotate(px, py, nCurrentRotation)] == 'X':
  206. pygame.draw.rect(screen, (255, 255, 255), ((nCurrentX+px) * 40, (nCurrentY+py) * 40, 40, 40))
  207. if len(vline) != 0:
  208. pField_copy = copy.deepcopy(pField)
  209. nscore += 114514*len(vline)
  210. for dy in vline:
  211. for dx in range(1, fieldwidth-1):
  212. pField[dy*fieldwidth+dx] = 0
  213. for dy in range(0, vline[0]):
  214. for dx in range(1, fieldwidth-1):
  215. pField[(dy + len(vline)) * fieldwidth + dx] = 0
  216. for dy in range(0, vline[0]):
  217. for dx in range(1, fieldwidth-1):
  218. if pField_copy[dy*fieldwidth+dx] == 1:
  219. pField[(dy+len(vline))*fieldwidth+dx] = 1
  220. vline = []
  221. if (nPieceCount%10 == 0) and fall_time>0.2:
  222. fall_time -= 0.01
  223. font = pygame.font.Font(None, 36) # 创建字体对象
  224. score_text = font.render("Score: " + str(nscore), True, (255, 135, 207)) # 渲染分数文本
  225. screen.blit(score_text, (10, 10)) # 在屏幕上绘制分数文本的位置
  226. # pygame.time.delay(wait_time)
  227. pygame.display.update()
  228. pygame.quit()
  229. # print(tetromino)

运行视频:

...

github链接:

https://github.com/NanGongXun/Python_Tetris.git

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/832533
推荐阅读
相关标签
  

闽ICP备14008679号