Pyglet 中的 Sprite 没有做我想做的事

Sprite in Pyglet not doing what I want

我正在尝试创建一个圆圈,当单击该圆圈时,它会移动到屏幕上的其他位置。但是,当我点击圆圈时,没有任何反应。

#IMPORT STUFF
import pyglet as pg
from random import randint

mouse = pg.window.mouse

#VARS
window = pg.window.Window(width = 640, height = 480)
score = 0
circleImg = pg.image.load("circle.png")
circle = pg.sprite.Sprite(circleImg, randint(1, window.width), randint(1, window.height))
text = pg.text.Label("Click red!", font_name = "Times New Roman", font_size = 18, x = 260, y = 10)


#DETECT MOUSE PRESS ON CIRCLE
@window.event
def on_mouse_press(x, y, button, modifiers):
    if x == circle.x and y == circle.y:
        circle.x = randint(1, window.width)
        circle.y = randint(1, window.height)

@window.event
def on_draw():
    window.clear()
    text.draw()
    circle.draw()

pg.app.run()

我不熟悉 pyglet,但我猜问题是你正在检查是否 x == circle.x 等,这意味着它只有在你单击正中心的单个像素时才会移动圈子。尝试与中心的某种最大距离(例如斜边 math.sqrt( (x-circle.x)**2 + (y-circle.y)**2) < circle.radius

import pyglet
from pyglet.gl import *
from random import randint

glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

class Circle(pyglet.sprite.Sprite):
    def __init__(self, radiance=5, x=0, y=0):
        self.texture = pyglet.image.load('circle.png')
        super(Circle, self).__init__(self.texture)

    def click(self, x, y):
        if x >= self.x and y >= self.y:
            if x <= self.x + self.texture.width and y <= self.y + self.texture.height:
                return self

mouse = pyglet.window.mouse

#VARS
window = pyglet.window.Window(width = 640, height = 480)
score = 0
#circleImg = pyglet.image.load("circle.png")
#circle = pyglet.sprite.Sprite(circleImg, randint(1, window.width), randint(1, window.height))
circle = Circle(x=50, y=50)
text = pyglet.text.Label("Click red!", font_name = "Times New Roman", font_size = 18, x = 260, y = 10)


#DETECT MOUSE PRESS ON CIRCLE
@window.event
def on_mouse_press(x, y, button, modifiers):
    if circle.click(x, y):
        print('Clicked in circle')
        circle.x = randint(0, window.width - 10)
        circle.y = randint(0, window.height - 10)

@window.event
def on_draw():
    window.clear()
    text.draw()
    circle.draw()

pyglet.app.run()

对其作用的简短描述是它创建了一个名为 Circle 的自定义 class,它继承了 Sprite class。它将 circle.png 作为纹理加载,并带有由 GL 库混合的 alpha 通道。

我们添加一个名为 click 的自定义函数,用于检查最低 x,y 坐标是否高于圆圈最低 x,y,然后我们检查光标是否低于 [=18] =] 和图像区域的 y 相同。

如果是这样,我们 return 圆形精灵 class 作为 True 值,以防我们想要使用精灵。

未来的改进:

您应该使用 gl functions 绘制圆,因此我在 class 定义中定义了 radiance。然而,此处的 radiance 从未使用过,它是未来的占位符。 这样一来,如果您确实在圆圈内单击,就可以使用数学来定义,但这超出了我快速回答的范围。我必须自己进行大量调试才能使数学相加(这不是我坚强的一面)。

现在它起作用的原因是我们使用图像宽度、高度、x 和 y 数据来粗略地检查我们是否在图像内,也就是 "the circle"。


作为奖励,我会将此答案添加到增强列表中,因为它包含一些可能有用的内容。一种是用自定义 pyglet.window.Window class 替换 90% 的代码,以替换全局变量和装饰器等。

它看起来像这样:

import pyglet
from pyglet.gl import *
from random import randint

glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

key = pyglet.window.key

class Circle(pyglet.sprite.Sprite):
    def __init__(self, radiance=5, x=0, y=0):
        self.texture = pyglet.image.load('circle.png')
        super(Circle, self).__init__(self.texture)

    def click(self, x, y):
        if x >= self.x and y >= self.y:
            if x <= self.x + self.texture.width and y <= self.y + self.texture.height:
                return self

class MainScreen(pyglet.window.Window):
    def __init__ (self):
        super(MainScreen, self).__init__(800, 600, fullscreen = False)
        self.x, self.y = 0, 0

        self.bg = pyglet.sprite.Sprite(pyglet.image.load('background.jpg'))
        self.sprites = {}
        self.sprites['circle'] = Circle(x=50, y=50)
        self.sprites['label'] = pyglet.text.Label("Click red!", font_name = "Times New Roman", font_size = 18, x = 260, y = 10)
        self.alive = 1

    def on_draw(self):
        self.render()

    def on_close(self):
        self.alive = 0

    def on_mouse_press(self, x, y, button, modifiers):
        if self.sprites['circle'].click(x, y):
            print('Clicked in circle')
            self.sprites['circle'].x = randint(0, self.width - 10)
            self.sprites['circle'].y = randint(0, self.height - 10)

    def on_key_press(self, symbol, modifiers):
        if symbol == key.ESCAPE: # [ESC]
            self.alive = 0

    def render(self):
        self.clear()
        self.bg.draw()

        for sprite_name, sprite_obj in self.sprites.items():
            sprite_obj.draw()

        self.flip()

    def run(self):
        while self.alive == 1:
            self.render()

            # -----------> This is key <----------
            # This is what replaces pyglet.app.run()
            # but is required for the GUI to not freeze
            #
            event = self.dispatch_events()

x = MainScreen()
x.run()