试图绘制精灵或更改图片pyglet

时间:2016-12-04 20:17:04

标签: python sprite pyglet

我正在尝试学习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()

1 个答案:

答案 0 :(得分:2)

在订单中存在一些缺陷,您可以在其中执行操作 我将尽力描述它们,并为您提供一段代码,可以更好地满足您的需求。

我还认为你对这个问题的描述有点XY Problem,这在你认为自己接近解决方案的复杂问题上寻求帮助时很常见,所以你可以“在你提出的解决方案上寻求帮助,而不是问题。

我假设您要显示&#34;启动画面&#34; 10秒钟,这恰好是你的背景?然后在其上显示cat.pngdog.png,更正?

如果是这样,那么您可能需要更改内容才能使其正常工作:

draw()功能

它并没有真正更新屏幕,只是简单地将内容添加到图形内存中。更新屏幕的是您或某些事情告诉图形库您已经完成了向屏幕添加内容并且现在是时候更新您已经.draw()&n; n的所有内容。因此,循环中您需要的最后一件事是window.flip(),以便您实际绘制的内容能够显示。

如果你试图摆动窗口,你的东西可能会显示,它应该触发重新绘制场景,因为pyglet的内部机制如何工作..

如果你不打电话给.flip() - 可能永远不会发生redraw()电话 - 这也是Pyglet / GL的内部机制告诉显卡有什么东西已更新,我们已完成更新,现在是时候重新绘制场景。

一个场景

这是用户所看到的最常用词 我可能会在我的文字中大量提及这一点,所以很高兴知道这是用户所看到的,而不是你.draw()&n;或删除了什么,它是显卡的最后一次显卡呈现。

但是由于图形缓冲区的工作原理,我们可能已经删除或添加了内存而没有实际绘制它。记住这一点。

pyglet.app.run()来电

这是一个永无止境的循环本身,所以在while game:循环中使用它并不是真的有意义,因为.run()将会挂起&#34;在整个应用程序中,您要执行的任何代码都必须位于def on_drawevent中,而这些代码都是从图形代码本身生成的。

为了更好地理解这一点,请查看我的代码,多年来我已经在SO上粘贴了几次,它是两个自定义类的基本模型,继承了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()

现在,这段代码有目的地保持简单,我通常粘贴在SO上的完整代码可以在Torxed/PygletGui找到,gui.py是其中大部分内容来自的地方,它是&#39; s主循环。

我在这里做的只是使用&#34;实际&#34;替换Decorators。类中的函数。类本身继承了传统pyglet.window.Window中的函数,只要您将函数命名为与继承的函数相同,就可以用您决定的任何内容替换Window()的核心功能。在这种情况下,我模仿相同的功能,但添加了我自己的一些功能。

on_key_press

其中一个例子是on_key_press(),它通常只包含一个pass来电并且什么都不做,在这里,我们会检查是否按下了key.C,如果是,我们会添加一个项目self.sprites .. self.sprites恰好位于我们的render()循环中,其中的任何内容都会在背景上呈现。

这是我用过的照片:

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

bg.jpg cat.png dog.png

类:的CustomSprite

CustomSprite是一个非常简单的课程,旨在让您的生活更轻松,没有别的。它的功能非常有限,但它做得很少很棒。

它的灵魂目的是获取文件名,将其作为图像加载,您可以将对象视为传统的pyglet.sprite.Sprite,这意味着您可以移动它并以多种方式对其进行操作。

它保存了几行代码,必须加载您需要的所有图像,正如您在gui_classes_generic.py中所看到的那样,您可以添加一堆功能,这些功能可以隐藏&#34;并且通常不容易使用正常的精灵类。

我用这一堆!但是代码变得非常复杂,所以我保持这篇文章的目的很简单。

翻转功能

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

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

但是调用.flip()会告诉GL后端强制重绘。

进一步优化

有一个名为批量渲染的东西,基本上该图形卡旨在获取大量数据并一次性渲染,因此在几个项目上调用.draw()将只有在GPU有机会闪耀之前才会堵塞CPU。阅读有关Batched rendering and graphics的更多信息!它会为你节省很多帧率。

另一件事是在render()循环中保持尽可能少的功能,并使用事件触发器作为编码风格的主要来源。
Pyglet可以很好地保持快速,特别是如果你只是在事件驱动的任务上做事。

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

这是一段文字墙,我希望它能让你了解一些图形和东西的生活。继续前进,进入这种东西是一个障碍,但是一旦你掌握了它,它就会非常有价值(我仍然没有):)