反应时间游戏算数 (Python 3.10)

问题描述 投票:0回答:2

我正在制作一个反应时间游戏。描述:Tkinter GUI,随机时间后会出现一个具有随机颜色、大小、字体、位置的框。如果玩家愿意,openpyxl 可以保存游戏数据,线程用于计算所用的秒数,DateTime 可以放入游戏数据的 Excel 表中,随机选择位置、大小、字体、颜色、框中的文本。

预期的游戏是,你会在一段时间后出现一个框,你尽可能快地单击该框,它会循环 3 次,当 3 次完成时,你会得到一个统计 GUI,其中包含每次的时间3次,平均时间,保存btn,再玩btn。

错误:错误是游戏计数错误,如果你尝试游戏你会看到当统计GUI出现时一直会增加0.01,例如: 时间1:1.15 时间2:1.16 时间3:1.17

如果有人能指出错误,那就太棒了。

代码:

from tkinter import *
from tkinter import messagebox
from time import sleep
import openpyxl
import datetime
import random
import threading

def run_game():
    root = Tk()
    root.title("Reaction Time Game")
    root.iconbitmap("C:/Users/Axelr/PycharmProjects/PC01/main/Self built/Reaction Time Game/icon.ico")
    root.geometry("1400x1000")
    root.configure(bg="orange")

    workbook = openpyxl.load_workbook(filename="time_data.xlsx")
    sheet = workbook.active

    time_used_list = []
    first_run = True

    def clicked3():
        global keep_counting
        keep_counting = False
        root.destroy()

        root2 = Tk()
        root2.title("Reaction Time Game Completed")
        root2.iconbitmap("C:/Users/Axelr/PycharmProjects/PC01/main/Self built/Reaction Time Game/icon.ico")
        root2.geometry("700x570")
        root2.configure(bg="lightblue")

        def save():
            current_datetime = datetime.datetime.now()
            current_datetime = current_datetime.strftime("%Y-%m-%d | %H:%M")

            place = sheet.max_row + 1

            sheet[f"A{place}"] = round(time_used_list[0], 2)
            sheet[f"B{place}"] = round(time_used_list[1], 2)
            sheet[f"C{place}"] = round(time_used_list[2], 2)
            average = sum(time_used_list) / len(time_used_list)
            sheet[f"D{place}"] = round(average, 2)
            sheet[f"E{place}"] = current_datetime

            workbook.save(filename="time_data.xlsx")
            print("Saved time data")

        def run_another():
            root2.destroy()
            run_game()
        print("list of times:")
        for time in time_used_list:
            print(time)
        title_label = Label(root2, text="Results", font=("Arial", 20, "bold"), bg="orange")
        title_label.pack(padx=20, pady=20)
        time1_label = Label(root2, text=f"Time used 1: {round(time_used_list[0], 2)} seconds", font=("Arial", 20), bg="orange")
        time1_label.pack(padx=20, pady=20)
        time2_label = Label(root2, text=f"Time used 2: {round(time_used_list[1], 2)} seconds", font=("Arial", 20), bg="orange")
        time2_label.pack(padx=20, pady=20)
        time3_label = Label(root2, text=f"Time used 3: {round(time_used_list[2], 2)} seconds", font=("Arial", 20), bg="orange")
        time3_label.pack(padx=20, pady=20)
        average_time = sum(time_used_list) / len(time_used_list)
        average_label = Label(root2, text=f"Average Time Used: {round(average_time, 2)} seconds", font=("Arial", 20), bg="orange")
        average_label.pack(padx=20, pady=20)
        save_btn = Button(root2, text="Save", font=("Arial", 20), command=save, bg="orange")
        save_btn.pack(padx=20, pady=20)
        play_btn = Button(root2, text="Play Again", font=("Arial", 20), bg="orange", command=run_another)
        play_btn.pack(padx=20, pady=20)

        root2.mainloop()

    def clicked():
        global keep_counting, times_clicked, first_run
        keep_counting = False
        if times_clicked == 2:
            clicked3()
        else:
            times_clicked += 1
            btn.destroy()
            print(first_run)
            print(times_clicked)
            first_run = False
            start(first_run)


    def time_thread():
        global time_used
        time_used = 0.00
        while keep_counting:
            sleep(0.01)
            time_used += 0.01
        time_used_list.append(time_used)



    def start(first):
        global keep_counting, times_clicked, first_run
        if first:
            times_clicked = 0
            first_run = False

        color_list = ["red", "green", "yellow", "cyan", "white", "blue", "magenta"]
        random_color = random.choice(color_list)

        random_x = random.randint(100, 600)
        print(f"random_x = {random_x}")
        random_y = random.randint(100, 600)
        print(f"random_y = {random_y}")

        random_width = random.randint(5, 15)
        random_height = random.randint(5, 20)
        print(f"random_width = {random_width}, random_height = {random_height}")

        font_list = ["Helvetica", "Garamond", "Frutiger", "Bodoni", "Times", "Futura"]
        random_font = random.choice(font_list)
        random_font_size = random.randint(10, 18)
        print(f"Font = {random_font}, font_size = {random_font_size}")

        text_list = ["!", "?", "/", "+", "=", "<", ">", "%", "&", "(", ")", "-", "|", ";", ":", "[", "]", "{", "}", "^",
                     "@", "#"]
        random_text = random.choice(text_list)
        print(f"Random text = {random_text}")

        random_time = random.randint(3, 5)
        print(f"Random time = {random_time}")

        thread = threading.Thread(target=time_thread)
        keep_counting = True

        def btn_create():
            global btn
            btn = Button(root, text=random_text, font=(random_font, random_font_size), bg=random_color, width=random_width, command=clicked)
            btn.place(x=random_x, y=random_y)
            thread.start()

        time_wait = random_time * 1000
        root.after(time_wait, btn_create)

    start(first_run)

    root.mainloop()

run_game()

请帮助我。

python loops tkinter python-multithreading
2个回答
2
投票

您的

time_thread
假设0.01秒的睡眠总是需要0.01秒。这显然是错误的。睡眠仅保证您将等待至少 0.01 秒。例如,在 Windows 上,调度程序间隔约为 0.016 秒,因此您的睡眠时间永远不能少于该时间。您可以通过更改计时线程以仅拍摄之前和之后的时间来解决此问题。

    def time_thread():
        start = time.time()
        while keep_counting:
            time.sleep(0.01)
        time_used_list.append(time.time()-start)

然而,即使这样也有一个巨大的缺陷。这里的问题是,由于 Python 的解释器锁,在

keep_counting
有机会运行之前,很可能将
time_thread
设置为 False,然后再次设置为 True,在这种情况下,它将继续运行。您最终会同时计算所有三个 time_threads。

你不需要那个循环。只需在显示按钮时捕获

starttime
,并在单击按钮时捕获结束时间。完全消除
keep_counting
和时间线。这根本不需要导入
threading

所以:

def run_game():
    root = Tk()
    root.title("Reaction Time Game")
    root.geometry("1400x1000")
    root.configure(bg="orange")

    starttime = 0
    time_used_list = []
    first_run = True

    def clicked3():
        root.destroy()

        root2 = Tk()
...
    def clicked():
        global times_clicked, first_run
        time_used_list.append(time.time()-starttime)
        if times_clicked == 2:
            clicked3()
...
        random_time = random.randint(3, 5)
        print(f"Random time = {random_time}")

        def btn_create():
            global btn
            btn = Button(root, text=random_text, font=(random_font, random_font_size), bg=random_color, width=random_width, command=clicked)
            btn.place(x=random_x, y=random_y)
            starttime = time.time()

        time_wait = random_time * 1000
        root.after(time_wait, btn_create)

通常,不要使用线程来计算经过的时间。只需获取开始时间和结束时间并减去即可。


1
投票

在 Python 中使用 time.sleep() 函数的睡眠时间不可能少于 0.01 秒,而在 Windows 上则为 0.016 秒。

© www.soinside.com 2019 - 2024. All rights reserved.