赞
踩
- # creating assets
- tetromino = []
- object1 = "..X." \
- "..X." \
- "..X." \
- "..X."
- object2 = "..X." \
- ".XX." \
- ".X.." \
- "...."
- object3 = ".X.." \
- ".XX." \
- "..X." \
- "...."
- object4 = "...." \
- ".XX." \
- ".XX." \
- "...."
- object5 = "..X." \
- ".XX." \
- "..X." \
- "...."
- object6 = "...." \
- ".XX." \
- "..X." \
- "..X."
- object7 = "...." \
- ".XX." \
- ".X.." \
- ".X.."
-
- tetromino.append(object1)
- tetromino.append(object2)
- tetromino.append(object3)
- tetromino.append(object4)
- tetromino.append(object5)
- tetromino.append(object6)
- tetromino.append(object7)
'运行
在俄罗斯方块中,我们总是希望可以将方块旋转。
比如有下图这样的二维向量:
可以很轻松的通过x和y两个参数来进行索引(a[x][y])。同样也可以使用一个参数来索引,只要我们给每个位置一个数字作为索引,正如上图所示。例如,我们可以通过i[10]来索引a[2][2]。这里的10可以表示为2*4+2. 即以左上角为坐标原点,y*width+x。
现在旋转方块90°后:
如果我们还是想索引a[2][2]这个位置,如图易得现在需要用i[6]来索引。
通过图片可以轻易的看出,每当横坐标增加1,一维索引的数字就减少4;每当纵坐标增加1,一维索引的数字就增加1。因此旋转90°,索引数字为12-4x+y。
同样的:
旋转180°索引数字为15-4y-x。
旋转270°,索引数字为3-y+4x。
- def rotate(px, py, r):
- if r == 0:
- return py*4+px
- elif r == 1:
- return 12+py-4*px
- elif r == 2:
- return 15-4*py-px
- elif r == 3:
- return 3-py+4*px
在本节中,我将构建一个12*18字段。我会用9来表示边缘。
- # Field
- fieldwidth = 12
- fieldheight = 18
-
- pField = [0 for i in range(fieldwidth*fieldheight)]
- # print(len(pField))
- for x in range(fieldwidth):
- for y in range(fieldheight):
- # print(y*fieldwidth+x)
- pField[y*fieldwidth+x] = 9 if (x == 0 or x == fieldwidth-1 or y == fieldheight-1) else 0
在这个项目中,我使用pygame来实现输出。
- 1 import pygame
- 2 # game window
- 3 pygame.init()
- 4 window_width = 480
- 5 window_height = 720
- 6 window_title = "Tetris"
- 7
- 8 screen = pygame.display.set_mode((window_width, window_height))
- 9 pygame.display.set_caption(window_title)
- 10
- 11 running = True
- 12 while running:
- 13 for event in pygame.event.get():
- 14 if event.type == pygame.QUIT:
- 15 running = False
- 16
- 17 # fill in black background
- 18 screen.fill((0, 0, 0))
- 19 # implement the game interface and blocks here
- 20 for x in range(fieldwidth):
- 21 for y in range(fieldheight):
- 22 # print(y*fieldwidth+x)
- 23 if pField[y*fieldwidth+x] == 9:
- 24 pygame.draw.rect(screen, (255,255,255), (x*40, y*40, 40,
- 40))
- 25 else:
- 26 ...
- 27 pygame.display.update()
- 28 pygame.quit()
输出结果如下图:
游戏循环是游戏引擎中最重要的部分。这些都是一切发生的顺序。像俄罗斯方块这样的简单游戏并不是大规模的事件驱动应用程序。它包括一些元素,如时间、用户输入、游戏逻辑的日期,然后将其绘制在屏幕上。它一直这样做,直到游戏结束或用户退出为止。
此函数有四个参数:
nTetromino:它代表块的类型
nrotation:表示旋转角度
positionX:表示四阶块的水平坐标
positionY:表示四阶块的垂直坐标
- # judge if the position of the piece fit the rule
- def doesPieceFit(nTetromino, nrotation, positionX, positionY):
- for px in range(4):
- for py in range(4):
- # get the index
- pi = rotate(px, py, nrotation)
- # print(pi)
- # exit(0)
- #get index into field
- fi = int((positionY+py)*12+positionX+px)
- # print(fi)
- # exit(0)
- if (positionX+px >= 0) and (positionX+px <= 11):
- if (positionY+py >= 0) and (positionY+py <= 18):
- if tetromino[nTetromino][pi] == 'X' and ((pField[fi] == 1) or (pField[fi] == 9)):
- return False
-
- return True
俄罗斯方块中有四种类型的输入:左移、右移、下移和旋转在程序中,我使用左、右、下和z键来对应四种不同的操作。
- 1 for event in pygame.event.get():
- 2 if event.type == pygame.QUIT:
- 3 gameover = True
- 4 elif event.type == pygame.KEYDOWN:
- 5 if event.key == pygame.K_LEFT:
- 6 bKey = 1
- 7 elif event.key == pygame.K_RIGHT:
- 8 bKey = 2
- 9 elif event.key == pygame.K_DOWN:
- 10 bKey = 3
- 11 elif event.key == pygame.K_z:
- 12 bKey = 4
- 13 # Game logic ======================================================
- 14 if bKey == 1 and doesPieceFit(nCurrentPiece, nCurrentRotation,
- nCurrentX-1, nCurrentY):
- 15 nCurrentX = nCurrentX - 1
- 16 bKey = 0
- 17
- 18 if bKey == 2 and doesPieceFit(nCurrentPiece, nCurrentRotation,
- nCurrentX+1, nCurrentY):
- 19 nCurrentX = nCurrentX + 1
- 20 bKey = 0
- 21
- 22 if bKey == 3 and doesPieceFit(nCurrentPiece, nCurrentRotation,
- nCurrentX, nCurrentY+1):
- 23 nCurrentY = nCurrentY + 1
- 24 bKey = 0
- 25
- 26 if bKey == 4 and doesPieceFit(nCurrentPiece, (nCurrentRotation+1)%4,
- nCurrentX, nCurrentY):
- 27 nCurrentRotation += 1
- 28 nCurrentRotation %= 4
- 29 bKey = 0
但是,如果使用上述方法,每轮只能输入一个按钮,所以我使用了一个列表来保存每轮的输入。
- # input ===========================================================
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- gameover = True
- elif event.type == pygame.KEYDOWN:
- if event.key == pygame.K_LEFT:
- # 用户按下了左箭头键
- # print("左箭头键被按下")
- # bKey = 1
- bKey.append(1)
- elif event.key == pygame.K_RIGHT:
- # 用户按下了右箭头键
- # print("右箭头键被按下")
- # bKey = 2
- bKey.append(2)
- elif event.key == pygame.K_DOWN:
- # 用户按下了下箭头键
- # print("下箭头键被按下")
- # bKey = 3
- bKey.append(3)
- elif event.key == pygame.K_z:
- # 用户按下了上箭头键
- # print("上箭头键被按下")
- # bKey = 4
- bKey.append(4)
- # Game logic ======================================================
- if (1 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX-1, nCurrentY):
- nCurrentX = nCurrentX - 1
- bKey.remove(1)
- # bKey=0
-
- if (2 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX+1, nCurrentY):
- nCurrentX = nCurrentX + 1
- bKey.remove(2)
- # bKey=0
-
- if (3 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY+1):
- nCurrentY = nCurrentY + 1
- bKey.remove(3)
- # bKey=0
-
- if (4 in bKey) and doesPieceFit(nCurrentPiece, (nCurrentRotation+1)%4, nCurrentX, nCurrentY):
- nCurrentRotation += 1
- nCurrentRotation %= 4
- bKey.remove(4)
- # bKey=0
在俄罗斯方块中,方块会周期性地掉落。下落功能可以通过添加时间判断来容易地实现。
- fall_time = 0.5
- last_fall_time = time.time()
- if current_time - last_fall_time >= fall_time:
- if doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX,nCurrentY + 1):
- nCurrentY += 1
- last_fall_time = current_time
当然,我们还需要增加一个判断功能,看看方块是否可以继续下降。如果它不能下降,我们需要完成一系列的事情。
首先,我们需要将当前方块锁定到字段中。然后,检查我们是否有线路。最后,我们选择下一块,并检查它是否合适。
- else:
- 2 # lock the current piece into the field.
- 3 for px in range(4):
- 4 for py in range(4):
- 5 if tetromino[nCurrentPiece][rotate(px, py,
- nCurrentRotation)] == ’X’:
- 6 # print(len(pField))
- 7 #
- print(int((nCurrentY+py)*fieldwidth+nCurrentX+px))
- 8 pField[int((nCurrentY+py)*fieldwidth+nCurrentX+px)]= 1
- 9 # check if we get any lines.
- 10 for py in range(4):
- 11 if nCurrentY+py<fieldheight-1:
- 12 bline = True
- 13 for px in range(1, fieldwidth):
- 14 if pField[(nCurrentY+py)*fieldwidth+px] == 0:
- 15 bline = False
- 16 if bline:
- 17 # remove the line
- 18 for px in range(1, fieldwidth-1):
- 19 pField[(nCurrentY + py) * fieldwidth + px] = 8
- 20 vline.append(nCurrentY+py)
- 21 # Finally, we choose next piece
- 22 nCurrentX = fieldwidth//2
- 23 nCurrentY = 0
- 24 nCurrentRotation = 0
- 25 nCurrentPiece = random.randint(0, 6)
- 26 # check if piece fits.
- 27 gameover = not doesPieceFit(nCurrentPiece, nCurrentRotation,nCurrentX, nCurrentY)
- 1 if len(vline) != 0:
- 2 pField_copy = copy.deepcopy(pField)
- 3 for dy in vline:
- 4 for dx in range(1, fieldwidth-1):
- 5 pField[dy*fieldwidth+dx] = 0
- 6 for dy in range(0, vline[0]):
- 7 for dx in range(1, fieldwidth-1):
- 8 pField[(dy + len(vline)) * fieldwidth + dx] = 0
- 9 for dy in range(0, vline[0]):
- 10 for dx in range(1, fieldwidth-1):
- 11 if pField_copy[dy*fieldwidth+dx] == 1:
- 12 pField[(dy+len(vline))*fieldwidth+dx] = 1
- 13 vline = []
很容易可以通过以下代码实现:
- 1 nPieceCount = 1
- 2 nscore = 0
- 3
- 4 for py in range(4):
- 5 if nCurrentY+py<fieldheight-1:
- 6 bline = True
- 7 for px in range(1, fieldwidth):
- 8 if pField[(nCurrentY+py)*fieldwidth+px] == 0:
- 9 bline = False
- 10 if bline:
- 11 # remove the line
- 12 for px in range(1, fieldwidth-1):
- 13 pField[(nCurrentY + py) * fieldwidth + px] = 8
- 14 vline.append(nCurrentY+py)
- 15 # Finally, we choose next piece
- 16 nCurrentX = fieldwidth//2
- 17 nCurrentY = 0
- 18 nCurrentRotation = 0
- 19 nCurrentPiece = random.randint(0, 6)
- 20 nPieceCount += 1
- 21 nscore += 100
- 22
- 23 font = pygame.font.Font(None, 36)
- 24 score_text = font.render("Score: " + str(nscore), True, (255, 135,207))
- 25 screen.blit(score_text, (10, 10))
全部的代码如下:
- import random
- import copy
- import pygame
- import time
- # creating assets
- tetromino = []
- object1 = "..X." \
- "..X." \
- "..X." \
- "..X."
- object2 = "..X." \
- ".XX." \
- ".X.." \
- "...."
- object3 = ".X.." \
- ".XX." \
- "..X." \
- "...."
- object4 = "...." \
- ".XX." \
- ".XX." \
- "...."
- object5 = "..X." \
- ".XX." \
- "..X." \
- "...."
- object6 = "...." \
- ".XX." \
- "..X." \
- "..X."
- object7 = "...." \
- ".XX." \
- ".X.." \
- ".X.."
-
- tetromino.append(object1)
- tetromino.append(object2)
- tetromino.append(object3)
- tetromino.append(object4)
- tetromino.append(object5)
- tetromino.append(object6)
- tetromino.append(object7)
- # print(tetromino[1])
- #
- # exit(0)
- # rotate
- def rotate(px, py, r):
- if r == 0:
- return py*4+px
- elif r == 1:
- return 12+py-4*px
- elif r == 2:
- return 15-4*py-px
- elif r == 3:
- return 3-py+4*px
-
-
- # Field
- fieldwidth = 12
- fieldheight = 18
-
- pField = [0 for i in range(fieldwidth*fieldheight)]
- # print(len(pField))
- for x in range(fieldwidth):
- for y in range(fieldheight):
- # print(y*fieldwidth+x)
- pField[y*fieldwidth+x] = 9 if (x == 0 or x == fieldwidth-1 or y == fieldheight-1) else 0
-
- # print(pField)
- # game window
- pygame.init()
- window_width = 480
- window_height = 720
- window_title = "Tetris"
-
- screen = pygame.display.set_mode((window_width, window_height))
- pygame.display.set_caption(window_title)
-
- # judge if the position of the piece fit the rule
- def doesPieceFit(nTetromino, nrotation, positionX, positionY):
- for px in range(4):
- for py in range(4):
- # get the index
- pi = rotate(px, py, nrotation)
- # print(pi)
- # exit(0)
- #get index into field
- fi = int((positionY+py)*12+positionX+px)
- # print(fi)
- # exit(0)
- if (positionX+px >= 0) and (positionX+px <= 11):
- if (positionY+py >= 0) and (positionY+py <= 18):
- if tetromino[nTetromino][pi] == 'X' and ((pField[fi] == 1) or (pField[fi] == 9)):
- return False
-
- return True
-
- # Game logic stuff======================================================
- gameover = False
- # which piece is falling
- nCurrentPiece = random.randint(0, 6)
- # is it rotate
- nCurrentRotation = 0
- nCurrentX = fieldwidth/2
- nCurrentY = 0
-
- bKey = []
- clock = pygame.time.Clock()
- fps = 60
- wait_time = 100
-
- fall_time = 0.5
- last_fall_time = time.time() # 初始化最后一次下降时间点
- vline = []
-
- nPieceCount = 1
- nscore = 0
- # Render output ===================================================
-
- while not gameover:
- # game timing =====================================================
- clock.tick(fps)
- current_time = time.time() # 当前时间
- # input ===========================================================
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- gameover = True
- elif event.type == pygame.KEYDOWN:
- if event.key == pygame.K_LEFT:
- # 用户按下了左箭头键
- # print("左箭头键被按下")
- # bKey = 1
- bKey.append(1)
- elif event.key == pygame.K_RIGHT:
- # 用户按下了右箭头键
- # print("右箭头键被按下")
- # bKey = 2
- bKey.append(2)
- elif event.key == pygame.K_DOWN:
- # 用户按下了下箭头键
- # print("下箭头键被按下")
- # bKey = 3
- bKey.append(3)
- elif event.key == pygame.K_z:
- # 用户按下了上箭头键
- # print("上箭头键被按下")
- # bKey = 4
- bKey.append(4)
- # Game logic ======================================================
- if (1 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX-1, nCurrentY):
- nCurrentX = nCurrentX - 1
- bKey.remove(1)
- # bKey=0
-
- if (2 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX+1, nCurrentY):
- nCurrentX = nCurrentX + 1
- bKey.remove(2)
- # bKey=0
-
- if (3 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY+1):
- nCurrentY = nCurrentY + 1
- bKey.remove(3)
- # bKey=0
-
- if (4 in bKey) and doesPieceFit(nCurrentPiece, (nCurrentRotation+1)%4, nCurrentX, nCurrentY):
- nCurrentRotation += 1
- nCurrentRotation %= 4
- bKey.remove(4)
- # bKey=0
-
- if current_time - last_fall_time >= fall_time:
- # 执行方块的下降操作
- if doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY + 1):
- nCurrentY += 1
- last_fall_time = current_time # 更新最后一次下降时间点
- else:
- # lock the current piece into the field.
- for px in range(4):
- for py in range(4):
- if tetromino[nCurrentPiece][rotate(px, py, nCurrentRotation)] == 'X':
- # print(len(pField))
- # print(int((nCurrentY+py)*fieldwidth+nCurrentX+px))
- pField[int((nCurrentY+py)*fieldwidth+nCurrentX+px)] = 1
- # check if we get any lines.
- for py in range(4):
- if nCurrentY+py<fieldheight-1:
- bline = True
- for px in range(1, fieldwidth):
- if pField[(nCurrentY+py)*fieldwidth+px] == 0:
- bline = False
- if bline:
- # remove the line
- for px in range(1, fieldwidth-1):
- pField[(nCurrentY + py) * fieldwidth + px] = 8
- vline.append(nCurrentY+py)
- # Finally, we choose next piece
- nCurrentX = fieldwidth//2
- nCurrentY = 0
- nCurrentRotation = 0
- nCurrentPiece = random.randint(0, 6)
- nPieceCount += 1
- nscore += 100
- # check if piece fits.
- gameover = not doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY)
- # Fill in black background
- screen.fill((0, 0, 0))
- # Draw field pygame.draw.rect(screen, (255, 0, 0), (block_x, block_y, block_size, block_size))
- # pygame.draw.rect(screen, (255, 0, 0), (0, 0, 10, 10))
- for x in range(fieldwidth):
- for y in range(fieldheight):
- # print(y*fieldwidth+x)
- if pField[y*fieldwidth+x] == 9:
- pygame.draw.rect(screen, (255, 255, 179), (x*40, y*40, 40, 40))
- if pField[y*fieldwidth+x] == 1:
- pygame.draw.rect(screen, (255, 255, 255), (x*40, y*40, 40, 40))
- if pField[y*fieldwidth+x] == 8:
- pygame.draw.rect(screen, (255, 209, 224), (x*40, y*40, 40, 40))
- # draw current piece
- else:
- for px in range(4):
- for py in range(4):
- if tetromino[nCurrentPiece][rotate(px, py, nCurrentRotation)] == 'X':
- pygame.draw.rect(screen, (255, 255, 255), ((nCurrentX+px) * 40, (nCurrentY+py) * 40, 40, 40))
-
- if len(vline) != 0:
- pField_copy = copy.deepcopy(pField)
- nscore += 114514*len(vline)
- for dy in vline:
- for dx in range(1, fieldwidth-1):
- pField[dy*fieldwidth+dx] = 0
- for dy in range(0, vline[0]):
- for dx in range(1, fieldwidth-1):
- pField[(dy + len(vline)) * fieldwidth + dx] = 0
- for dy in range(0, vline[0]):
- for dx in range(1, fieldwidth-1):
- if pField_copy[dy*fieldwidth+dx] == 1:
- pField[(dy+len(vline))*fieldwidth+dx] = 1
- vline = []
-
- if (nPieceCount%10 == 0) and fall_time>0.2:
- fall_time -= 0.01
-
-
- font = pygame.font.Font(None, 36) # 创建字体对象
- score_text = font.render("Score: " + str(nscore), True, (255, 135, 207)) # 渲染分数文本
- screen.blit(score_text, (10, 10)) # 在屏幕上绘制分数文本的位置
-
- # pygame.time.delay(wait_time)
- pygame.display.update()
-
-
-
- pygame.quit()
-
- # print(tetromino)
-
-
-
-
-
-
运行视频:
...
github链接:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。