Python 如何使图像在pyglet窗口中移动?

Python 如何使图像在pyglet窗口中移动?,python,animation,pyglet,Python,Animation,Pyglet,我正在尝试使用pyglet制作动画。所以首先我尝试了一个简单的动画,在一条海峡线上移动图像。理想情况下,我希望它从左到右反弹 这是我的密码: 导入pyglet def中心图像: 将图像的定位点设置为其中心 image.anchor_x=image.width//2 image.anchor_y=image.height//2 做窗户。 window=pyglet.window.Windowwidth=640,height=480 加载图像。 pyglet.resource.path=['imag

我正在尝试使用pyglet制作动画。所以首先我尝试了一个简单的动画,在一条海峡线上移动图像。理想情况下,我希望它从左到右反弹

这是我的密码:

导入pyglet def中心图像: 将图像的定位点设置为其中心 image.anchor_x=image.width//2 image.anchor_y=image.height//2 做窗户。 window=pyglet.window.Windowwidth=640,height=480 加载图像。 pyglet.resource.path=['images'] pyglet.resource.reindex heart\u img=pyglet.resource.image'red-heart.png' 中心图像心脏图像 制作动画精灵。 heart\u grid=pyglet.image.ImageGridheart\u img,行=1,列=5 heart\u ani=pyglet.image.Animation.from\u image\u sequenceheart\u网格,持续时间=0.1 心形精灵=pyglet.sprite.Spriteheart\u ani,x=100,y=300 heart_sprite.updatescale=0.05 @窗口事件 def on_draw: 窗户,没问题 心形精灵 如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu': pyglet.app.run 此代码生成以下内容:

我怎样才能让整个心都穿过窗户

理想的心脏轨迹如下:


盒子是框架,拱门是轨迹,O是精灵。因此,每个单词的第一个字母的心脏会反弹,然后精灵会反弹。

我的解决方案使用两个固定精灵之间的中点来确定移动的精灵是向上还是向下。为此,我制作了所有字母的单个精灵,每个字母对应一个png

希望这张图片能更好地解释下面的代码。

!/usr/bin/env python 导入pyglet 当前反弹=0 中点=[] 端点=[] def计算_中点1、s2: 计算x轴上两个精灵之间的中点。 返回s1.x+s2.x//2 def应向下移动: 决定精灵是上升还是下降。 全球货币反弹 如果精灵完成所有反弹,则应用程序关闭不是最佳解决方案。 如果MaxLenMiddpoints、lenENDPOINTS、CURR_BOUNCE==CURR_BOUNCE: 升起系统出口 如果精灵位于中点和终点之间,则向下移动。 如果中点[CURR_BOUNCE],那么主要的问题是动画假设一幅大图像中有一系列图像。这就是所谓的精灵动画,它本质上只是一个系列片,通常是一行或一个你想要的运动网格模式。它对于设置行走、攻击和其他类似游戏机制的动画非常有用

但要在画布上移动对象,需要以某种方式手动操纵顶点或图像位置。您自己的解决方案的工作原理是检查X是否大于或小于最小和最大限制。我只想在上面加上一些技巧,让大家更容易、更快地掌握动作和方向。下面是我用来确定运动方向的主要方法,这会使心脏在父窗口的宽度和高度约束下反弹

我还通过将pyglet窗口类继承到一个对象/类中,使整个项目更加面向对象,并使heart自己的类更容易区分什么时候和什么对象上的调用

from pyglet import *
from pyglet.gl import *

key = pyglet.window.key
# Indented oddly on purpose to show the pattern:
UP    = 0b0001
DOWN  = 0b0010
LEFT  = 0b0100
RIGHT = 0b1000

class heart(pyglet.sprite.Sprite):
    def __init__(self, parent, image='heart.png', x=0, y=0):
        self.texture = pyglet.image.load(image)
        pyglet.sprite.Sprite.__init__(self, self.texture, x=x, y=y)

        self.parent = parent
        self.direction = UP | RIGHT # Starting direction

    def update(self):
        # We can use the pattern above with bitwise operations.
        # That way, one direction can be merged with another without collision.
        if self.direction & UP:
            self.y += 1
        if self.direction & DOWN:
            self.y -= 1
        if self.direction & LEFT:
            self.x -= 1
        if self.direction & RIGHT:
            self.x += 1

        if self.x+self.width > self.parent.width:
            self.direction = self.direction ^ RIGHT # Remove the RIGHT indicator
            self.direction = self.direction ^ LEFT # Start moving to the LEFT
        if self.y+self.height > self.parent.height:
            self.direction = self.direction ^ UP # Remove the UP indicator
            self.direction = self.direction ^ DOWN # Start moving DOWN
        if self.y < 0:
            self.direction = self.direction ^ DOWN
            self.direction = self.direction ^ UP
        if self.x < 0:
            self.direction = self.direction ^ LEFT
            self.direction = self.direction ^ RIGHT

    def render(self):
        self.draw()

# This class just sets up the window,
# self.heart <-- The important bit
class main(pyglet.window.Window):
    def __init__ (self, width=800, height=600, fps=False, *args, **kwargs):
        super(main, self).__init__(width, height, *args, **kwargs)
        self.x, self.y = 0, 0

        self.heart = heart(self, x=100, y=100)

        self.alive = 1

    def on_draw(self):
        self.render()

    def on_close(self):
        self.alive = 0

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

    def render(self):
        self.clear()

        self.heart.update()
        self.heart.render()
        ## Add stuff you want to render here.
        ## Preferably in the form of a batch.

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

if __name__ == '__main__':
    x = main()
    x.run()
基本原理是相同的,操纵sprite.x使其横向移动,操纵sprite.y使其垂直移动。还有更多的优化要做,例如,更新应该根据最后一次渲染进行缩放。这样做是为了避免图形卡跟不上时出现故障。它可能会变得非常复杂,非常快,所以我将给你一个如何计算这些运动的例子

此外,您可能希望渲染批处理,而不是直接渲染精灵。这将大大加快大型项目的渲染过程


如果您不熟悉按位操作,那么简短的描述是,它以级别4==0100为例进行操作,并对UP、DOWN、LEFT和RIGHT的值执行异或操作。我们可以通过合并0100和0001来添加/删除方向,以0101为例。然后,我们可以进行二进制运算,而不是像传统的AND运算符那样,通过执行self.direction&0100来确定第三个位置0100上的值是否包含1,如果它是真的,那么结果将是1。如果你愿意的话,这是一种方便快捷的检查状态的方法。

理想情况下,我希望它从左到右弹跳——你能表现出预期的行为吗?@Alderven我在问题中对此进行了解释。它看起来像你使用的图像,是一个心脏的静态图像,这是正确的吗?这是因为动画意味着在一个图像中设置一系列图像的动画。这里有一些例子:我会像你在下面一样解决它,但可能在一个更简单和更短的版本。如果你愿意,我可以写一个答案,虽然如果你对自己目前的答案感到满意,可能需要10分钟的时间,但这也没关系,因为解决方案也会类似——只是稍微简单一点
ct导向:谢谢,这真的很好。我喜欢使用位操作来控制移动。