《Python3編程實戰Tetris機器人》python
在測試過程當中,發現程序出錯,但關閉定時器,不進行自動下落就不會有問題。緣由是Timer會新開一個線程,線程和主線會產生資源衝突。linux
首先想到的是加鎖,遊戲邏輯很簡單,加鎖應該很容易解決問題。但無論我粗粒度加,仍是儘可能細粒度加,最後都會死鎖。最後進行打印,發現程序停在了tkinter.Canvas.move處,我的認爲這是tkinter的bug。
此路不通,換個思路。開一個工做線程,來完成全部的操做,主線程與定時器操做,都只是往工做線程中提交任務。也就是隻讓一個工做線程來作任務,這樣就把資源衝突的問題避開了。git
加鎖方案分析github
tickLock[0] = True with curTetrisLock: print("-------+++---00000000--- get lock", tickLock) if ke.keysym == 'Left': self.game.moveLeft() if ke.keysym == 'Right': self.game.moveRight() if ke.keysym == 'Up': self.game.rotate() if ke.keysym == 'Down': self.game.moveDown() if ke.keysym == 'space': self.game.moveDownEnd() print("-------+++---00000000--- lose lock", tickLock)
def tickoff(self): if self.gameRunningStatus == 1: if not tickLock[0]: with curTetrisLock: print("------------------ get lock", tickLock[1]) self.moveDown() print("================== lose lock", tickLock[1]) self.tick = Timer(self.gameSpeedInterval / 1000, self.tickoff) self.tick.start()
程序最後停在了Block類中的tkinter.Canvas.move處,每次都由定時器觸發,沒法釋放。
有興趣的同窗能夠到項目中,切換到lockbug分支去研究,我寫了不少打印輸出方便問題定位。編程
新增一個Queue,鍵盤響應與定時器響應往隊列中增長任務單元,工做線程逐一處理這些任務。任務單元以下設計:segmentfault
("cmd",(data))
每個任務單元都是一個二元元組(方便數據解構),第一個是字符串,爲命令;第二個是元組,是數據包(也按方便解構的方式去設計),由每一個命令自行定義。windows
def opWork(self): while True: if not opQueue.empty(): cmd,data = opQueue.get() if op == "Left": self.moveLeft() elif op == "Right": self.moveRight() elif op == "Up": self.rotate() elif op == "Down": self.moveDown() elif op == "space": self.moveDownEnd() elif op == "quit": break else: time.sleep(0.01)
def processKeyboardEvent(self, ke): if self.game.getGameRunningStatus() == 1: if ke.keysym == 'Left': opQueue.put(('Left',())) if ke.keysym == 'Right': opQueue.put(('Right',())) if ke.keysym == 'Up': opQueue.put(('Up',())) if ke.keysym == 'Down': opQueue.put(('Down',())) if ke.keysym == 'space': opQueue.put(('space',()))
遊戲控制主要函數,在方塊下落到底部後,進行消層、統計得分、速度等級斷定、遊戲是否結束斷定以及將下一方塊移入遊戲空間並再生成一個方塊顯示在下一方塊顯示空間中。函數
def tickoff(self): if self.gameRunningStatus == 1: opQueue.put(('Down'),()) self.tick = Timer(self.gameSpeedInterval / 1000, self.tickoff) self.tick.start()
https://gitee.com/zhoutk/ptetris 或 https://github.com/zhoutk/ptetris
1. install python3, git 2. git clone https://gitee.com/zhoutk/ptetris (or download and unzip source code) 3. cd ptetris 4. python3 tetris This project surpport windows, linux, macOs on linux, you must install tkinter first, use this command: sudo apt install python3-tk
已經實現了C++版,項目地址:測試
https://gitee.com/zhoutk/qtetris