python - 如何使图像通过 pyglet 窗口移动?
问题描述
我正在尝试使用 pyglet 制作动画。所以首先我尝试了一个简单的动画,将图像沿直线移动。理想情况下,我希望它从左到右弹跳。
这是我的代码:
import pyglet
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width // 2
image.anchor_y = image.height // 2
# Make window.
window = pyglet.window.Window(width=640, height=480)
# Load image.
pyglet.resource.path = ['images']
pyglet.resource.reindex()
heart_img = pyglet.resource.image('red-heart.png')
center_image(heart_img)
# Make animation sprite.
heart_grid = pyglet.image.ImageGrid(heart_img, rows=1, columns=5)
heart_ani = pyglet.image.Animation.from_image_sequence(heart_grid, duration=0.1)
heart_sprite = pyglet.sprite.Sprite(heart_ani, x=100, y=300)
heart_sprite.update(scale=0.05)
@window.event
def on_draw():
window.clear()
heart_sprite.draw()
if __name__ == '__main__':
pyglet.app.run()
此代码产生:
怎样才能让整颗心穿过窗子?
理想的心脏轨迹是这样的:
盒子是框架,拱门是轨迹,O是精灵。所以心脏会弹跳每个单词的第一个字母,然后弹跳精灵。
解决方案
所以主要问题是Animation
假设一个大图像中有一系列图像。它被称为精灵动画,它本质上只是一系列你想要的动作(通常是一行或一个网格模式)。它对于动画行走、攻击和其他类似的游戏机制很有用。
但是要在画布上移动对象,您需要以某种方式手动操作顶点或图像位置。您自己的解决方案的工作原理是检查是否X
大于或小于min
和max
限制。我只想在此基础上添加一些技巧,以更轻松、更快速地处理动作和方向。下面我使用按位运算来确定运动方向,这使得心脏围绕宽度和高度的父(窗口)约束反弹。
我还冒昧地通过将 pygletWindow
类继承到一个对象/类中来使整个项目更加面向对象,并使其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
例如),并对 、 和的值进行XOR
操作。作为示例,我们可以通过合并和生成来添加/删除方向。然后我们可以做二进制(不像传统的运算符)来确定一个值是否在第三个位置()上包含 a ,这将导致if it's 。如果您愿意,这是检查“状态”的一种方便快捷的方法。UP
DOWN
LEFT
RIGHT
0100
0001
0101
AND
and
1
0100
self.direction & 0100
1
True
推荐阅读
- node.js - Angular CLI - ng serve - 来自节点进程的高 CPU 使用率
- reactjs - 返回搜索消息在反应钩子中显示零搜索结果
- c# - 如何阻止我的播放器从地板上掉下来?并在它降落时播放音频?
- python - 如何将数组保存在与 FBK Fairseq 兼容的 .npz 结构中以进行直接语音翻译?
- actions-on-google - 如何制作场景海峡的报告状态?
- mysql - Mysql Join - 问答标签系统 - 如何修改以显示标签和答案计数,即使是没有交叉引用的标签
- linux - dumpe2fs 只显示一行信息
- python - 分布式时如何划分数据集
- c# - Unity5 实例化可编写脚本的对象
- java - 仅将唯一的属性记录保存到数据库的良好做法