2017-06-11 56 views
1

我正在爲學校製作一個拳擊程序,在那裏你必須打出敵人擊倒,但敵人也會每隔幾秒進行一次攻擊。當他要攻擊時它會顯示一個感嘆號,並且你必須快速反應才能阻止它。反應計時器錯誤

基本上我想要它做的是產生一個隨機時間後,它執行一個命令(在我的情況下是一個攻擊),當我不按快速按鈕。總之是一個反應計時器。

我用多線程可以同時運行阻塞功能和敵人攻擊功能。將來我想添加一個線程,以便您能夠進行攻擊。

這是我的反應計時器:

from random import * 
from turtle import * 
from time import * 
from threading import * 

def Reaction(): 
    vTime = 0 
    while vTime < 3: #The time in which you have to react 
     vNow = time() 
     vStep = vNow + 0.25 
     while time() < vStep: 
      vJack = True #Useless arguments to fill up the time between each step 
      vJack = False 
     vTime += 0.25 
     print(vTime) 
     if vReaction == True: #Checking if you have pressed the key 
      print("Oke") 
      break 
    print("af") 

def key(): 
    global vReaction 
    vReaction = True 

def Block(): 
    global vTimer 
    while vTimer < 5: 
     onkey(key, "space") 
     listen() 

def AttackEnemy(): 
    global vTimer 
    while vTimer < 5: 
     vHitTime = randrange(4, 12)/4 * 1000 # Generating the random time after which the enemy is going to hit 
     ontimer(Reactie, vHitTime) 
     vTimer += 1 


vTimer = 0 
vBlock = Thread(target = Block, args =()) 
vAttack = Thread(target = AttackEnemy, args =()) 

vBlock.start() 
vAttack.start() 

vBlock.join() 
vAttack.join() 

print("End") 

運行程序時,我得到這些錯誤:

Exception in thread Thread-2: 
Traceback (most recent call last): 
    File "D:\Programma's\Python\lib\threading.py", line 916, in _bootstrap_inner 
    self.run() 
    File "D:\Programma's\Python\lib\threading.py", line 864, in run 
    self._target(*self._args, **self._kwargs) 
    File "G:\test getal.py", line 35, in AanvalVijand 
    ontimer(Reactie, vSlagtijd) 
    File "<string>", line 6, in ontimer 
    File "D:\Programma's\Python\lib\turtle.py", line 3662, in Screen 
    Turtle._screen = _Screen() 
    File "D:\Programma's\Python\lib\turtle.py", line 3690, in __init__ 
    TurtleScreen.__init__(self, _Screen._canvas) 
    File "D:\Programma's\Python\lib\turtle.py", line 985, in __init__ 
    "blank" : Shape("image", self._blankimage()) 
    File "D:\Programma's\Python\lib\turtle.py", line 470, in _blankimage 
    img = TK.PhotoImage(width=1, height=1) 
    File "D:\Programma's\Python\lib\tkinter\__init__.py", line 3539, in __init__ 
    Image.__init__(self, 'photo', name, cnf, master, **kw) 
    File "D:\Programma's\Python\lib\tkinter\__init__.py", line 3495, in __init__ 
    self.tk.call(('image', 'create', imgtype, name,) + options) 
RuntimeError: main thread is not in main loop 

我是新來的這一切,剛剛碼好幾個星期的,所以我真的想知道我做錯了什麼,以及如何解決它。

PS:對於項目我不能使用擴展庫。

回答

0

我覺得你應該避免與烏龜混合穿線,如果你只能用烏龜自己的ontimer()事件逃脫。這裏是我只用ontimer()控制動作代碼的返工:

from random import randrange 
from turtle import Turtle, Screen 

vStep = 0.25 # in seconds 
FONT = ('Arial', 18, 'normal') 
ROUNDS = 3 
TIME_PER_ROUND = 5 # in seconds 
TIME_BETWEEN_ROUNDS = 2 # in seconds 

def StartAttack(): 
    global vTimer, vReaction 

    magicMarker.undo() 
    magicMarker.write("!", align='center', font=FONT) 

    vTimer = 3 # you now have 3 seconds to react 
    vReaction = False 
    Reaction() 

def Reaction(): 
    global vTimer 

    if vTimer > 0: # The time in which you have to react 

     if vReaction: # Check if you have pressed the key 
      magicMarker.undo() 
      magicMarker.write("Reacted in time!", align='center', font=FONT) 
     else: 
      vTimer -= vStep 
      screen.ontimer(Reaction, int(vStep * 1000)) # recheck in vStep seconds 
    else: 
     magicMarker.undo() 
     magicMarker.write("Didn't react in time!", align='center', font=FONT) 

def key(): 
    global vReaction 
    vReaction = True 

def Block(): 
    screen.onkey(key, 'space') 
    # disable above event handler in after round ends 
    screen.ontimer(lambda: screen.onkey(None, 'space'), int(TIME_PER_ROUND * 1000)) 

def AttackEnemy(): 
    global vTimer 

    vTimer = -1 
    # Generate random time after which the enemy is going to hit 
    vHitTime = randrange(4, 12)/4 * 1000 
    screen.ontimer(StartAttack, int(vHitTime)) 

def NextRound(): 
    global vRounds 

    if vRounds > 0: 

     magicMarker.undo() 
     magicMarker.write(" ", align='center', font=FONT) 

     Block() 

     AttackEnemy() 

     vRounds -= 1 

     screen.ontimer(NextRound, int((TIME_PER_ROUND + TIME_BETWEEN_ROUNDS) * 1000)) 
    else: 
     magicMarker.undo() 
     magicMarker.write("Match Over!", align='center', font=FONT) 

screen = Screen() 
screen.listen() 

magicMarker = Turtle(visible=False) 
magicMarker.write(" ", align='center', font=FONT) 

vTimer = -1 # just to make these exist 
vReaction = None 
vRounds = ROUNDS 

NextRound() 

screen.mainloop() 

點擊彈出來激活它,因此它可以接收鍵盤事件的窗口。

我相信你遇到了這個問題的Tkinter(龜託底)與線程交互 - 如果你想要走這條路線,你可以檢查出Tkinter and Threads

+0

的screen.listen()函數不停止程序,直到你按下一個鍵? – Rek3beef21

+0

@ Rek3beef21,no。它只是使窗口能夠接收默認情況下未啓用的關鍵事件。根據文檔,「專注於TurtleScreen(爲了收集關鍵事件)」。如果有的話,你只能在程序中調用一次。 – cdlane

+0

我差點忘了謝謝你的建議和更正。非常感謝!! – Rek3beef21