在我的游戏中错误的顺序

时间:2018-04-20 18:22:39

标签: python tkinter

我在tkinter做了一个小项目。这是一个游戏,它接收一个玩家列表,并以一种饥饿游戏的方式逐个将玩家从列表中删除。问题在于我为游戏设置的标签在那些无法生存的人面前展示了胜利者。我希望它能够展示那些先没有生存,然后是胜利者的人。

from tkinter import *
from tkinter import simpledialog
import random

class Survive(Frame):
    def __init__(self, master):
        self.master = master
        self.master.title("Survival")
        self.master.geometry("500x500+250+100")
        self.master.config(bg = "#000000")
        self.master.resizable(0,0)
        self.create_widgets()
        self.create_game_tools()
        self.user_label.after(1000, lambda: self.ask_names_of_players())

    def create_random_scenarios(self):
        random_scenario_list = ["Jungle Fire", "Deserted Island", "Kidnapped on a Plane", "Playground Battlegrounds"]
        #A list of random scenarios.
        self.scenario = random_scenario_list[random.randint(0, len(random_scenario_list) - 1)] #Creates our scenario.
        if self.scenario == "Jungle Fire":
            self.list_of_murders = ["was burned to a crisp", "was crushed by a falling tree",
                "accidentally discovered a bear trap", "died from asphyxiation", "being eaten by a boar",
                "ran into a sharp branch eye first", "fell into a World War II jungle trap", "got lost in the jungle"]
        elif self.scenario == "Deserted Island":
            self.list_of_murders = ["was killed by dehydration", "had hallucinated and strangled their self",
                "was murdered by a falling coconut", "had received a really bad sun burn"]
        elif self.scenario == "Kidnapped on a Plane":
            self.list_of_murders = ["got squashed after hitting the ground when jumping from the plane",
                "was chopped into pieces inside of the jet", "promptly was shot by a kidnapper",
                "had been destroyed by jet lag"]
        else:
            self.list_of_murders = ["got shot by someone across the yard", "was stabbed by a nearby infant",
                "was bit by a rogue toddler", "has been annihilated by the sonic scream of a baby's cry"]
        #Creates a list of murders.

    def create_game_tools(self):
        self.useful_input = "" #Will be changed to whatever the user's input is.
        self.did_user_input = False #Will be changed to true if the user just had input something.
        self.player_count = 5 #It can be anything really.
        self.player_list = [] #A list of players that will participate.
        self.create_random_scenarios()

    def create_widgets(self):
        self.top = Frame(self.master, bg = "#fff", width = 500, height = 400)
        self.top.pack(fill="none", expand=True)
        self.top.pack_propagate(0)

        self.bottom = Frame(self.master, bg = "#000000", width = 500, height = 100)
        self.bottom.pack(fill="none", expand=True)

        self.user_label = Label(self.top, text = "Survival...", fg = "#000000", bg = "#fff",
                            font=("Times",25), bd = 1, relief = FLAT)
        self.user_label.place(relx=.5, rely=.5, anchor="center")

        self.user_input = Entry(self.bottom, fg = "#fff", bg = "#000000", font=("Times", 25), bd = 1, relief = FLAT,
                   justify = "center", insertbackground = "#fff", selectbackground = "#fff", selectforeground = "#000000")
        self.user_input.bind("<Return>", self.get_user_input_from_entry)
        self.user_input.place(relx=.5, rely=.5, anchor="center")

    def get_user_input_from_entry(self, event):
        self.useful_input = str(self.user_input.get()) #We're getting the text from the user_input entry widget.
        self.did_user_input = True
        self.user_input.delete(0, 'end') #Clears the user_input entry widget.

    def ask_names_of_players(self):
        self.user_label.config(text = "What are the names of the players?") #We're going to ask the names of the players.

        for i in range(self.player_count):
            player = simpledialog.askstring("", "Player %s out %s" % (i + 1, self.player_count))
            self.player_list.append(player)
            if player is None:
                pass

        self.user_label.after(1000, lambda: self.remove_player())

    def remove_player(self):
        original_total_players = self.player_count
        for i in range(original_total_players - 1):
            player_killed = str(self.player_list[random.randint(0, len(self.player_list) - 1)])
            self.player_list.remove(player_killed)
            self.user_label.after(3000, lambda: self.user_label.config(text = player_killed + " \n" +
                                                str(self.get_murder_for_person()) + "."))
            #We're going to begin to kill off players involved until one survives.

        self.user_label.after(3000, lambda: self.winner_of_game())


    def winner_of_game(self):
        self.user_label.config(text = self.player_list[0] + " has survived the game.") #We're going to display the winner.

app = Tk()

Survive = Survive(app)
app.mainloop()

我如何得到它以便首先显示玩家的死亡然后是胜利者?

1 个答案:

答案 0 :(得分:0)

我很确定您的问题出在remove_player方法中,但这并不符合您的意图。它不是一次一个地移除玩家,而是在关于它们的消息之间有几秒钟,而是立即删除交易玩家并更新关于死亡的输出(以及关于获胜幸存者的消息)之后。

我认为基本问题是你误解了after小部件上tkinter方法的作用。它不等同于睡眠,然后调用你给它的功能!相反,它是调度回调。调用after或多或少立即返回, not 在延迟过后并且回调已经运行。

当您致电something.after(3000, foo),然后立即致电something.after(3000, bar)时,回拨给foobar的电话将不会被隔开3000毫秒。相反,它们几乎不会在时间上分开,因为每个人在安排后​​大约被调用3000毫秒。我不太了解tkinter内部,但如果它使用单独的线程来运行回调,bar甚至可能在foo之前运行(它将是一个竞争条件,所以他们的顺序可能会在不同的比赛之间变化。)

如果您希望每次将几个函数调用隔开三秒,则需要增加每次调用后传递给after的延迟。 (或者,您可以重新设计您的功能,以便您只需要预先安排一个回调,并让它调用的功能安排下一个,依此类推......但这比仅增加延迟要复杂一些。 )

尝试这样的事情:

def remove_player(self):
    original_total_players = self.player_count
    for i in range(original_total_players - 1):
        player_killed = str(self.player_list[random.randint(0, len(self.player_list) - 1)])
        self.player_list.remove(player_killed)
        self.user_label.after(3000 * i, lambda player_killed=player_killed:
                              self.user_label.config(text = player_killed + " \n" +
                              str(self.get_murder_for_person()) + "."))
        #We're going to begin to kill off players involved until one survives.

    self.user_label.after(3000 * (i+1), lambda: self.winner_of_game())

主要修复方法是将3000 ms的延迟乘以循环变量i,因此每次死亡的报告都是前一个死亡后的3秒。我还需要修改回调lambda函数,因为它不会看到正确的player_killed值(为了更好地理解该问题,请参阅this question)。