我正在使用customtkinter库制作一个游戏,这个游戏是一个涉及豆子的点击器大亨游戏。与cookie clicker非常相似。下面是整个代码
import customtkinter as ctk
from customtkinter import CTkImage,CTkButton,CTkLabel
#from PIL import Image
import time as t
# stores money
money = 0
# variables for bean generation
beans = 0
click = 1
#toggles bean collection
toggle=False
#Application
class BeanApp(ctk.CTk):
def __init__(self):
super().__init__()
# sets window and frames
self.title("Bean Tycoon")
self.geometry("500x500+700+200")
#click modes
multiplier_lbl=CTkLabel(self,text= "Multipliers")
multiplier_lbl.place(x=250,y=1,anchor="n",)
def xOne():#x1 multiplier toggle
global click
click=1
one_click_mode_btn.configure(state="disabled")
two_click_mode_btn.configure(state="enable")
click_multiplyer_lbl.configure(text=f" Beans/click: x{click} ")
def xTwo():#x2 multiplier toggle
global click
click=2
one_click_mode_btn.configure(state="enable")
two_click_mode_btn.configure(state="disabled")
click_multiplyer_lbl.configure(text=f" Beans/click: x{click} ")
one_click_mode_btn= CTkButton(self,text="x1",width=20,height=10,command=xOne,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=xTwo,state="disabled")
two_click_mode_btn.place(x=173,y=25,anchor="nw")
click_multiplyer_lbl=CTkLabel(self,text=f" Beans/click: x{click} ")
click_multiplyer_lbl.place(x=3,y=45,anchor="nw",)
# Bean generator
#beanbtn = CTkImage(Image.open("Pictures\TheBean.png"),size=(200,200))
bean_amt_lbl = CTkLabel(self,text= f" Beans: {beans} ",)
bean_amt_lbl.place(x=3,y=5,anchor="nw")
def clicked():
global beans
global click
beans += click
bean_amt_lbl.configure(text= f" Beans: {beans} ")
sell_beans_btn = CTkButton(self,text= "",image=None, command= clicked,width=180,height=180)
sell_beans_btn.place(x=250,y=330, anchor="s")
# Sell Beans
money_amt_lbl = CTkLabel(self,text=f" Money: ${money} ", )
money_amt_lbl.place(x=3,y=25,anchor='nw')
def sell():
global money
global beans
while beans >0:
money = money+beans
beans = 0
bean_amt_lbl.configure(text=f" Beans: {beans} ")
money_amt_lbl.configure(text=f" Money: ${money }")
sell_bean_btn = CTkButton(self,text="Sell Beans",image=None, command=sell)
sell_bean_btn.place(x=250,y=360,anchor='s')
#2 times multiplier
def d_b_u():#double_bean_upgrade
global click,money
if money>=100:
click=2
money=money-100
money_amt_lbl.configure(text=f" Money: ${money }")
double_bean_upgrade_btn.configure(state="disabled")
two_click_mode_btn.configure(state="disabled")
one_click_mode_btn.configure(state="enable")
click_multiplyer_lbl.configure(text=f" Beans/click: x{click} ")
#automatic bean collector
def a_b_c_u():#automatic_bean_collector_upgrade
global beans,money,toggle
if money>=20:
money=money-20
money_amt_lbl.configure(text=f" Money: ${money }")
auto_collect_bean_btn.configure(state="disabled")
while beans >=0 :
beans=beans+1
bean_amt_lbl.configure(text=f" Beans: {beans} " )
t.sleep(3)
print(beans)
#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=d_b_u,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=a_b_c_u,width=20,corner_radius=20)
auto_collect_bean_btn.place(x=390,y=70,anchor="nw")
if __name__ == "__main__":
app = BeanApp()
app.mainloop()
游戏包括在后台运行的递增计数器,循环通过按钮切换。然而,当循环激活时,它冻结应用程序。如何解决这个问题?
编辑:我给图像库和图像函数加了标签,因为它现在对代码没有任何影响。
编辑2:如何正确实现线程?我不认为我做得对…
#automatic bean collector
def b_c_():
global beans
while beans >=0 :
beans=beans+1
bean_amt_lbl.configure(text=f" Beans: {beans} " )
t.sleep(3)
print(beans)
bean_collector=Thread(target= b_c_)
def a_b_c_u():#automatic_bean_collector_upgrade
global beans,money,toggle
if money>=20:
money=money-20
money_amt_lbl.configure(text=f" Money: ${money }")
auto_collect_bean_btn.configure(state="disabled")
bean_collector.run()
编辑3:在这个项目上休息了一会儿,现在我又回来了。无论如何,在实现OneCrickiteer提供的代码后,我一边编辑一边摆脱错误并适应我的代码,我最终遇到了一个递归错误
#entire program
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")
self.bank = Bank()
self.bean_counter = BeanCounter()
#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("Pictures\TheBean.png"),size=(200,200))
def on_click():
self.bean_counter.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: {self.bean_counter.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(self.bean_counter.amount) # times amount per bean ; todo: add bank label updater function
self.bean_counter.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()
RecursionError:超过最大递归深度
self在BeanApp下的所有函数中被删除为self.bean_counter,而self.bank没有注册为Class Bank和Class BeanCounter的一部分。我也把类放在类函数class BeanDoubler(Thread,BeanCounter)
中,让它们下面的函数工作并注册对象。这是我的解决方案,以摆脱提示的错误,但现在我所拥有的是一个递归错误。
2条答案
按热度按时间fwzugrvs1#
您需要将循环放入另一个线程中,以便用户界面不会冻结。您可以使用
thread
库。3duebb1j2#
不阻塞UI的一般解决方案是在UI实际上需要更新时传递函数,根本不使用循环,或者非常少。
您还拥有全局状态,这是不推荐的。要解决这两个问题,请添加更多的类。
然后更新app构造函数,用上面的函数定义一些功能
然后呢
这并不能完全解决“自动收集器”阻塞UI的问题,但它至少为您指出了一个将“状态/模型”与“视图”分离的一般起点
一个解决方案是像这样围绕beancounter类创建一个线程 Package 器,然后在关联的操作上启动它。
(code尚未测试,抱歉,如果有错别字)