<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          500 行代碼寫一個俄羅斯方塊游戲

          共 19551字,需瀏覽 40分鐘

           ·

          2020-07-27 19:46


          導(dǎo)讀:本文我們要制作一個俄羅斯方塊游戲。




          01 俄羅斯方塊 Tetris


          俄羅斯方塊游戲是世界上最流行的游戲之一。是由一名叫Alexey Pajitnov的俄羅斯程序員在1985年制作的,從那時起,這個游戲就風(fēng)靡了各個游戲平臺。


          俄羅斯方塊歸類為下落塊迷宮游戲。游戲有7個基本形狀:S、Z、T、L、反向L、直線、方塊,每個形狀都由4個方塊組成,方塊最終都會落到屏幕底部。所以玩家通過控制形狀的左右位置和旋轉(zhuǎn),讓每個形狀都以合適的位置落下,如果有一行全部被方塊填充,這行就會消失,并且得分。游戲結(jié)束的條件是有形狀接觸到了屏幕頂部。


          方塊展示:



          PyQt5是專門為創(chuàng)建圖形界面產(chǎn)生的,里面一些專門為制作游戲而開發(fā)的組件,所以PyQt5是能制作小游戲的。


          制作電腦游戲也是提高自己編程能力的一種很好的方式。



          02 開發(fā)


          沒有圖片,所以就自己用繪畫畫出來幾個圖形。每個游戲里都有數(shù)學(xué)模型的,這個也是。


          開工之前:


          • QtCore.QBasicTimer()QtCore.QBasicTimer()創(chuàng)建一個游戲循環(huán)

          • 模型是一直下落的

          • 模型的運動是以小塊為基礎(chǔ)單位的,不是按像素

          • 從數(shù)學(xué)意義上來說,模型就是就是一串數(shù)字而已


          代碼由四個類組成:Tetris, Board, Tetrominoe和Shape。Tetris類創(chuàng)建游戲,Board是游戲主要邏輯。Tetrominoe包含了所有的磚塊,Shape是所有磚塊的代碼。


            1#!/usr/bin/python3
          2#?-*-?coding:?utf-8?-*-
          3
          4"""
          5ZetCode?PyQt5?tutorial
          6This?is?a?Tetris?game?clone.
          7
          8Author:?Jan?Bodnar
          9Website:?zetcode.com
          10Last?edited:?August?2017
          11"""

          12
          13from?PyQt5.QtWidgets?import?QMainWindow,?QFrame,?QDesktopWidget,?QApplication
          14from?PyQt5.QtCore?import?Qt,?QBasicTimer,?pyqtSignal
          15from?PyQt5.QtGui?import?QPainter,?QColor
          16import?sys,?random
          17
          18class?Tetris(QMainWindow):
          19
          20???def?__init__(self):
          21???????super().__init__()
          22
          23???????self.initUI()
          24
          25
          26???def?initUI(self):
          27???????'''initiates?application?UI'''
          28
          29???????self.tboard?=?Board(self)
          30???????self.setCentralWidget(self.tboard)
          31
          32???????self.statusbar?=?self.statusBar()
          33???????self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage)
          34
          35???????self.tboard.start()
          36
          37???????self.resize(180,?380)
          38???????self.center()
          39???????self.setWindowTitle('Tetris')
          40???????self.show()
          41
          42
          43???def?center(self):
          44???????'''centers?the?window?on?the?screen'''
          45
          46???????screen?=?QDesktopWidget().screenGeometry()
          47???????size?=?self.geometry()
          48???????self.move((screen.width()-size.width())/2,
          49???????????(screen.height()-size.height())/2)
          50
          51
          52class?Board(QFrame):
          53
          54???msg2Statusbar?=?pyqtSignal(str)
          55
          56???BoardWidth?=?10
          57???BoardHeight?=?22
          58???Speed?=?300
          59
          60???def?__init__(self,?parent):
          61???????super().__init__(parent)
          62
          63???????self.initBoard()
          64
          65
          66???def?initBoard(self):
          67???????'''initiates?board'''
          68
          69???????self.timer?=?QBasicTimer()
          70???????self.isWaitingAfterLine?=?False
          71
          72???????self.curX?=?0
          73???????self.curY?=?0
          74???????self.numLinesRemoved?=?0
          75???????self.board?=?[]
          76
          77???????self.setFocusPolicy(Qt.StrongFocus)
          78???????self.isStarted?=?False
          79???????self.isPaused?=?False
          80???????self.clearBoard()
          81
          82
          83???def?shapeAt(self,?x,?y):
          84???????'''determines?shape?at?the?board?position'''
          85
          86???????return?self.board[(y?*?Board.BoardWidth)?+?x]
          87
          88
          89???def?setShapeAt(self,?x,?y,?shape):
          90???????'''sets?a?shape?at?the?board'''
          91
          92???????self.board[(y?*?Board.BoardWidth)?+?x]?=?shape
          93
          94
          95???def?squareWidth(self):
          96???????'''returns?the?width?of?one?square'''
          97
          98???????return?self.contentsRect().width()?//?Board.BoardWidth
          99
          100
          101???def?squareHeight(self):
          102???????'''returns?the?height?of?one?square'''
          103
          104???????return?self.contentsRect().height()?//?Board.BoardHeight
          105
          106
          107???def?start(self):
          108???????'''starts?game'''
          109
          110???????if?self.isPaused:
          111???????????return
          112
          113???????self.isStarted?=?True
          114???????self.isWaitingAfterLine?=?False
          115???????self.numLinesRemoved?=?0
          116???????self.clearBoard()
          117
          118???????self.msg2Statusbar.emit(str(self.numLinesRemoved))
          119
          120???????self.newPiece()
          121???????self.timer.start(Board.Speed,?self)
          122
          123
          124???def?pause(self):
          125???????'''pauses?game'''
          126
          127???????if?not?self.isStarted:
          128???????????return
          129
          130???????self.isPaused?=?not?self.isPaused
          131
          132???????if?self.isPaused:
          133???????????self.timer.stop()
          134???????????self.msg2Statusbar.emit("paused")
          135
          136???????else:
          137???????????self.timer.start(Board.Speed,?self)
          138???????????self.msg2Statusbar.emit(str(self.numLinesRemoved))
          139
          140???????self.update()
          141
          142
          143???def?paintEvent(self,?event):
          144???????'''paints?all?shapes?of?the?game'''
          145
          146???????painter?=?QPainter(self)
          147???????rect?=?self.contentsRect()
          148
          149???????boardTop?=?rect.bottom()?-?Board.BoardHeight?*?self.squareHeight()
          150
          151???????for?i?in?range(Board.BoardHeight):
          152???????????for?j?in?range(Board.BoardWidth):
          153???????????????shape?=?self.shapeAt(j,?Board.BoardHeight?-?i?-?1)
          154
          155???????????????if?shape?!=?Tetrominoe.NoShape:
          156???????????????????self.drawSquare(painter,
          157???????????????????????rect.left()?+?j?*?self.squareWidth(),
          158???????????????????????boardTop?+?i?*?self.squareHeight(),?shape)
          159
          160???????if?self.curPiece.shape()?!=?Tetrominoe.NoShape:
          161
          162???????????for?i?in?range(4):
          163
          164???????????????x?=?self.curX?+?self.curPiece.x(i)
          165???????????????y?=?self.curY?-?self.curPiece.y(i)
          166???????????????self.drawSquare(painter,?rect.left()?+?x?*?self.squareWidth(),
          167???????????????????boardTop?+?(Board.BoardHeight?-?y?-?1)?*?self.squareHeight(),
          168???????????????????self.curPiece.shape())
          169
          170
          171???def?keyPressEvent(self,?event):
          172???????'''processes?key?press?events'''
          173
          174???????if?not?self.isStarted?or?self.curPiece.shape()?==?Tetrominoe.NoShape:
          175???????????super(Board,?self).keyPressEvent(event)
          176???????????return
          177
          178???????key?=?event.key()
          179
          180???????if?key?==?Qt.Key_P:
          181???????????self.pause()
          182???????????return
          183
          184???????if?self.isPaused:
          185???????????return
          186
          187???????elif?key?==?Qt.Key_Left:
          188???????????self.tryMove(self.curPiece,?self.curX?-?1,?self.curY)
          189
          190???????elif?key?==?Qt.Key_Right:
          191???????????self.tryMove(self.curPiece,?self.curX?+?1,?self.curY)
          192
          193???????elif?key?==?Qt.Key_Down:
          194???????????self.tryMove(self.curPiece.rotateRight(),?self.curX,?self.curY)
          195
          196???????elif?key?==?Qt.Key_Up:
          197???????????self.tryMove(self.curPiece.rotateLeft(),?self.curX,?self.curY)
          198
          199???????elif?key?==?Qt.Key_Space:
          200???????????self.dropDown()
          201
          202???????elif?key?==?Qt.Key_D:
          203???????????self.oneLineDown()
          204
          205???????else:
          206???????????super(Board,?self).keyPressEvent(event)
          207
          208
          209???def?timerEvent(self,?event):
          210???????'''handles?timer?event'''
          211
          212???????if?event.timerId()?==?self.timer.timerId():
          213
          214???????????if?self.isWaitingAfterLine:
          215???????????????self.isWaitingAfterLine?=?False
          216???????????????self.newPiece()
          217???????????else:
          218???????????????self.oneLineDown()
          219
          220???????else:
          221???????????super(Board,?self).timerEvent(event)
          222
          223
          224???def?clearBoard(self):
          225???????'''clears?shapes?from?the?board'''
          226
          227???????for?i?in?range(Board.BoardHeight?*?Board.BoardWidth):
          228???????????self.board.append(Tetrominoe.NoShape)
          229
          230
          231???def?dropDown(self):
          232???????'''drops?down?a?shape'''
          233
          234???????newY?=?self.curY
          235
          236???????while?newY?>?0:
          237
          238???????????if?not?self.tryMove(self.curPiece,?self.curX,?newY?-?1):
          239???????????????break
          240
          241???????????newY?-=?1
          242
          243???????self.pieceDropped()
          244
          245
          246???def?oneLineDown(self):
          247???????'''goes?one?line?down?with?a?shape'''
          248
          249???????if?not?self.tryMove(self.curPiece,?self.curX,?self.curY?-?1):
          250???????????self.pieceDropped()
          251
          252
          253???def?pieceDropped(self):
          254???????'''after?dropping?shape,?remove?full?lines?and?create?new?shape'''
          255
          256???????for?i?in?range(4):
          257
          258???????????x?=?self.curX?+?self.curPiece.x(i)
          259???????????y?=?self.curY?-?self.curPiece.y(i)
          260???????????self.setShapeAt(x,?y,?self.curPiece.shape())
          261
          262???????self.removeFullLines()
          263
          264???????if?not?self.isWaitingAfterLine:
          265???????????self.newPiece()
          266
          267
          268???def?removeFullLines(self):
          269???????'''removes?all?full?lines?from?the?board'''
          270
          271???????numFullLines?=?0
          272???????rowsToRemove?=?[]
          273
          274???????for?i?in?range(Board.BoardHeight):
          275
          276???????????n?=?0
          277???????????for?j?in?range(Board.BoardWidth):
          278???????????????if?not?self.shapeAt(j,?i)?==?Tetrominoe.NoShape:
          279???????????????????n?=?n?+?1
          280
          281???????????if?n?==?10:
          282???????????????rowsToRemove.append(i)
          283
          284???????rowsToRemove.reverse()
          285
          286
          287???????for?m?in?rowsToRemove:
          288
          289???????????for?k?in?range(m,?Board.BoardHeight):
          290???????????????for?l?in?range(Board.BoardWidth):
          291???????????????????????self.setShapeAt(l,?k,?self.shapeAt(l,?k?+?1))
          292
          293???????numFullLines?=?numFullLines?+?len(rowsToRemove)
          294
          295???????if?numFullLines?>?0:
          296
          297???????????self.numLinesRemoved?=?self.numLinesRemoved?+?numFullLines
          298???????????self.msg2Statusbar.emit(str(self.numLinesRemoved))
          299
          300???????????self.isWaitingAfterLine?=?True
          301???????????self.curPiece.setShape(Tetrominoe.NoShape)
          302???????????self.update()
          303
          304
          305???def?newPiece(self):
          306???????'''creates?a?new?shape'''
          307
          308???????self.curPiece?=?Shape()
          309???????self.curPiece.setRandomShape()
          310???????self.curX?=?Board.BoardWidth?//?2?+?1
          311???????self.curY?=?Board.BoardHeight?-?1?+?self.curPiece.minY()
          312
          313???????if?not?self.tryMove(self.curPiece,?self.curX,?self.curY):
          314
          315???????????self.curPiece.setShape(Tetrominoe.NoShape)
          316???????????self.timer.stop()
          317???????????self.isStarted?=?False
          318???????????self.msg2Statusbar.emit("Game?over")
          319
          320
          321
          322???def?tryMove(self,?newPiece,?newX,?newY):
          323???????'''tries?to?move?a?shape'''
          324
          325???????for?i?in?range(4):
          326
          327???????????x?=?newX?+?newPiece.x(i)
          328???????????y?=?newY?-?newPiece.y(i)
          329
          330???????????if?x?0?or?x?>=?Board.BoardWidth?or?y?0?or?y?>=?Board.BoardHeight:
          331???????????????return?False
          332
          333???????????if?self.shapeAt(x,?y)?!=?Tetrominoe.NoShape:
          334???????????????return?False
          335
          336???????self.curPiece?=?newPiece
          337???????self.curX?=?newX
          338???????self.curY?=?newY
          339???????self.update()
          340
          341???????return?True
          342
          343
          344???def?drawSquare(self,?painter,?x,?y,?shape):
          345???????'''draws?a?square?of?a?shape'''
          346
          347???????colorTable?=?[0x000000,?0xCC6666,?0x66CC66,?0x6666CC,
          348?????????????????????0xCCCC66,?0xCC66CC,?0x66CCCC,?0xDAAA00]
          349
          350???????color?=?QColor(colorTable[shape])
          351???????painter.fillRect(x?+?1,?y?+?1,?self.squareWidth()?-?2,
          352???????????self.squareHeight()?-?2,?color)
          353
          354???????painter.setPen(color.lighter())
          355???????painter.drawLine(x,?y?+?self.squareHeight()?-?1,?x,?y)
          356???????painter.drawLine(x,?y,?x?+?self.squareWidth()?-?1,?y)
          357
          358???????painter.setPen(color.darker())
          359???????painter.drawLine(x?+?1,?y?+?self.squareHeight()?-?1,
          360???????????x?+?self.squareWidth()?-?1,?y?+?self.squareHeight()?-?1)
          361???????painter.drawLine(x?+?self.squareWidth()?-?1,
          362???????????y?+?self.squareHeight()?-?1,?x?+?self.squareWidth()?-?1,?y?+?1)
          363
          364
          365class?Tetrominoe(object):
          366
          367???NoShape?=?0
          368???ZShape?=?1
          369???SShape?=?2
          370???LineShape?=?3
          371???TShape?=?4
          372???SquareShape?=?5
          373???LShape?=?6
          374???MirroredLShape?=?7
          375
          376
          377class?Shape(object):
          378
          379???coordsTable?=?(
          380???????((0,?0),?????(0,?0),?????(0,?0),?????(0,?0)),
          381???????((0,?-1),????(0,?0),?????(-1,?0),????(-1,?1)),
          382???????((0,?-1),????(0,?0),?????(1,?0),?????(1,?1)),
          383???????((0,?-1),????(0,?0),?????(0,?1),?????(0,?2)),
          384???????((-1,?0),????(0,?0),?????(1,?0),?????(0,?1)),
          385???????((0,?0),?????(1,?0),?????(0,?1),?????(1,?1)),
          386???????((-1,?-1),???(0,?-1),????(0,?0),?????(0,?1)),
          387???????((1,?-1),????(0,?-1),????(0,?0),?????(0,?1))
          388???)
          389
          390???def?__init__(self):
          391
          392???????self.coords?=?[[0,0]?for?i?in?range(4)]
          393???????self.pieceShape?=?Tetrominoe.NoShape
          394
          395???????self.setShape(Tetrominoe.NoShape)
          396
          397
          398???def?shape(self):
          399???????'''returns?shape'''
          400
          401???????return?self.pieceShape
          402
          403
          404???def?setShape(self,?shape):
          405???????'''sets?a?shape'''
          406
          407???????table?=?Shape.coordsTable[shape]
          408
          409???????for?i?in?range(4):
          410???????????for?j?in?range(2):
          411???????????????self.coords[i][j]?=?table[i][j]
          412
          413???????self.pieceShape?=?shape
          414
          415
          416???def?setRandomShape(self):
          417???????'''chooses?a?random?shape'''
          418
          419???????self.setShape(random.randint(1,?7))
          420
          421
          422???def?x(self,?index):
          423???????'''returns?x?coordinate'''
          424
          425???????return?self.coords[index][0]
          426
          427
          428???def?y(self,?index):
          429???????'''returns?y?coordinate'''
          430
          431???????return?self.coords[index][1]
          432
          433
          434???def?setX(self,?index,?x):
          435???????'''sets?x?coordinate'''
          436
          437???????self.coords[index][0]?=?x
          438
          439
          440???def?setY(self,?index,?y):
          441???????'''sets?y?coordinate'''
          442
          443???????self.coords[index][1]?=?y
          444
          445
          446???def?minX(self):
          447???????'''returns?min?x?value'''
          448
          449???????m?=?self.coords[0][0]
          450???????for?i?in?range(4):
          451???????????m?=?min(m,?self.coords[i][0])
          452
          453???????return?m
          454
          455
          456???def?maxX(self):
          457???????'''returns?max?x?value'''
          458
          459???????m?=?self.coords[0][0]
          460???????for?i?in?range(4):
          461???????????m?=?max(m,?self.coords[i][0])
          462
          463???????return?m
          464
          465
          466???def?minY(self):
          467???????'''returns?min?y?value'''
          468
          469???????m?=?self.coords[0][1]
          470???????for?i?in?range(4):
          471???????????m?=?min(m,?self.coords[i][1])
          472
          473???????return?m
          474
          475
          476???def?maxY(self):
          477???????'''returns?max?y?value'''
          478
          479???????m?=?self.coords[0][1]
          480???????for?i?in?range(4):
          481???????????m?=?max(m,?self.coords[i][1])
          482
          483???????return?m
          484
          485
          486???def?rotateLeft(self):
          487???????'''rotates?shape?to?the?left'''
          488
          489???????if?self.pieceShape?==?Tetrominoe.SquareShape:
          490???????????return?self
          491
          492???????result?=?Shape()
          493???????result.pieceShape?=?self.pieceShape
          494
          495???????for?i?in?range(4):
          496
          497???????????result.setX(i,?self.y(i))
          498???????????result.setY(i,?-self.x(i))
          499
          500???????return?result
          501
          502
          503???def?rotateRight(self):
          504???????'''rotates?shape?to?the?right'''
          505
          506???????if?self.pieceShape?==?Tetrominoe.SquareShape:
          507???????????return?self
          508
          509???????result?=?Shape()
          510???????result.pieceShape?=?self.pieceShape
          511
          512???????for?i?in?range(4):
          513
          514???????????result.setX(i,?-self.y(i))
          515???????????result.setY(i,?self.x(i))
          516
          517???????return?result
          518
          519
          520if?__name__?==?'__main__':
          521
          522???app?=?QApplication([])
          523???tetris?=?Tetris()
          524???sys.exit(app.exec_())

          (代碼可以左右滑動)

          游戲很簡單,所以也就很好理解。程序加載之后游戲也就直接開始了,可以用P鍵暫停游戲,空格鍵讓方塊直接落到最下面。游戲的速度是固定的,并沒有實現(xiàn)加速的功能。分數(shù)就是游戲中消除的行數(shù)。


          self.tboard?=?Board(self)
          self.setCentralWidget(self.tboard)


          創(chuàng)建了一個Board類的實例,并設(shè)置為應(yīng)用的中心組件。


          self.statusbar?=?self.statusBar()
          self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage)


          創(chuàng)建一個statusbar來顯示三種信息:消除的行數(shù),游戲暫停狀態(tài)或者游戲結(jié)束狀態(tài)。msg2Statusbar是一個自定義的信號,用在(和)Board類(交互),showMessage()方法是一個內(nèi)建的,用來在statusbar上顯示信息的方法。


          self.tboard.start()


          初始化游戲:


          class?Board(QFrame):

          ???msg2Statusbar?=?pyqtSignal(str)
          ...???


          創(chuàng)建了一個自定義信號msg2Statusbar,當我們想往statusbar里顯示信息的時候,發(fā)出這個信號就行了。


          BoardWidth?=?10
          BoardHeight?=?22
          Speed?=?300


          這些是Board類的變量。BoardWidthBoardHeight分別是board的寬度和高度。Speed是游戲的速度,每300ms出現(xiàn)一個新的方塊。


          ...
          self.curX?=?0
          self.curY?=?0
          self.numLinesRemoved?=?0
          self.board?=?[]
          ...


          initBoard()里初始化了一些重要的變量。self.board定義了方塊的形狀和位置,取值范圍是0-7。


          def?shapeAt(self,?x,?y):
          ???return?self.board[(y?*?Board.BoardWidth)?+?x]


          shapeAt()決定了board里方塊的的種類。


          def?squareWidth(self):
          ???return?self.contentsRect().width()?//?Board.BoardWidth


          board的大小可以動態(tài)的改變。所以方格的大小也應(yīng)該隨之變化。squareWidth()計算并返回每個塊應(yīng)該占用多少像素--也即Board.BoardWidth。


          def?pause(self):
          ???'''pauses?game'''

          ???if?not?self.isStarted:
          ???????return

          ???self.isPaused?=?not?self.isPaused

          ???if?self.isPaused:
          ???????self.timer.stop()
          ???????self.msg2Statusbar.emit("paused")

          ???else:
          ???????self.timer.start(Board.Speed,?self)
          ???????self.msg2Statusbar.emit(str(self.numLinesRemoved))

          ???self.update()


          pause()方法用來暫停游戲,停止計時并在statusbar上顯示一條信息。


          def?paintEvent(self,?event):

          ???'''paints?all?shapes?of?the?game'''

          ???painter?=?QPainter(self)
          ???rect?=?self.contentsRect()
          ...


          渲染是在paintEvent()方法里發(fā)生的QPainter負責(zé)PyQt5里所有低級繪畫操作。


          for?i?in?range(Board.BoardHeight):
          ???for?j?in?range(Board.BoardWidth):
          ???????shape?=?self.shapeAt(j,?Board.BoardHeight?-?i?-?1)

          ???????if?shape?!=?Tetrominoe.NoShape:
          ???????????self.drawSquare(painter,
          ???????????????rect.left()?+?j?*?self.squareWidth(),
          ???????????????boardTop?+?i?*?self.squareHeight(),?shape)


          渲染游戲分為兩步。第一步是先畫出所有已經(jīng)落在最下面的的圖,這些保存在self.board里??梢允褂?/span>shapeAt()查看這個這個變量。


          if?self.curPiece.shape()?!=?Tetrominoe.NoShape:

          ???for?i?in?range(4):

          ???????x?=?self.curX?+?self.curPiece.x(i)
          ???????y?=?self.curY?-?self.curPiece.y(i)
          ???????self.drawSquare(painter,?rect.left()?+?x?*?self.squareWidth(),
          ???????????boardTop?+?(Board.BoardHeight?-?y?-?1)?*?self.squareHeight(),
          ???????????self.curPiece.shape())


          第二步是畫出更在下落的方塊。


          elif?key?==?Qt.Key_Right:
          ???self.tryMove(self.curPiece,?self.curX?+?1,?self.curY)


          keyPressEvent()方法獲得用戶按下的按鍵。如果按下的是右方向鍵,就嘗試把方塊向右移動,說嘗試是因為有可能到邊界不能移動了。


          elif?key?==?Qt.Key_Up:
          ???self.tryMove(self.curPiece.rotateLeft(),?self.curX,?self.curY)


          上方向鍵是把方塊向左旋轉(zhuǎn)一下


          elif?key?==?Qt.Key_Space:
          ???self.dropDown()


          空格鍵會直接把方塊放到底部


          elif?key?==?Qt.Key_D:
          ???self.oneLineDown()


          D鍵是加速一次下落速度。


          def?tryMove(self,?newPiece,?newX,?newY):

          ???for?i?in?range(4):

          ???????x?=?newX?+?newPiece.x(i)
          ???????y?=?newY?-?newPiece.y(i)

          ???????if?x?0?or?x?>=?Board.BoardWidth?or?y?0?or?y?>=?Board.BoardHeight:
          ???????????return?False

          ???????if?self.shapeAt(x,?y)?!=?Tetrominoe.NoShape:
          ???????????return?False

          ???self.curPiece?=?newPiece
          ???self.curX?=?newX
          ???self.curY?=?newY
          ???self.update()
          ???return?True


          tryMove()是嘗試移動方塊的方法。如果方塊已經(jīng)到達board的邊緣或者遇到了其他方塊,就返回False。否則就把方塊下落到想要


          def?timerEvent(self,?event):

          ???if?event.timerId()?==?self.timer.timerId():

          ???????if?self.isWaitingAfterLine:
          ???????????self.isWaitingAfterLine?=?False
          ???????????self.newPiece()
          ???????else:
          ???????????self.oneLineDown()

          ???else:
          ???????super(Board,?self).timerEvent(event)


          在計時器事件里,要么是等一個方塊下落完之后創(chuàng)建一個新的方塊,要么是讓一個方塊直接落到底(move a falling piece one line down)。


          def?clearBoard(self):

          ???for?i?in?range(Board.BoardHeight?*?Board.BoardWidth):
          ???????self.board.append(Tetrominoe.NoShape)


          clearBoard()方法通過Tetrominoe.NoShape清空broad。


          def?removeFullLines(self):

          ???numFullLines?=?0
          ???rowsToRemove?=?[]

          ???for?i?in?range(Board.BoardHeight):

          ???????n?=?0
          ???????for?j?in?range(Board.BoardWidth):
          ???????????if?not?self.shapeAt(j,?i)?==?Tetrominoe.NoShape:
          ???????????????n?=?n?+?1

          ???????if?n?==?10:
          ???????????rowsToRemove.append(i)

          ???rowsToRemove.reverse()


          ???for?m?in?rowsToRemove:

          ???????for?k?in?range(m,?Board.BoardHeight):
          ???????????for?l?in?range(Board.BoardWidth):
          ???????????????????self.setShapeAt(l,?k,?self.shapeAt(l,?k?+?1))

          ???numFullLines?=?numFullLines?+?len(rowsToRemove)
          ...


          如果方塊碰到了底部,就調(diào)用removeFullLines()方法,找到所有能消除的行消除它們。消除的具體動作就是把符合條件的行消除掉之后,再把它上面的行下降一行。注意移除滿行的動作是倒著來的,因為我們是按照重力來表現(xiàn)游戲的,如果不這樣就有可能出現(xiàn)有些方塊浮在空中的現(xiàn)象。


          def?newPiece(self):

          ???self.curPiece?=?Shape()
          ???self.curPiece.setRandomShape()
          ???self.curX?=?Board.BoardWidth?//?2?+?1
          ???self.curY?=?Board.BoardHeight?-?1?+?self.curPiece.minY()

          ???if?not?self.tryMove(self.curPiece,?self.curX,?self.curY):

          ???????self.curPiece.setShape(Tetrominoe.NoShape)
          ???????self.timer.stop()
          ???????self.isStarted?=?False
          ???????self.msg2Statusbar.emit("Game?over")


          newPiece()方法是用來創(chuàng)建形狀隨機的方塊。如果隨機的方塊不能正確的出現(xiàn)在預(yù)設(shè)的位置,游戲結(jié)束。


          class?Tetrominoe(object):

          ???NoShape?=?0
          ???ZShape?=?1
          ???SShape?=?2
          ???LineShape?=?3
          ???TShape?=?4
          ???SquareShape?=?5
          ???LShape?=?6
          ???MirroredLShape?=?7


          Tetrominoe類保存了所有方塊的形狀。我們還定義了一個NoShape的空形狀。


          Shape類保存類方塊內(nèi)部的信息。


          class?Shape(object):

          ???coordsTable?=?(
          ???????((0,?0),?????(0,?0),?????(0,?0),?????(0,?0)),
          ???????((0,?-1),????(0,?0),?????(-1,?0),????(-1,?1)),
          ???????...
          ???)
          ...????


          coordsTable元組保存了所有的方塊形狀的組成。是一個構(gòu)成方塊的坐標模版。


          self.coords?=?[[0,0]?for?i?in?range(4)]??


          上面創(chuàng)建了一個新的空坐標數(shù)組,這個數(shù)組將用來保存方塊的坐標。


          坐標系示意圖:



          上面的圖片可以幫助我們更好的理解坐標值的意義。比如元組(0, -1), (0, 0), (-1, 0), (-1, -1)代表了一個Z形狀的方塊。這個圖表就描繪了這個形狀。


          def?rotateLeft(self):

          ???if?self.pieceShape?==?Tetrominoe.SquareShape:
          ???????return?self

          ???result?=?Shape()
          ???result.pieceShape?=?self.pieceShape

          ???for?i?in?range(4):

          ???????result.setX(i,?self.y(i))
          ???????result.setY(i,?-self.x(i))

          ???return?result


          rotateLeft()方法向右旋轉(zhuǎn)一個方塊。正方形的方塊就沒必要旋轉(zhuǎn),就直接返回了。其他的是返回一個新的,能表示這個形狀旋轉(zhuǎn)了的坐標。


          程序展示:


          作者:派森學(xué)python
          來源:
          https://segmentfault.com/a/1190000017845103

          ---

          推薦閱讀:

          完全整理 | 365篇高質(zhì)技術(shù)文章目錄整理

          算法之美 : 棧和隊列

          主宰這個世界的10大算法

          徹底理解cookie、session、token

          淺談什么是遞歸算法

          專注服務(wù)器后臺技術(shù)棧知識總結(jié)分享

          歡迎關(guān)注交流共同進步

          碼農(nóng)有道?coding


          碼農(nóng)有道,為您提供通俗易懂的技術(shù)文章,讓技術(shù)變的更簡單

          嘿,你在看嗎

          瀏覽 14
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美成人精品一级乱黄 | 91欧美在线 | 黄色日逼免费网站 | 九哥操比网 | 欧美性爱天天射 |