python游戏1——俄罗斯方块
1.创造方块:
1.1使用string和vector去创造对象
# 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)
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。
def rotate(px, py, r):if r == 0:return py*4+pxelif r == 1:return 12+py-4*pxelif r == 2:return 15-4*py-pxelif r == 3:return 3-py+4*px
3.界面
在本节中,我将构建一个12*18字段。我会用9来表示边缘。
# Field
fieldwidth = 12
fieldheight = 18pField = [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()
输出结果如下图:

4.游戏循环
游戏循环是游戏引擎中最重要的部分。这些都是一切发生的顺序。像俄罗斯方块这样的简单游戏并不是大规模的事件驱动应用程序。它包括一些元素,如时间、用户输入、游戏逻辑的日期,然后将其绘制在屏幕上。它一直这样做,直到游戏结束或用户退出为止。
4.1判断位置是否正确
此函数有四个参数:
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 indexpi = rotate(px, py, nrotation)# print(pi)# exit(0)#get index into fieldfi = 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 Falsereturn True
4.2输入和相应的操作
俄罗斯方块中有四种类型的输入:左移、右移、下移和旋转在程序中,我使用左、右、下和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 = Trueelif event.type == pygame.KEYDOWN:if event.key == pygame.K_LEFT:# 用户按下了左箭头键# print("左箭头键被按下")# bKey = 1bKey.append(1)elif event.key == pygame.K_RIGHT:# 用户按下了右箭头键# print("右箭头键被按下")# bKey = 2bKey.append(2)elif event.key == pygame.K_DOWN:# 用户按下了下箭头键# print("下箭头键被按下")# bKey = 3bKey.append(3)elif event.key == pygame.K_z:# 用户按下了上箭头键# print("上箭头键被按下")# bKey = 4bKey.append(4)
# Game logic ======================================================if (1 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX-1, nCurrentY):nCurrentX = nCurrentX - 1bKey.remove(1)# bKey=0if (2 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX+1, nCurrentY):nCurrentX = nCurrentX + 1bKey.remove(2)# bKey=0if (3 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY+1):nCurrentY = nCurrentY + 1bKey.remove(3)# bKey=0if (4 in bKey) and doesPieceFit(nCurrentPiece, (nCurrentRotation+1)%4, nCurrentX, nCurrentY):nCurrentRotation += 1nCurrentRotation %= 4bKey.remove(4)# bKey=0
4.3物块下降
在俄罗斯方块中,方块会周期性地掉落。下落功能可以通过添加时间判断来容易地实现。
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 += 1last_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
5.附加功能:增加难度和分数显示
很容易可以通过以下代码实现:
1 nPieceCount = 1
2 nscore = 0
3
4 for py in range(4):
5 if nCurrentY+py
全部的代码如下:
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+pxelif r == 1:return 12+py-4*pxelif r == 2:return 15-4*py-pxelif r == 3:return 3-py+4*px# Field
fieldwidth = 12
fieldheight = 18pField = [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 indexpi = rotate(px, py, nrotation)# print(pi)# exit(0)#get index into fieldfi = 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 Falsereturn True# Game logic stuff======================================================
gameover = False
# which piece is falling
nCurrentPiece = random.randint(0, 6)
# is it rotate
nCurrentRotation = 0
nCurrentX = fieldwidth/2
nCurrentY = 0bKey = []
clock = pygame.time.Clock()
fps = 60
wait_time = 100fall_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 = Trueelif event.type == pygame.KEYDOWN:if event.key == pygame.K_LEFT:# 用户按下了左箭头键# print("左箭头键被按下")# bKey = 1bKey.append(1)elif event.key == pygame.K_RIGHT:# 用户按下了右箭头键# print("右箭头键被按下")# bKey = 2bKey.append(2)elif event.key == pygame.K_DOWN:# 用户按下了下箭头键# print("下箭头键被按下")# bKey = 3bKey.append(3)elif event.key == pygame.K_z:# 用户按下了上箭头键# print("上箭头键被按下")# bKey = 4bKey.append(4)# Game logic ======================================================if (1 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX-1, nCurrentY):nCurrentX = nCurrentX - 1bKey.remove(1)# bKey=0if (2 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX+1, nCurrentY):nCurrentX = nCurrentX + 1bKey.remove(2)# bKey=0if (3 in bKey) and doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY+1):nCurrentY = nCurrentY + 1bKey.remove(3)# bKey=0if (4 in bKey) and doesPieceFit(nCurrentPiece, (nCurrentRotation+1)%4, nCurrentX, nCurrentY):nCurrentRotation += 1nCurrentRotation %= 4bKey.remove(4)# bKey=0if current_time - last_fall_time >= fall_time:# 执行方块的下降操作if doesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY + 1):nCurrentY += 1last_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+py0.2:fall_time -= 0.01font = 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链接:
https://github.com/NanGongXun/Python_Tetris.git
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
