![](/img/trans.png)
[英]Pyglet: Sprite.draw() and Batch.draw() don't work, but Image.blit does
[英]trying to draw over sprite or change picture 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()
順序和執行操作時存在一些缺陷。
我將盡力描述它們,並為您提供一段代碼,使其可能更適合您的需求。
我也認為您對問題的描述有點像XY問題 ,這在您認為您已經接近解決方案的復雜問題上尋求幫助時很常見,因此您正在尋求有關已解決方案的幫助提出來,而不是問題。
我假設您想在10秒鍾內顯示“啟動畫面”,這恰好是您的背景? 然后在其cat.png
顯示cat.png
和dog.png
,對嗎?
如果是這樣,您可能需要在這里進行一些更改才能使其正常工作:
draw()
函數
它並沒有真正更新屏幕,只是將內容添加到圖形內存中。 更新屏幕的是您自己,或者是告訴圖形庫您已經完成了向屏幕中添加內容的工作,現在該更新所有.draw()
'n了。 因此,循環中需要的最后一件事是window.flip()
,以使繪制的內容真正顯示出來。
如果嘗試擺動窗口,您的情況可能會顯示出來,由於pyglet的內部機制如何工作,它應該觸發場景的重新繪制。
如果您不調用.flip()
- redraw()
調用將永遠不會發生的可能性-同樣,這是Pyglet / GL的內部機制,它告知圖形卡某些內容已更新,我們完成了更新,是時候重繪場景了。
一個場景
這是用戶看到的最常用的詞。
我可能會在文本中提到很多,所以很高興知道這是用戶正在查看的內容,而不是您看到的.draw()
'n或已刪除的內容,這是當前的最新渲染。圖形卡到顯示器。
但是由於圖形緩沖區的工作方式,我們可能已經刪除了內容或將內容添加到了內存中,而尚未實際繪制它。 請記住這一點。
pyglet.app.run()
調用
這本身就是一個永無止境的循環,因此在一段while game:
循環並沒有任何意義,因為.run()
將“掛起”整個應用程序,您要執行的任何代碼都必須在def on_draw
或從圖形代碼本身內部生成的event
。
為了更好地理解這一點,請看一下我的代碼,這些年來,我在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是其中的大部分來源,它是主循環。
我在這里所做的只是通過使用類中的“實際”函數來替換裝飾器 。 該類本身從傳統的pyglet.window.Window
繼承這些函數,並且一旦您將這些函數命名為與一次繼承的函數相同,就將您決定的內容替換Window()
的核心功能。在這種情況下,我模仿相同的功能,但添加一些我自己的功能。
這樣的例子就是on_key_press()
,它通常只包含一個pass
調用並且不執行任何操作,在這里,我們檢查是否按下了key.C
,如果是的話-我們在self.sprites
.. self.sprites
添加了一個項目在我們的render()
循環中,其中的所有內容都會在背景之上渲染。
這是我使用的圖片:
(名為bg.jpg
, cat.png
, dog.png
注意不同的文件結尾 )
CustomSprite
是一個非常簡單的類,旨在使您現在的生活更輕松,沒有別的。 它的功能非常有限,但是做得很少。
靈魂的目的是獲取一個文件名,將其作為圖像加載,然后您可以將該對象像傳統的pyglet.sprite.Sprite
一樣對待,這意味着您可以在其中移動並以多種方式對其進行操作。
它節省了幾行代碼,必須加載所需的所有圖像,並且如您在gui_classes_generic.py中看到的那樣,您可以向正常的sprite類添加一堆“不可見”且通常不易使用的函數。
我一堆用! 但是代碼變得非常復雜,所以我故意使這篇文章變得簡單。
即使在我的課堂上,我仍然需要使用flip()
來更新屏幕內容。 這是因為.clear()
會如您.clear()
清除窗口,這也會觸發場景的重繪。
在某些情況下,如果數據足夠大或發生其他事情(例如移動窗口bg.draw()
,則bg.draw()
可能會觸發重繪。
但是調用.flip()
會告訴GL后端強制重繪。
有一種叫做批處理渲染的東西,基本上,圖形卡被設計為可容納大量數據並一次性渲染,因此在多個項目上調用.draw()
只會在GPU甚至沒有機會發光之前阻塞CPU。 閱讀有關批量渲染和圖形的更多信息! 它將為您節省很多幀率。
另一件事是在render()
循環中保留盡可能少的功能,並將事件觸發器用作您的主要編碼樣式來源。
Pyglet可以很好地做到快速,特別是如果您僅在事件驅動的任務上執行操作。
盡量避免使用計時器,但是如果您確實需要使用時間來進行操作(例如在一定時間后刪除cat.png
,請使用clock / time事件調用刪除貓的函數。 不要嘗試使用自己的t = time()
樣式的代碼,除非您知道將代碼放置在何處以及原因。 有一個很好的計時器,我很少使用。。但是,如果您要開始的話,應該這樣做。
這一直是一堵牆的地獄,我希望它能教給您一些有關圖形和事物生活的知識。 繼續前進,進入這種東西是一個障礙,但是一旦您掌握了它,這將是非常有意義的(我還沒有):)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.