Search code examples
pythonpython-3.xtkintertkinter-buttontkinter-text

Tkinter Displaying Wrong Thing at Incorrect Time


I am trying to create a clicker game, and all the basic fundamentals are in; there's a button, you can click it, there's an upgrade, you can infinitely buy it while the price goes up 15%. Now, all of this is fine, but I want to implement a "prestige" for the upgrade; if you buy the upgrade 10 times, you will have to pay a price 5x the cost, but after that the upgrade will give you more rewards. I decided to put a counter in, and whenever you buy the upgrade, it goes up. Now, here is my problem. I put an if statement for when the counter reaches 10 (all of the data for that upgrade is stored in its own dictionary), it will change the text and cost. This does not work at all. Instead, it keeps the same text, and after buying it 1 - 3 more times, it will change the reward given, but nothing else.

Here is my code:

from tkinter import *
from threading import Timer

window = Tk()
window.minsize(1200, 500)
window.title("Clicker Game")

# general setup
default_font = ("Calibri", 15, "normal")
clicks = 0
click_power = 1

# upgrade variables
upgrade1_stats = {
    "cost": 15,
    "can buy": False,
    "times bought": 0,
    "click power given": 1,
    "prestige": False,
}


# functions

def check_clicks():
    global clicks, upgrade1_stats

    if clicks >= 10:
        upgrade1.place(x=200, y=50)

    if clicks >= upgrade1_stats["cost"]:
        upgrade1_stats["can buy"] = True
    else:
        upgrade1_stats["can buy"] = False


def get_upgrade1():
    global clicks, upgrade1_stats, click_power
    if upgrade1_stats["times bought"] == 10 and upgrade1_stats["can buy"]:
        upgrade1_stats["cost"] = int(upgrade1_stats["cost"] * 5)
        update_stats()
        upgrade1_stats["prestige"] = False
        upgrade1_stats["click power given"] += 1
        upgrade1_stats["times bought"] += 1
    if upgrade1_stats["can buy"]:
        clicks -= upgrade1_stats["cost"]
        click_power += upgrade1_stats["click power given"]
        upgrade1_stats["cost"] = int(upgrade1_stats["cost"] * 1.15)
        upgrade1_stats["times bought"] += 1
        update_stats()
    else:
        not_enough_clicks()
    check_clicks()

    if upgrade1_stats["prestige"]:
        upgrade1.config(text=f"MAX UPGRADES BOUGHT\nPRESTIGE COST: {upgrade1_stats['cost']}")
    else:
        upgrade1.config(text=f"+{upgrade1_stats['click power given']} Click Power\nCost: {upgrade1_stats['cost']}")




def not_enough_clicks():
    new_label = Label(text="NOT ENOUGH CLICKS", font=("Calibri", 80, "bold"))
    new_label.place(x=125, y=180)
    t = Timer(1, new_label.destroy)
    t.start()


def increase_score(*args):
    global clicks
    if len(args) > 0:
        update_amount = args[0]
    else:
        update_amount = click_power
    clicks += update_amount
    update_stats()
    check_clicks()


def update_stats(**kwargs):
    global clicks, click_power
    click_display.config(text=f"{clicks} Clicks")
    if click_power == 1:
        click_power_display.config(text=f"{click_power} Click per Button Click")
    else:
        click_power_display.config(text=f"{click_power} Clicks per Button Click")


# title text
title_label = Label(text="Clicker Game", font=("Calibri", 30, "bold"))
title_label.grid(column=1, columnspan=2, row=1)
window.grid_columnconfigure(2, weight=1)
window.grid_rowconfigure(1, weight=1)

# click display
click_display = Label(text=f"{clicks} Clicks", font=default_font)
click_display.grid(column=2, row=2)
window.grid_rowconfigure(2, weight=0, pad=70)

# button to click
clicker = Button(text="Click Me", command=increase_score, height=3, width=10, bg="red")
clicker.grid(column=2, row=3)
window.grid_rowconfigure(3, pad=200)

# click power display
click_power_display = Label(text=f"{click_power} Click per Button Click", font=default_font)
click_power_display.place(x=495, y=150)

# upgrades
upgrade1 = Button(text=f"+1 Click Power\nCost: {upgrade1_stats['cost']}", command=get_upgrade1)
window.mainloop()

The expectation is that once buying the upgrade 10 times, it would change the text to "MAX UPGRADES REACHED. PRESTIGE COST: (prestige cost here)". This is not at all what is happening, and I am very confused why. Any and all help would be greatly appreciated by me.

EDIT

With the help of @Alexander, I did update my code to this:

from tkinter import *
from threading import Timer

window = Tk()
window.minsize(1200, 500)
window.title("Clicker Game")

# general setup
default_font = ("Calibri", 15, "normal")
clicks = 0
click_power = 1

# upgrade variables
upgrade1_stats = {
    "cost": 15,
    "can buy": False,
    "times bought": 0,
    "click power given": 1,
    "prestige": False,
}


# functions

def check_clicks():
    global clicks, upgrade1_stats

    if clicks >= 10:
        upgrade1.place(x=200, y=50)

    if clicks >= upgrade1_stats["cost"]:
        upgrade1_stats["can buy"] = True
    else:
        upgrade1_stats["can buy"] = False


def get_upgrade1():
    global clicks, upgrade1_stats, click_power
    if upgrade1_stats["times bought"] == 10 and upgrade1_stats["can buy"]:
        upgrade1_stats["cost"] = int(upgrade1_stats["cost"] * 5)
        update_stats()
        upgrade1_stats["prestige"] = True
        upgrade1_stats["click power given"] += 1
        upgrade1_stats["times bought"] += 1
    elif upgrade1_stats["can buy"] and upgrade1_stats["times bought"] != 10:
        clicks -= upgrade1_stats["cost"]
        click_power += upgrade1_stats["click power given"]
        upgrade1_stats["cost"] = int(upgrade1_stats["cost"] * 1.15)
        upgrade1_stats["times bought"] += 1
        upgrade1_stats["prestige"] = False
        update_stats()
    else:
        not_enough_clicks()
    check_clicks()

    if upgrade1_stats["prestige"]:
        upgrade1.config(text=f"MAX UPGRADES BOUGHT\nPRESTIGE COST: {upgrade1_stats['cost']}")
    else:
        upgrade1.config(text=f"+{upgrade1_stats['click power given']} Click Power\nCost: {upgrade1_stats['cost']}")




def not_enough_clicks():
    new_label = Label(text="NOT ENOUGH CLICKS", font=("Calibri", 80, "bold"))
    new_label.place(x=125, y=180)
    t = Timer(1, new_label.destroy)
    t.start()


def increase_score(*args):
    global clicks
    if len(args) > 0:
        update_amount = args[0]
    else:
        update_amount = click_power
    clicks += update_amount
    update_stats()
    check_clicks()


def update_stats(**kwargs):
    global clicks, click_power
    click_display.config(text=f"{clicks} Clicks")
    if click_power == 1:
        click_power_display.config(text=f"{click_power} Click per Button Click")
    else:
        click_power_display.config(text=f"{click_power} Clicks per Button Click")


# title text
title_label = Label(text="Clicker Game", font=("Calibri", 30, "bold"))
title_label.grid(column=1, columnspan=2, row=1)
window.grid_columnconfigure(2, weight=1)
window.grid_rowconfigure(1, weight=1)

# click display
click_display = Label(text=f"{clicks} Clicks", font=default_font)
click_display.grid(column=2, row=2)
window.grid_rowconfigure(2, weight=0, pad=70)

# button to click
clicker = Button(text="Click Me", command=increase_score, height=3, width=10, bg="red")
clicker.grid(column=2, row=3)
window.grid_rowconfigure(3, pad=200)

# click power display
click_power_display = Label(text=f"{click_power} Click per Button Click", font=default_font)
click_power_display.place(x=495, y=150)

# upgrades
upgrade1 = Button(text=f"+1 Click Power\nCost: {upgrade1_stats['cost']}", command=get_upgrade1)
window.mainloop()

Now, there is still another problem: The prestige only shows up after "buying" the upgrade 2 or 3 times after you actually bought it 10 times. I want it to show up after EXACTLY 10 times. Could anybody help me with this?


Solution

  • The reason it takes more than 10 clicks for it to appear is because you do not increment the upgrade1_stats["times bought"] until after you have already checked how many times user has previously clicked the bonus. So it takes exactly 11 times.

    The solution would be to increment the times bought before checking if it has been bought 10 times, or alternatively you could start the times bought counter at 1 instead of 0.

    upgrade1_stats["times bought"] += 1
    

    I would recommend moving the above line and making a few other alterations to reduce some unnecessary code and improve readability. See inline notes in example below.

    from tkinter import *
    from threading import Timer
    
    window = Tk()
    window.minsize(1200, 500)
    window.title("Clicker Game")
    
    # general setup
    default_font = ("Calibri", 15, "normal")
    clicks = 0
    click_power = 1
    
    # upgrade variables
    upgrade1_stats = {
        "cost": 15,
        "times bought": 0,
        "click power given": 1
    }
    
    def get_upgrade1():
        global clicks, click_power 
        if clicks < upgrade1_stats["cost"]:      # if there is not enough clicks
            return not_enough_clicks()           # exit the function early
        upgrade1_stats["times bought"] += 1      # increase times bought before check
        if upgrade1_stats["times bought"] == 10:   
            upgrade1_stats["cost"] *= 5          # simplified multiplication
            upgrade1_stats["click power given"] += 1
            upgrade1.config(text=f"+{upgrade1_stats['click power given']} Click Power\nCost: {upgrade1_stats['cost']}")
        else:
            clicks -= upgrade1_stats["cost"]
            click_power += upgrade1_stats["click power given"]
            upgrade1_stats["cost"] = int(upgrade1_stats["cost"] * 1.15)
            upgrade1.config(text=f"MAX UPGRADES BOUGHT\nPRESTIGE COST: {upgrade1_stats['cost']}")
        update_stats()
    
    def not_enough_clicks():
        new_label = Label(text="NOT ENOUGH CLICKS", font=("Calibri", 80, "bold"))
        new_label.place(x=125, y=180)
        t = Timer(1, new_label.destroy)
        t.start()
    
    def increase_score(*_):
        global clicks
        clicks += click_power
        if clicks >= 10:
            upgrade1.place(x=200, y=50)
        update_stats()
    
    def update_stats(**_):
        verb = "Click" if click_power == 1 else "Clicks"
        click_display.config(text=f"{clicks} {verb}")
        click_power_display.config(text=f"{click_power} {verb} per Button Click")
    
    # title text
    title_label = Label(text="Clicker Game", font=("Calibri", 30, "bold"))
    title_label.grid(column=1, columnspan=2, row=1)
    window.grid_columnconfigure(2, weight=1)
    window.grid_rowconfigure(1, weight=1)
    
    # click display
    click_display = Label(text=f"{clicks} Clicks", font=default_font)
    click_display.grid(column=2, row=2)
    window.grid_rowconfigure(2, weight=0, pad=70)
    
    # button to click
    clicker = Button(text="Click Me", command=increase_score, height=3, width=10, bg="red")
    clicker.grid(column=2, row=3)
    window.grid_rowconfigure(3, pad=200)
    
    # click power display
    click_power_display = Label(text=f"{click_power} Click per Button Click", font=default_font)
    click_power_display.place(x=495, y=150)
    
    # upgrades
    upgrade1 = Button(text=f"+1 Click Power\nCost: {upgrade1_stats['cost']}", command=get_upgrade1)
    window.mainloop()