我正在尝试创建一个简单的点击游戏。我想随机创建“炸弹”,玩家需要在它爆炸之前点击它。现在我真的很努力,所以我的程序可以注册点击坐标,并确定你是否点击了炸弹或你是否错过了。有没有人有任何关于前进的指示/提示?
这是我到目前为止所得到的。
我的炸弹课:
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()
答案 0 :(得分:1)
我相信你有两个问题要解决。
首先,您正在呼叫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执行此操作。每一帧,你想告诉它一次检查和处理事件,而不是永远,我认为这样:
while not quit:
window.mainloop(1)
for bomb in bombs:
bomb.update()
if bomb.is_clicked():
bomb.defuse()
但这可能不对,主文档中没有提及,所以你可能需要进行一些搜索。
话虽如此,如果你真的想要一个手动帧循环,你可能真的不想要Tkinter
和graphics
,你想要PyGame
。
但是有一种不同的方法可以解决这个问题:让Tkinter运行它的事件循环(我认为graphics
会神奇地为你处理这个问题,如果你不顺利的话),并要求Tkinter安排你的东西运行。像这样:
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在另外的100ms内再次调用do_frame
。
唯一需要改变的是,当quit
为真时,你不能只是在程序结束时失败,所以你可能必须明确地调用一些quit
方法,可能在window
。
这个不能给你非常准确的时间。因此,任何事物,例如,移动一定数量的像素/帧将变得越来越慢。如果你希望它移动一定数量的像素/秒,你必须检查时间,看看自上次调用do_frame
以来它已经有多长时间并调整像素。
但它更简单,更适合Tkinter。
无论哪种方式解决这个问题,您的click_callback
都应该开始接听。
但它会在窗口上调用,而不是在圈子或其他图形小部件上调用。
据我所知,graphics
库没有任何用于命中测试的功能(确定鼠标所在的对象)。因此,您必须手动查看对象并查看谁应该获得单击,然后手动调用该对象上的某个方法。 (另外,如果您想要根据对象的中心或角来设置坐标,而不是主窗口,则必须手动转换它们。)
使用一个漂亮的精灵库(再次,就像PyGame中的那个),这会更容易,但 很难自己做 - 尤其是如果你不担心效率的话。 (当这是一个很难解决的问题时,视频游戏控制台的速度大约是手机的10000倍。)