[英]Having multiple sprites in one Pyglet Window
我有下面的代碼,當前在空白的Pyglet窗口上輸出圖像,但是僅輸出一個圖像。 我真的需要每兩秒鍾添加一個新圖像,並且以前的圖像也保持不變。 例如,添加一個圖像,兩秒鍾后添加另一個圖像,並在添加另一個圖像后兩秒鍾。 我已經添加了隨機庫,因此可以添加隨機圖像。
我下面的代碼僅顯示一個圖像-我覺得這卡在繪制部分的某處。
import pyglet
import time
import random
window = pyglet.window.Window()
while True:
images = ["Image 1.png", "Image 2.png", "Image 3.png"]
choice = images[random.randint(0,2)]
rawImage = pyglet.resource.image(choice)
sprite = pyglet.sprite.Sprite(rawImage)
@window.event
def on_draw():
window.clear()
sprite.draw()
time.sleep(2)
pyglet.app.run()
您提供的任何幫助或建議,將不勝感激。
您的代碼有一些問題/建議。 首先,以下代碼是多余的:
while True:
images = ["Image 1.png", "Image 2.png", "Image 3.png"]
....
pyglet.app.run()
因為pyglet.app.run()
是一個阻塞調用,也就是說,該循環永遠不會循環-因為pyglet.app.run()
本身就是一個循環(稍后會詳細介紹)。
除非您的應用程序崩潰了,但您不處理這些異常,因此即使在那種情況下,也不會重新運行/循環代碼。
其次,永遠不要在循環內定義數組/列表或任何其他內容。 循環通常用於邏輯操作,而不是創建事物。 在大多數情況下,在循環內創建事物很有用,但有時它們通常不帶有if
語句。
資源對於計算機而言,設置和內存/硬盤驅動器等均耗費大量資源。因此,建議盡早在任何循環之外創建列表。 例如:
window = pyglet.window.Window()
images = ["Image 1.png", "Image 2.png", "Image 3.png"]
while True:
choice = images[random.randint(0,2)]
如果-再次-循環實際上循環了,那將是一個更好的選擇。 在這種情況下,只需整理一下即可。
另外,此代碼塊:
@window.event
def on_draw():
window.clear()
sprite.draw()
也不應該在循環中創建它,而是要替換您的window
變量on_draw
函數。 因此,應盡快將其移出並放入邏輯IMO中。 至少與所有其他邏輯保持分離,因此它不在“添加隨機圖像”和“循環”之間。
現在,您的代碼失敗的主要原因是您認為這會循環,但不會。 再次, pyglet.app.run()
會將代碼執行鎖定在該行上,因為在該函數調用內循環永遠不會結束。
您可以擴展代碼,然后從pyglet.py
的源代碼中復制粘貼代碼,它看起來像這樣(只是為了讓您了解正在發生的事情):
window = pyglet.window.Window()
while True:
images = ["Image 1.png", "Image 2.png", "Image 3.png"]
choice = images[random.randint(0,2)]
rawImage = pyglet.resource.image(choice)
sprite = pyglet.sprite.Sprite(rawImage)
@window.event
def on_draw():
window.clear()
sprite.draw()
time.sleep(2)
def run(self):
while True:
event = self.dispatch_events()
if event:
self.on_draw()
請注意pyglet.app.run()
如何while True
循環中擴展為另一個, while True
循環永遠不會中斷。 有點簡化了 ,但這實際上就是發生的事情。
因此,您的sprite = pyglet.sprite.Sprite(rawImage)
永遠不會重新觸發。
然后,要解決第二個大問題,為什么此代碼將永遠無法工作:
你在做:
def on_draw():
sprite.draw()
但是每個循環都可以通過執行sprite = pyglet.sprite.Sprite(rawImage)
用一個新的sprite
對象替換舊的sprite
對象。 因此,您想要做的是將列表/字典與所有可見圖像保持在循環外部,然后添加到列表/字典中,僅渲染添加的圖像。
很像這樣:
import pyglet
import time
import random
width, height = 800, 600
window = pyglet.window.Window(width, height)
## Image options are the options we have,
## while `images` are the visible images, this is where we add images
## so that they can be rendered later
image_options = ["Image 1.png", "Image 2.png", "Image 3.png"]
images = {}
## Keep a timer of when we last added a image
last_add = time.time()
## Just a helper-function to generate a random image and return it
## as a sprite object (good idea to use sprites, more on that later)
def get_random_image():
choice = image_options[random.randint(0, len(image_options)-1)]
return pyglet.sprite.Sprite(pyglet.image.load(choice))
## Here, we define the `on_draw` replacement for `window.on_draw`,
## and it's here we'll check if we should add a nother image or not
## depending on how much time has passed.
@window.event
def on_draw():
window.clear()
## If two seconds have passed, and the ammount of images added are less/equal
## to how many images we have in our "database", aka `image_options`, then we'll
## add another image somewhere randomly in the window.
if time.time() - last_add > 2 and len(images) < len(image_options):
last_add = time.time()
image = get_random_image()
image.x = random.randint(0, width)
image.y = random.randint(0, height)
images[len(images)] = image
## Then here, is where we loop over all our added images,
## and render them one by one.
for _id_ in images:
images[_id_].draw()
## Ok, lets start off by adding one image.
image = get_random_image()
image.x = random.randint(0, width)
image.y = random.randint(0, height)
images[len(images)] = image
## And then enter the never ending render loop.
pyglet.app.run()
現在,這僅在您按下一個鍵或在窗口內按下鼠標時有效。 這是因為這是事件被調度的唯一時間。 而且Pyglet僅在觸發事件時才渲染事物。 有兩種方法可以解決此問題,我現在將跳過硬核OOP方法。
第二種是使用所謂的“ Pyglet時鍾”,您可以在其中安排間隔執行某件事。 我在這部分並不很擅長,因為我傾向於使用自己的調度程序等。
但這是要點:
def add_image():
images[len(images)] = get_random_image()
pyglet.clock.schedule_interval(add_image, 2) # Every two seconds
這比執行if time.time() - last_add > 2
要干凈得多。
結果應如下所示:
import pyglet
import time
import random
width, height = 800, 600
window = pyglet.window.Window(width, height)
## Image options are the options we have,
## while `images` are the visible images, this is where we add images
## so that they can be rendered later
image_options = ["Image 1.png", "Image 2.png", "Image 3.png"]
images = {}
## Just a helper-function to generate a random image and return it
## as a sprite object (good idea to use sprites, more on that later)
def get_random_image():
choice = image_options[random.randint(0, len(image_options)-1)]
return pyglet.sprite.Sprite(pyglet.image.load(choice))
def add_image(actual_time_passed_since_last_clock_tick):
image = get_random_image()
image.x = random.randint(0, width)
image.y = random.randint(0, height)
images[len(images)] = image
## Here, we define the `on_draw` replacement for `window.on_draw`,
## and it's here we'll check if we should add a nother image or not
## depending on how much time has passed.
@window.event
def on_draw():
window.clear()
## Then here, is where we loop over all our added ima ges,
## and render them one by one.
for _id_ in images:
images[_id_].draw()
## Ok, lets start off by adding one image.
image = get_random_image()
image.x = random.randint(0, width)
image.y = random.randint(0, height)
images[len(images)] = image
## Add the schedule interval of adding a image every two seconds.
pyglet.clock.schedule_interval(add_image, 2)
## And then enter the never ending render loop.
pyglet.app.run()
這樣,您無需按任何鍵或鼠標即可在Pyglet中觸發事件,它將為您處理事件並按計划執行。
接下來,是我的部分小優化。 這是一種獎勵,並且會加快處理速度。 這稱為批處理渲染 ,當您渲染大量圖像和精靈時,您當前一次將一張圖像發送到圖形卡。 這非常占用CPU 。 您要做的就是將工作放在GPU上 。 因為畢竟您正在使用圖形,對嗎?
因此,在這種情況下,批處理渲染非常簡單。 每次調用pyglet.sprite.Sprite
,它都有一個名為batch=None
(默認)的參數。 如果將批處理添加到sprite對象,則可以通過調用batch.draw()
而不是每個單獨的sprite.draw()
來渲染整個批處理。
解決方案如下所示:
import pyglet
import time
from random import randint
width, height = 800, 600
window = pyglet.window.Window(width, height)
main_batch = pyglet.graphics.Batch()
## Image options are the options we have,
## while `images` are the visible images, this is where we add images
## so that they can be rendered later
image_options = ["Image 1.png", "Image 2.png", "Image 3.png"]
images = {}
## Just a helper-function to generate a random image and return it
## as a sprite object (good idea to use sprites, more on that later)
def get_random_image(x=0, y=0):
choice = image_options[randint(0, len(image_options)-1)]
return pyglet.sprite.Sprite(pyglet.image.load(choice), x=x, y=y, batch=main_batch)
def add_image(actual_time_passed_since_last_clock_tick=0):
image = get_random_image(x=randint(0, width), y=randint(0, height))
images[len(images)] = image
## Here, we define the `on_draw` replacement for `window.on_draw`,
## and it's here we'll check if we should add a nother image or not
## depending on how much time has passed.
@window.event
def on_draw():
window.clear()
## Instead of looping over each image in `images`,
## just do:
main_batch.draw()
## Ok, lets start off by adding one image.
## Instead of doing it manually, use the function add_image.
add_image()
## Add the schedule interval of adding a image every two seconds.
pyglet.clock.schedule_interval(add_image, 2)
## And then enter the never ending render loop.
pyglet.app.run()
我還對add_image
和get_random_image
進行了一些更改,主要是為了使您可以知道圖像在函數中應該位於什么位置,因為pyglet.sprite.Sprite
還pyglet.sprite.Sprite
其他兩個參數x
和y
。 因此,在創建精靈后更改x
和y
毫無意義,除非以后要移動它們(例如,在pyglet.clock.schedule_interval
調用中)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.