I am making a customtkinter game that is basically Cookie Clicker but themed around beans. and by suggestions from another thread I added Threading, which I'm having a hard time implementing, and multiple classes, which I don't understand how to make the data pass into my main class. regardless these attempts has gave me a recursion error
This is the entire program so far
import customtkinter as ctk
from customtkinter import CTkImage,CTkButton,CTkLabel
from PIL import Image
import time as t
from threading import Thread
class Bank():
def __init__(self):
self.money=0
def deposit(self,amount,handler=None):
self.money += amount
if handler:
handler(amount)
def withdraw(self, amount, handler=None):
if self.money >= amount:
self.money -= amount
if handler:
handler(amount)
else:
print('error: not enough money available')
class BeanCounter():
def __init__(self, amount=0):
self.amount = amount
def increment(self, handler=None):
''' accepts optional function called after one bean added '''
self.amount += 1
if handler:
handler()
class BeanDoubler(Thread,BeanCounter):
def __init__(self,update_func=None):
self.bean_counter = BeanCounter()
self.update_func = update_func
def run(self):
while True:
# use a for loop to increment over the amount (thereby doubling)
for _ in range(self.bean_counter.amount):
self.bean_counter.increment(self.update_func)
class BeanApp(ctk.CTk,Bank,BeanCounter):
def __init__(self):
# sets window and frames
self.title("Bean Tycoon")
#click modes
multiplier_lbl=CTkLabel(self,text= "Multipliers")
multiplier_lbl.place(x=250,y=1,anchor="n",)
one_click_mode_btn= CTkButton(self,text="x1",width=20,height=10,command=None,state="disabled")
one_click_mode_btn.place(x=145,y=25,anchor="nw")
two_click_mode_btn=CTkButton(self, text="x2",width=20,height=10,command=None,state="disabled")
two_click_mode_btn.place(x=173,y=25,anchor="nw")
click_multiplyer_lbl=CTkLabel(self,text=f" Beans/click: x{None} ")
click_multiplyer_lbl.place(x=3,y=45,anchor="nw",)
# Bean generator
beanbtn = CTkImage(Image.open("None"),size=(200,200))
def on_click():
BeanCounter.increment(bean_label_updater())
bean_amt_lbl = CTkLabel(self,text= f" Beans: {None} ",)
bean_amt_lbl.place(x=3,y=5,anchor="nw")
def bean_label_updater():
bean_amt_lbl.configure(text= f" Beans: {BeanCounter.amount} ")
sell_beans_btn = CTkButton(self,text= "",image=beanbtn, command= on_click,width=180,height=180)
sell_beans_btn.place(x=250,y=330, anchor="s")
# Sell Beans
money_amt_lbl = CTkLabel(self,text=f" Money: ${None} ", )
money_amt_lbl.place(x=3,y=25,anchor='nw')
def on_click_sell(self):
Bank.deposit(BeanCounter.amount) # times amount per bean ; todo: add bank label updater function
BeanCounter.amount = 0
sell_bean_btn = CTkButton(self,text="Sell Beans",image=None, command=on_click_sell)
sell_bean_btn.place(x=250,y=360,anchor='s')
#2 times multiplier
#Shop
shop_lbl= CTkLabel(self,text="Shop")
shop_lbl.place(x=425,y=5,anchor="nw")
double_bean_upgrade_btn = CTkButton(self,text="Bean Doubler\n$100",command=None,width=20,corner_radius=20)
double_bean_upgrade_btn.place(x=390,y=30,anchor="nw")
auto_collect_bean_btn = CTkButton(self,text="Auto Collect 1\n$200",command=None,width=20,corner_radius=20)
auto_collect_bean_btn.place(x=390,y=70,anchor="nw")
if __name__ == "__main__":
bank = Bank()
bean_counter = BeanCounter()
beandoubler = BeanDoubler()
app = BeanApp()
app.mainloop()
this is the error that pulled up recursion error
can anyone tell me where I went wrong and help me fix it?
what should come up is a customtkinter window that looks similar to this first window iteration the code that popped up that window kept freezing the application when i ran it, which is how I got to the current problem that I'm facing.
Edit 1: I have figured I should share the full callback log
Read the traceback, and you'll find that your error is only coming from self.title("Bean Tycoon")
line, so has nothing to do with the remainder of the code...
In any case, your classes don't need multi-inheritance
Replace
class BeanDoubler(Thread,BeanCounter):
with
class BeanDoubler(Thread):
A BeanCounter instance is passed into the __init__
constructor of that class, as shown in my previous answer
Similar for BeanApp
. It only needs to be a ctk.CTk
class, and the __init__
is different for that. Plus, you've removed super().__init__()
for some reason
Then, it is not BeanCounter.increment(bean_label_updater())
, it is self.bean_counter.increment(bean_label_updater)
...
You use an instance to call a function, not a class
You do not pass the return value of a function call into increment
, only the function name / handle. It's the responsibility of increment
to actually call the function via this section
if handler:
handler()
Similarly, BeanCounter.amount
is not a valid accessor. You should use self.bean_counter.amount
since it is an instance field, as was also written in my last answer.
You have defined functions within your __init__
of the BeanApp, which is generally not recommended. Define all functions at the class level, rather than within other functions. Then self
will reference the BeanApp
instance, where you can access self.bank
and self.bean_counter
, after updating your __init__
parameters and __main__
section.