pythontkinter

How to stop this game for seconds and start from where it was stopped?


from tkinter import *
from tkinter import messagebox
import random


win = Tk()
win.title('Color game')
win.geometry('500x500')
win.config(bg = "#C1AB8C")
win.resizable(0,0)

#================================function=====================================

colors = ['Yellow' , 'Blue' , 'Green' , 'Black' , 'Red' , 'Orange' , 'White' , 'Purple' , 'Brown']
score = 0


timeleft = 45


def startgame(event):
    if timeleft == 45 :
        countdown()
    nextcolor()


def nextcolor():
    global score
    global timeleft
    if timeleft > 0 :
        ent.focus_set()
        if ent.get().strip():
            if ent.get().lower() == colors[1].lower():
                lbl_feedback.config(text = 'CORRECT!' , fg = '#075B21')
                score += 1
            else:
                lbl_feedback.config(text = 'WRONG!' , fg = '#AE1717')
        else:
            lbl_feedback.config(text= '')
        ent.delete(0 , END)
        random.shuffle(colors)
        lbl_color.config(fg = str(colors[1]) , text = str(colors[0]))
        lbl_score.config(text = 'Score :' + str(score) , font = ('comic sans ms' , 16 , 'bold') )


def countdown():
    global timeleft
    if timeleft > 0 :
        timeleft -= 1
        lbl_time.config(text='Time :' + str(timeleft) , font = ('comic sans ms' , 16 , 'bold'))
        lbl_time.after(1000 , countdown)
    
        if timeleft == 0 :
            messagebox.showinfo('End' , 'Times up!')


    if timeleft <= 10 and timeleft > 0 :
        lbl_hurry_up.config(text ='Hurry up ,you are\n runing out of time!!!\U0001f630' )


def escape(event):
    global timeleft
    result = messagebox.askquestion('Quit' , 'Are you sure to quit?')
    if result == 'yes':
        win.destroy()
        
#================================label========================================

lbl_question = Label(win , text = 'Enter the color of each word.' , font = ('comic sans ms' , 19 , 'bold'))
lbl_question.place(x = 60 , y = 20)

lbl_time = Label(win , text = 'Time :' , font = ('comic sans ms' , 16 , 'bold'))
lbl_time.place(x = 130, y = 70)

lbl_hurry_up = Label(win , text = '' , font = 'arial 13 bold' , bg = "#C1AB8C" , fg = "#B80000")
lbl_hurry_up.place(x = 290 , y = 70)

lbl_score = Label(win , text = 'Score :' , font = ('comic sans ms' , 16 , 'bold'))
lbl_score.place(x = 130 , y = 115)

lbl_color = Label(win , text = '' , font = 'arial 33 bold' , bg = "#C1AB8C" )
lbl_color.place(x =170 , y = 180 )

lbl_feedback = Label(win , text = '' , font = 'arial 12 bold' , bg = "#C1AB8C")
lbl_feedback.place(x = 190, y = 270)

#================================entry========================================

ent = Entry(win , font = 'arial 17' ,  width = 20)
ent.place(x = 105 , y = 240)

#================================frame========================================

frame_tip =LabelFrame(win , text='Tips' , font=('Arial',12 , 'bold') ,width=370 , height=180 , bg = "#C1AB8C" , fg = "#B80000")
frame_tip.place(x = 89 , y = 300)

lbl_welcome = Label (frame_tip , text = f'\u2b55Welcome to COLOR GAME.   ' '\n\u2b55The game starts with ENTER.\n\u2b55The game stops with SPACE.\n\u2b55The game closes with ESC.   '   '\n\u2b55Answer them all,you will win. ''\n\u2b55You only have 45 seconds.'"\U0001F605" , font = 'arial 15 bold' , bg = "#C1AB8C" ,fg = "#503B3B")
lbl_welcome.pack(padx = 4 , pady =3 )


#================================bind=========================================
win.bind('<Return>' , startgame)
win.bind('<Escape>' , escape)


win.mainloop()

Solution

  • It sounds like what you're asking for is a "Pause Game" feature. There are a couple of different ways to go about this, but basically you'll need a global flag that indicates whether or not the game is paused which starts as False, and gets toggled by the pause function as it does some other related actions.

    In this example I've added multiple global variables:

    game_started = False  # Is set to True by the startgame function to prevent pause action from working before the game is started.
    
    game_paused = False # Toggled by the new pause function
    
    countdown_id = None  # Will be set to the value of lbl_time.after(), so that we can cancel the scheduled event.
    

    Here's the pause function I wrote, and the keybinding for it. I added a "PAUSED" label to the timer for simplicity, but that could be moved elsewhere, including the text entry field. As it currently stands, it has a graphical glitch due overlap with lbl_hurry_up:

    win.bind("<space>", pause)
    
    def pause(event):
        global game_paused
        # Do nothing if game has not been started yet
        if not game_started:
            return
    
        if game_paused:  # Restart the countdown
            ent.config(state="normal")
            lbl_time.after(1000, countdown)
            lbl_time.config(text="Time :" + str(timeleft), font=("comic sans ms", 16, "bold"))
        else:
            # Remove the space the user just added
            current = ent.get()
            ent.delete(0, END)
            ent.insert(0, current[:-1])
    
            # Disable entry field and cancel next countdown
            ent.config(state="readonly")
            lbl_time.after_cancel(countdown_id)
            lbl_time.config(text="Time :" + str(timeleft) + " PAUSED", font=("comic sans ms", 16, "bold"))
        game_paused = not game_paused
    

    See this post for methods to update the value of the entry widget. I used the delete/insert method as you do not currently have a bound StringVar.

    Update the game_started function as follows to set the game_started flag and to not call nextcolor() while the game is paused:

    def startgame(event):
        global game_started
        if not game_started and timeleft == 45:
            game_started = True
            countdown()
        if not game_paused:
            nextcolor()
    

    Update the countdown() function to get the id of the next scheduled countdown and check the game_paused flag:

    def countdown():
        global timeleft
        global countdown_id
        if not game_paused and timeleft > 0:
            timeleft -= 1
            lbl_time.config(text="Time :" + str(timeleft), font=("comic sans ms", 16, "bold"))
            countdown_id = lbl_time.after(1000, countdown)
    
            if timeleft == 0:
                messagebox.showinfo("End", "Times up!")
    
        if timeleft <= 10 and timeleft > 0:
            lbl_hurry_up.config(text="Hurry up ,you are\n runing out of time!!!\U0001f630")
    

    You may want to consider moving all of those global flags inside of a single game state dictionary or class. That would allow you remove all of the explicit global varname calls in the code.