如何让我的对象检测它是否已被单击?



我正在尝试创建一个简单的点击游戏。我想随机制造"炸弹",玩家需要在它爆炸之前点击它。现在我真的很难做到,这样我的程序就可以注册点击坐标,并确定你是点击了炸弹还是错过了。有人对未来有什么建议吗?

以下是我迄今为止的收获。

我的炸弹等级:

from graphics import *
import time

class Bomb(object):
def __init__(self, location, radius, window):
self.circle = Circle(location, radius)
self.circle.draw(window)
self.circle.setFill("black")
self.start_time = time.time()

def update(self):
if time.time() - self.start_time > 3.0:
self.circle.setFill("blue")
def ready_to_explode(self):
if time.time() - self.start_time > 3.0:
return True
def is_clicked(self):
#use x y coordinates of click and determine if the distance between this point and center of circle is < or > than radius?
def explode(self):
self.circle.setFill("pink")

def defuse(self):
self.circle.setFill("green")

我的主要程序:

from graphics import *
import time
import random
from bomb import Bomb

window = GraphWin("Click-click-BOOM! *", 400, 400)
event_text = Text(Point(100, 100), "events")
event_text.draw(window)
time_text = Text(Point(100, 200), "time info")
time_text.draw(window)

def keyboard_callback(event):
event_text.setText(event.char)
if "q" == event.char:
global quit
quit = True

def click_callback(event):
click_output = "button1 click at "
click_output += "<" + str(event.x) + ", " + str(event.y) + ">"
event_text.setText(click_output)
window.bind_all("<Key>", keyboard_callback)
window.bind_all("<Button-1>", click_callback)
start_time = time.time()
last_time = start_time
quit = False
bombs = []
bomb_to_add = Bomb(Point(random.randint(1, 400), random.randint(1, 400)), 25, window)
bombs.append(bomb_to_add)

frames = 0
while not quit:
for bomb in bombs:
bomb.update()
if bomb.is_clicked():
bomb.defuse()
window.close()
exit()

我相信您有两个问题需要解决。

首先,您正在呼叫window.bind_all("<Button-1>", click_callback)。这不是graphics方法,而是Tkinter方法。(Tkinter是graphics秘密使用的窗口和低级别图形库;它是Python标准库的一部分。)

应该意味着,每当用户在窗口中的任何位置单击鼠标时,都会调用click_callback函数。您可以看到它是否被调用,例如,在函数的开头添加一个print('click_callback got called')


但看起来你在这里运行自己的手动帧循环:

while not quit:
for bomb in bombs:
bomb.update()
if bomb.is_clicked():
bomb.defuse()

只要您从循环中驱动Tkinter的主循环,您就可以使用Tkinter执行此操作。每一帧,你都想告诉它检查和处理一次事件,而不是永远,我认为这看起来像这样:

while not quit:
window.mainloop(1)
for bomb in bombs:
bomb.update()
if bomb.is_clicked():
bomb.defuse()

但这可能是不对的,而且在主要文档中也没有提到,所以你可能需要做一些搜索。

也就是说,如果你真的想要手动帧循环,你可能真的不想要Tkintergraphics,你想要PyGame


但有一种不同的方法可以解决这个问题:只需让Tkinter运行它的事件循环(我认为graphics会神奇地为你解决这个问题,如果你不妨碍它的话),并让Tkinster安排你的东西运行。像这样:

def do_frame():
if quit:
window.quit() # may be wrong...
for bomb in bombs:
bomb.update()
if bomb.is_clicked():
bomb.defuse()
window.after(100, do_frame)
window.after(100, do_frame)

最后一行的意思是"从现在起,尽可能接近100毫秒,呼叫do_frame

然后,在do_frame中,你通过循环完成每次正在做的所有事情,最后要求Tkinter在100毫秒后再次调用do_frame

唯一需要更改的另一件事是,当quit为true时,您不能从程序的末尾掉下来,因此您可能必须显式调用一些quit方法,可能是在window上。

这个不能给你很准确的时间。所以,任何东西,比如说,移动一定数量的像素/帧,都会越来越慢。如果你想让它每秒移动一定数量的像素,你必须检查时间,看看距离上次调用do_frame已经有多长时间了,并调整像素。

但它要简单得多,对特金特来说也更地道。


一旦你解决了这个问题,无论哪种方式,你的click_callback都应该开始被调用。

但它是在窗口上调用的,而不是圆形或其他图形小部件。

据我所知,graphics库没有任何命中测试功能(确定鼠标所在的对象)。因此,您必须手动浏览对象,看看谁应该得到点击,然后手动调用该对象的一些方法。(此外,如果你想要以对象的中心或角为单位的坐标,而不是主窗口,你必须手动转换它们。)

有了一个漂亮的精灵库(同样,就像PyGame中的精灵库),这会更容易,但这并不是你自己很难做到的,尤其是如果你不担心效率的话。(当这还是一个棘手的问题时,视频游戏机的速度大约是你现在手机的10000倍。)

相关内容

  • 没有找到相关文章

最新更新