0

我正在尝试创建一个简单的点击游戏。我想随机制造“炸弹”,玩家需要在它爆炸之前点击它。现在我真的很难做到,所以我的程序可以注册点击坐标,并确定你是否点击了炸弹或者你是否错过了。有没有人有任何前进的指针/提示?

这是我到目前为止所得到的。

我的炸弹类:

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()
4

1 回答 1

1

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

首先,您正在调用window.bind_all("<Button-1>", click_callback). 这不是一种graphics方法,而是一种 Tkinter 方法。(Tkinter 是在幕后使用的 windows-and-low-level-graphics 库graphics;它是 Python 标准库的一部分。)

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


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

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()

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

话虽这么说,如果你真的想要一个手动帧循环,你可能真的不想要Tkintergraphics你想要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,你在循环中做你每次做的所有事情,最后让 Tkinterdo_frame在另外 100 毫秒内再次调用。

您需要更改的唯一另一件事是,当为 true 时,您不能只是退出程序的末尾quit,因此您可能必须显式调用某个quit方法,可能是 on window

这个不能给你非常准确的时间。因此,任何移动一定数量的像素/帧的东西都会变得越来越慢。如果您希望它每秒移动一定数量的像素,则必须检查时间并查看自上次do_frame调用以来已经过了多长时间并调整像素。

但对于 Tkinter 来说,它更简单,也更惯用。


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

但它在window上被调用,而不是在 circle 或其他图形小部件上。

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

使用漂亮的 sprite 库(同样,就像 PyGame 中的那个)会更容易,但自己动手并不——尤其是如果您不担心效率的话。(当这是一个难题时,视频游戏机的速度大约是您今天手机的 10000 倍。)

于 2015-04-18T00:04:17.870 回答