试图在精灵上绘制或更改图片侏儒

本教程将介绍试图在精灵上绘制或更改图片侏儒的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

试图在精灵上绘制或更改图片侏儒 教程 第1张

问题描述

我正在尝试学习pyglet,并用问卷之类的东西练习一些python编码,但我找不到一种方法来将背景图片移除或绘制在上面或其他东西上10秒钟。我是新来的,缺乏很多我需要的知识,谢谢你的帮助!

import pyglet
from pyglet.window import Window
from pyglet.window import key
from pyglet import image
import time

card1 = False
cat_image = pyglet.image.load("cat.png")
dog_image = pyglet.image.load("dog.png")
image = pyglet.image.load("backg.png")
background_sprite = pyglet.sprite.Sprite(image)
cat = pyglet.sprite.Sprite(cat_image)
dog = pyglet.sprite.Sprite(dog_image)
window = pyglet.window.Window(638, 404, "Life")
mouse_pos_x = 0
mouse_pos_y = 0
catmeme = pyglet.image.load("catmeme.png")
sprite_catmeme = pyglet.sprite.Sprite(catmeme)

@window.event
def on_draw():
 window.clear()
 background_sprite.draw()
 card_draw1(63, 192, 385, 192)
def card1():
 while time.time() < (time.time() + 10):
  window.clear()
  sprite_catmeme.draw()
@window.event
def card_draw1(x1, y1, x2, y2):
 cat.set_position(x1, y1)
 dog.set_position(x2, y2)
 cat.draw()
 dog.draw()
def card_draw2():
 pass
@window.event
def on_mouse_press(x, y, button, modifiers):
 if x > cat.x and x < (cat.x + cat.width):
  if y > cat.y and y < (cat.y + cat.height):
card1()
game = True
while game:
 on_draw()
 pyglet.app.run()

推荐答案

您的顺序和做事方式有一些缺陷。
我会尽我所能地描述它们,并给您提供一段可能更适合您的需求的代码。

我还认为您对问题的描述有点XY Problem,这在您认为自己接近解决方案的复杂问题上寻求帮助时非常常见,因此您请求的是针对您提出的解决方案的帮助,而不是问题。

我假设您想要显示10秒的"闪屏",而这恰好是您的背景?然后在上面显示cat.pngdog.png,对吗?

如果是这种情况,您可能需要更改以下内容才能使其正常工作:

draw()函数

它实际上并没有太多地更新屏幕,它只是在图形内存中添加了一些东西。更新屏幕的是您或某个人告诉图形库您已完成向屏幕添加内容,是时候更新所有内容.draw()‘n。因此,您在循环中最不需要的就是window.flip()以使您绘制的内容真正显示出来。

您的东西可能会显示如果您尝试摇动窗口,它应该会触发场景的重新绘制,因为侏儒的内部机制是怎么工作的。

如果您不调用.flip()-redraw()调用可能永远不会发生-这也是Pyglet/GL的内部机制,它会通知显卡某些内容已更新,我们已完成更新,是时候重新绘制场景了。

场景

这是最常用于表示用户所看到的内容的词。
我可能会在我的文本中多次提到这一点,所以很高兴知道这是用户看到的,而不是您.draw()‘n或已删除的内容,它是显卡在显示器上的最后一次当前渲染。

但由于图形缓冲区的工作方式,我们可能已经在没有实际绘制的情况下将内容删除或添加到内存中。请记住这一点。

pyglet.app.run()调用

这本身就是一个永无止境的循环,因此将其放在while game:循环中并无实际意义,因为.run()将"挂起"整个应用程序,您要执行的任何代码都需要位于def on_draw或从图形代码本身生成的event中。

为了更好地理解这一点,请看一下我的代码,这些年来,我在这里粘贴了几次它,它是两个自定义类的基本模型,继承了Pyglet的行为,但允许您设计自己的类,使其行为略有不同。

,并且大多数功能都在on_???函数下,该函数几乎总是用于捕获Events的函数。Pyglet内置了很多这样的代码,我们将用自己的代码覆盖它们(但名称必须相同)

import pyglet
from pyglet.gl import *

key = pyglet.window.key

class CustomSprite(pyglet.sprite.Sprite):
 def __init__(self, texture_file, x=0, y=0):
  ## Must load the texture as a image resource before initializing class:Sprite()
  self.texture = pyglet.image.load(texture_file)

  super(CustomSprite, self).__init__(self.texture)
  self.x = x
  self.y = y

 def _draw(self):
  self.draw()

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

  self.bg = CustomSprite('bg.jpg')
  self.sprites = {}
  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
  elif symbol == key.C:
print('Rendering cat')
self.sprites['cat'] = CustomSprite('cat.png', x=10, y=10)
  elif symbol == key.D:
self.sprites['dog'] = CustomSprite('dog.png', x=100, y=100)

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

现在,这段代码故意保持简单,我通常粘贴的完整代码可以在Torxed/PygletGui中找到,gui.py是大部分代码的来源,它是主循环。

我在这里所做的只是在类中使用"实际"函数替换Decorators。这个类本身继承了传统pyglet.window.Window的函数,一旦请问这些函数命名为与继承的函数相同的名称,就会用您决定的任何函数替换Window()的核心功能。在本例中,我模仿了相同的函数,但添加了几个我自己的函数。

On_Key_Press

on_key_press()就是一个这样的例子,它通常只包含一个pass调用,不执行任何操作,在这里,我们检查是否按下了key.C,如果按下了,则向self.sprites添加一个项。self.sprites正好在render()循环中,其中的任何内容都将呈现在背景之上。

以下是我使用的图片:

(命名为bg.jpgcat.pngdog.png-注意不同的文件结尾)

类:CustomSprite

CustomSprite是一个非常简单的类,旨在让您的生活在这一点上变得更容易,仅此而已。它的功能非常有限,但它做的很少,非常棒。

它的核心用途是获取文件名,将其作为图像加载,您可以将该对象视为传统的pyglet.sprite.Sprite,这意味着您可以通过多种方式移动和操作它。

它节省了几行代码来加载您需要的所有图像,并且正如您在gui_classes_generic.py中看到的那样,您可以添加一堆"不可见"的函数,这些函数通常不会轻易用于普通的Sprite类。

我经常用这个!但代码变得非常复杂,所以我故意让这篇文章变得简单。

翻转函数

即使在我的课堂上,我仍然需要使用flip()来更新屏幕内容。这是因为.clear()会像您预期的那样清除窗口,这也会触发场景的重绘。

bg.draw()在某些情况下,如果数据足够大或发生其他情况(例如,您移动窗口),可能会触发重新绘制。

但调用.flip()将通知GL后端强制重画。

进一步优化

有一种东西叫做批处理渲染,基本上显卡的设计是为了获取海量数据并一次渲染它,所以在几个项目上调用.draw()只会在GPU有机会发光之前就阻塞CPU。阅读有关Batched rendering and graphics的更多信息!它将为您节省大量的帧速率。

另一件事是在render()循环中保留尽可能少的功能,并使用事件触发器作为主要的编码样式来源。
Pyglet在快速方面做得很好,特别是当你只在事件驱动的任务上做事情的时候。

尽量避免计时器,但如果您确实需要使用时间来处理某些事情,例如在一段时间后删除cat.png,请使用clock/time event调用一个删除猫的函数。不要试图使用您自己的t = time()样式的代码,除非您知道要将它放在哪里以及为什么。有一个好的定时器,我很少用它。但如果你刚开始,你就应该这么做。

这是一堵地狱般的文字墙,我希望它能教会你一些图形和东西的生活中的东西。继续前进,这是进入这种东西的障碍,但一旦你掌握了它,它就会非常有意义(我仍然没有):)

好了关于试图在精灵上绘制或更改图片侏儒的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。