少儿编程分享:码趣君教你用Python编写俄罗斯方块(五) ...

[复制链接]
kgd520 发表于 2018-3-19 08:27:01 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
! u; P% Z: N1 o) K
比起操作而言
0 G0 H" b& j: L5 d4 X设定好游戏的边界及设定更关键噢
+ a* |9 ?% j+ r4 N+ {* ] 设定底部7 |: V2 _+ `# U

. s, Z1 M; O! E% q' `( N254. # move the current block all the way down(当前方块直达底部)5 K% G/ t. E/ V: W, G+ n* b1 I
255. elif event.key == K_SPACE:% L: F8 z# V9 {5 F8 w
256. movingDown = False3 T  [- {" B& o4 @2 \& X
257. movingLeft = False
2 Q8 q% W  |2 {; Q2 B; i: k& g258. movingRight = False
* R) t! d2 D" y: {6 w( M259. for i in range(1, BOARDHEIGHT):
# `' P3 a2 [# n( O260. if not isValidPosition(board, fallingPiece, adjY=i):; @1 j2 M  y- @/ c8 R8 n
261. break1 Y/ \% p  b+ m% W8 u
262. fallingPiece['y'] += i - 1/ ]' t- V$ x7 g" v8 w) f. ^1 E
当玩家按下空格键时,正在下降的积木将直达底部。这一部分需要计算积木离底部有多少格。3 m  J* Z8 p0 D: T
256至258行将设所有移动为False(这将使之后的编程认为玩家松开了所有按下的方向键)。做这段代码是因为我们不想让玩家在按下Space键使第一块积木直达底部的同时,仍然按着的方向键影响到第二块积木的移动。& S9 a! b$ T9 _" h
为了找到积木可以下落的最大格数,我们应首先调取isValidPosition()并给adjY参数赋值整数1。如果isValidPosition()反馈False,那么积木已经到达了底部,如果isValidPosition()反馈True,那么积木可以继续向下移动一格。8 y/ ?6 l( J# B; }
在这种情况下,我们应调取isValidPosition()并给adjY参数赋值至2。如果再次反馈Ture,则赋值为3,依次类推。这就是259行 for循环的意义。调取isValidPosition()并将不断增长的整数赋值给参数adjY直到得到反馈False,这时意味着i中的值超过了底部一格,这也是为什么262 行fallingPiece增值为i - 1 而不是i
% m3 }0 _8 P5 h, c3 R% P(要注意这里行259 for语句,range()第二个参数是用来设定画板高度的,这个值是积木可以下降格数的最大值)9 ]' C1 ]- I! C5 ^; p
按方向键移动
1 U+ p4 D8 J: r7 [; w7 H  [6 x- w7 h2 Y" }  J' o& Z
264. # handle moving the block because of user input
# |' r3 o/ G6 Z0 u1 ~' z # 积木因玩家输入而移动: ^6 m, w! q& }1 _! X0 r8 Z$ i: S
265. if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:
! B$ M; N7 s5 T( ^. H8 U% _266. if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):
$ w5 k: L8 b) l5 N  a1 G267. fallingPiece['x'] -= 1
0 |( r( a  v! \+ `; G( ?268. elif movingRight and isValidPosition(board, fallingPiece, adjX=1):% c4 |3 D0 o7 G0 N' h- n$ k
269. fallingPiece['x'] += 1
( i- H' O$ q7 L: l7 B270. lastMoveSidewaysTime = time.time()) }1 L) V: c4 T' @+ e2 a
还记得227行的如果玩家按下左方向键, movingLeft变量设为True吗?(同理233行movingRight)这些移动变量在玩家放开方向键时,同样会设为False(见217行和219行)# x8 z2 q& q  n
当玩家按下向左或向右键会发生the lastMoveSidewaysTime变量会设置为当前时间(这就是time.time()的反馈值)如果玩家持续按键不放,那么movingLeft or movingRight变量会设置为True。2 y, y" {# T7 L- D2 W
如果玩家持续按键超过0.15秒(储存在MOVESIDEWAYSFREQ值是在0.15浮动的)那么表达式time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ评估为True。265行的状况是True如果玩家同时按下方向键和0.15秒过完,在这状况下我们应该将降落的积木向左或向右,即使玩家啊没有再按方向键。
' x. j: T5 k0 p, U$ G& |& `这个代码很重要,因为如果让玩家反复单点按方向键来使积木在底板上移动会使玩家很快感到疲倦。取而代之的是,玩家可以按住一个方向键使积木持续移动直到松开它。与此同时,216到221行的代码将设定移动变量为False,那么265行的判断也将会是False。这也阻止了积木移动过快。) \% `/ }  D  q* H1 w% S% o
为了演示为什么在过了MOVESIDEWAYSFREQ中的数值的秒数后 time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ返回True,运行这个简短的程序:7 Z: s) P# ]4 J4 h
import time
/ p# g$ @0 l7 e3 e* ~+ X+ mWAITTIME = 4% m0 U' _! g1 i" s7 b' N
begin = time.time()& I1 T9 ~; R4 [* A9 l+ X
while True:( \: }4 {, D" d# S% O3 i1 n) u
now = time.time()+ k1 r% I& M2 o. n  |, P
message = '%s, %s, %s' % (begin, now, (now - begin))& O2 B4 _' f7 h2 x+ K3 p
if now - begin > WAITTIME:: e" U7 K$ y# D* w
print(message + ' PASSED WAIT TIME!')
" J2 C* y- S+ H% ?9 s else:1 j7 A, K2 ^6 G+ o8 R1 W5 @
print(message + ' Not yet...')
$ P" A) M( o$ rtime.sleep(0.2)- m; ?) ]1 a% ^0 T3 T9 A
这个程序有一个无限循环,所以为了终止它,按Ctrl-C。 该程序的输出将如下所示:
  `9 `+ ?) `, u& C4 k- v1322106392.2, 1322106392.2, 0.0 Not yet...
7 {& @# f8 D- z  r3 X0 R5 {1322106392.2, 1322106392.42, 0.219000101089 Not yet...
3 @, d2 J$ X, w' D1322106392.2, 1322106392.65, 0.449000120163 Not yet...
5 ^- {6 o: E, h0 ?1322106392.2, 1322106392.88, 0.680999994278 Not yet...
, y6 Z8 k  D4 m  y% f. w1322106392.2, 1322106393.11, 0.910000085831 Not yet...
1 d' ~7 B7 D. A% w6 W' n1322106392.2, 1322106393.34, 1.1400001049 Not yet...& r; T5 H/ ~3 b' s
1322106392.2, 1322106393.57, 1.3710000515 Not yet...+ f7 t; f. e: U4 [  x
1322106392.2, 1322106393.83, 1.6360001564 Not yet...
0 ?' F2 s6 Y8 A1322106392.2, 1322106394.05, 1.85199999809 Not yet...
- g6 _; [7 R' g) n* x' H& y1322106392.2, 1322106394.28, 2.08000016212 Not yet.... u' ^+ F6 E0 _
1322106392.2, 1322106394.51, 2.30900001526 Not yet...
. D0 i1 u4 D9 k5 f2 q1322106392.2, 1322106394.74, 2.54100012779 Not yet..., o) ]" S" v# q1 D: D. P
1322106392.2, 1322106394.97, 2.76999998093 Not yet...
% E. ~7 t; r% x/ T8 }0 U' Q1322106392.2, 1322106395.2, 2.99800014496 Not yet...9 ]% I  |" [- U
1322106392.2, 1322106395.42, 3.22699999809 Not yet...5 E2 S: _; V+ T3 k  @5 P
1322106392.2, 1322106395.65, 3.45600008965 Not yet...3 _6 z2 u9 z2 P# Z# G4 S
1322106392.2, 1322106395.89, 3.69200015068 Not yet...
- W& t5 a$ u& ~0 U8 c1322106392.2, 1322106396.12, 3.92100000381 Not yet...$ D  e! z) o6 ]; \- J
1322106392.2, 1322106396.35, 4.14899992943 PASSED WAIT TIME!8 o. Q7 P9 x1 {
1322106392.2, 1322106396.58, 4.3789999485 PASSED WAIT TIME!
! |% }4 `0 u) L2 g- k. D4 a+ O( n+ X1322106392.2, 1322106396.81, 4.60700011253 PASSED WAIT TIME!
) W# h: z" z# r# L" n2 h9 X1322106392.2, 1322106397.04, 4.83700013161 PASSED WAIT TIME!
2 z6 J1 i# x& V+ ~1322106392.2, 1322106397.26, 5.06500005722 PASSED WAIT TIME!
( O; f$ C- w! c/ E- o. @Traceback (most recent call last):
) d- J  k5 x2 e+ `6 E File "C:\timetest.py", line 13, in
3 n/ h5 F" e8 o; R time.sleep(0.2): f7 D1 t, ?2 Y+ M8 q
KeyboardInterrupt8 S! l3 ~& [$ f5 L$ D0 k8 v
每行的输出的第一个数值是程序第一次运行时,time.time()的返回值(并且这个数值永不改变)。第二个数值是time.time()最新的返回值(这个数值将着每次循环不断更新)。而第三个数值是两个数值的差值,这个数值是从begin=time.time()运行后的具体时间。+ y0 J. y; N7 ]: F4 h% x
如果这个数值大于4,代码将显示“PASSED WAIT TIME!”而不是“Not yet”。这是程序用来计算当一段代码开始运行后的耗时。在四格拼图程序中,time.time() – lastMoveSidewaysTime表达式将计算从开始运行到lastMoveSidewaysTime最后一次运行的时间。
; y; b# {0 q% c* A$ x- A别忘记把当前时间更新到lastMoveSidewaysTime!我们在270行就是这么做的。8 L: L0 E; K) C+ A' x. a( Z
272. if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1):" Q0 V! e7 s3 }
273. fallingPiece['y'] += 1
/ u* m' R8 j2 m2 g8 G  I* m274. lastMoveDownTime = time.time()5 U# v/ X; l  D+ g8 F' n' ?, D
272到274行除了将落下的积木向下移动之外,几乎与265〜270行完全相同。 它有一个单独的移动变量(moveDown)和“last time”变量(lastMoveDownTime)以及一个不同的“移动频率”变量(MOVEDOWNFREQ)。
! r% s  w5 L" U' F+ {! y0 @积木自然下落4 A9 ~4 }0 D( S2 F7 m  A- E

/ d; Q# O( n( `: D' `7 A4 P; l. v276. # let the piece fall if it is time to fall2 h% a$ E7 d; [7 R5 z8 [0 Y0 o
277. if time.time() - lastFallTime > fallFreq:
: K; a3 y7 S1 f0 G! r7 p+ W  z278. # see if the piece has landed
; L! k7 p6 a8 b0 s# P; @279. if not isValidPosition(board, fallingPiece, adjY=1):( D1 L7 I7 W- s
280. # falling piece has landed, set it on the board
1 D1 r& ?+ t3 c; M; Y0 p281. addToBoard(board, fallingPiece)2 i+ Y. P' i, C3 z
282. score += removeCompleteLines(board)
' o, N: R+ O$ O283. level, fallFreq = calculateLevelAndFallFreq(score)
4 l0 @: U& `; {284. fallingPiece = None
% X( a5 r- X1 l9 D$ l" v# k  w; l3 y0 Y285. else:
8 s- j: b3 j( U' Z$ J286. # piece did not land, just move the block down
; O! P4 N+ i& [; ~: u2 I4 b287. fallingPiece['y'] += 1
/ t1 e- ?( a3 S1 o3 S288. lastFallTime = time.time()
- z2 i/ M: j: n/ ]+ x积木自然下降的速度由变量lastFallTime追踪。当积木下降一格后过了足够长的时间,279行至288行将会使积木继续下降一格。
5 J& W3 g5 b* r* s4 J. P) r2 w如果279行的判断为True,那么积木已经落地了。AddToBoard()函数的调取将使积木变为底板的数据结构(所以之后的积木可以在其上方落地),而removeCompleteLines() 的调取将处理消除底板上完整的行并使上方方块下降。removeCompleteLines() 函数也将返回一个整数值表达多少行被移除然后将此值添加至分数。
4 q1 T; G8 R# X5 }" Z# n- D因为分数可能改变,我们将调取 calculateLevelAndFallFreq() 函数来更新当前的关卡数和方块下落的次数。并最终设置fallingpiece变量至None来指示下一个下落积木并且是一个随机的积木。(这一步在195行至199行最开始的循环完成)" F" W; ]. [6 t: q) E( G7 A
如果积木还未落地,我们就简单地将它的Y轴下降一格(287行)并且重启 lastFallTime至当前时间(288行)
2 u. V. g$ m4 z(未完待续)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题
推荐阅读更多+
阅读排行更多+
用心服务创业者
0851-88611148
周一至周五 9:00-18:00
意见反馈:admin@0851life.com

扫一扫关注我们

Powered by 童码少儿编程 X3.4© 2001-2013 0851life Inc.|网站地图