- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个应用程序正在创建名为 Pizza Clicker 的 Cookie Clicker 的替代版本。它非常基本,但运行速度非常慢,我不明白为什么。
import pyglet
window = pyglet.window.Window(fullscreen=True, caption="Click For Pizzas", resizable=True)
win_width = window.width
win_height = window.height
window.set_fullscreen(False)
window.set_size(win_width, win_height)
image_height = round(int(win_width/5)/1.4, 1)
class Main(object):
def __init__(self):
self.label = pyglet.text.Label('Pizzas: 0', font_size=100, color=(0, 0, 0, 255),
x=win_width//2, y=win_height - 100,
anchor_x='left', anchor_y='top')
self.points = 0
self.number = 1
def background(self):
background_img = pyglet.resource.image('pizza_clicker.png')
background_img.width = (win_width/5)*4
background_img.height = win_height
background_img.blit(int(win_width/5), 0, 0.5)
def drawSidebar(self):
width = int(win_width/5)
height = int(win_height)
sidebar_pattern = pyglet.image.SolidColorImagePattern(color=(100, 100, 100, 100))
sidebar = sidebar_pattern.create_image(width, height)
sidebar.blit(0, 0)
pizza = []
images = ('pizza_1.png', 'pizza_5.png', 'pizza_5.png', 'pizza_5.png')
for i in range (0, len(images)):
divideby = 1.4 / (i + 1)
pizza.append(pyglet.resource.image(images[i]))
pizza[i].width = width
pizza[i].height = round(width/1.4, 1)
pizza[i].blit(0, window.height - (round(width/divideby, 1)))
def getNumber(self, y):
if y > window.height - int(image_height):
self.number = 1
elif y > window.height - (int(image_height)*2):
self.number = 5
elif y > window.height - (int(image_height)*3):
self.number = 10
elif y > window.height - (int(image_height)*4):
self.number = 20
def addPoint(self):
self.points += self.number
self.label.text = 'Pizzas: %s' %self.points
@window.event
def on_mouse_press(x, y, buttons, modifiers):
if buttons & pyglet.window.mouse.LEFT and x > win_width/5:
main.addPoint()
elif buttons & pyglet.window.mouse.LEFT and x < win_width/5:
main.getNumber(y)
@window.event
def on_draw():
window.clear()
main.background()
main.label.draw()
main.drawSidebar()
main = Main()
pyglet.app.run()
所以问题是,当我单击窗口右侧时,它应该立即添加一个点(或多个),但会滞后几秒钟。另外,为了避免大家感到困惑,代码确实可以工作,但速度很慢。我应该怎么解决?
最佳答案
在每次 draw()
迭代中,您都会执行以下操作:
background_img = pyglet.resource.image('pizza_clicker.png')
这意味着您正在从硬盘驱动器加载同一张图片中的每个渲染序列。您还对不同的披萨图像执行 for 循环,并从硬盘驱动器中获取它们:
for i in range (0, len(images)):
divideby = 1.4 / (i + 1)
pizza.append(pyglet.resource.image(images[i]))
我强烈建议您阅读如何加载资源,并使用 cProfiler 分析器。
here 是如何分析代码的一个很好的例子。 。由于这是一个外部来源,我还将添加两个 SO 的链接,这两个链接同样好(但不是那么有效或不言自明):
这是一个 tl-dr 版本:
python -m cProfile -o profile_data.pyprof your_script.py
pyprof2calltree -i profile_data.pyprof -k
这应该呈现一个所谓的“调用树”,其中包含您的代码执行的所有执行、它们花费了多长时间以及它们使用了多少内存。从应用程序的开始到底部。
但是,我强烈建议您执行 1 个渲染序列,并在第一次渲染后添加 exit(1)
。这样您就可以分析 1 次运行,而不是每秒 60 次。
搜索关键字以了解代码缓慢的原因:Python、profiling、kcachegrind、cprofile、cprofiling、callstack。
要解决大部分问题,请将所有 I/O 密集型操作(加载图像、创建形状等)移至主类的 __init__
调用中。
最终产品看起来像这样:
class Main(object):
def __init__(self):
self.label = pyglet.text.Label('Pizzas: 0', font_size=100, color=(0, 0, 0, 255),
x=win_width//2, y=win_height - 100,
anchor_x='left', anchor_y='top')
self.points = 0
self.number = 1
self.background_img = pyglet.resource.image('pizza_clicker.png')
self.background_img.width = (win_width/5)*4
self.background_img.height = win_height
sidebar_pattern = pyglet.image.SolidColorImagePattern(color=(100, 100, 100, 100))
self.sidebar = sidebar_pattern.create_image(width, height)
self.pizzas = []
width = int(win_width/5)
height = int(win_height)
self.pizza_images = ('pizza_1.png', 'pizza_5.png', 'pizza_5.png', 'pizza_5.png')
for i in range (0, len(pizza_images)):
resource = pyglet.resource.image(pizza_images[i])
resource.width = width
resource.height = round(width/1.4, 1) # Not sure why you're using width here.. meh.. keeping it -yolo-
self.pizzas.append(resource)
def background(self):
self.background_img.blit(int(win_width/5), 0, 0.5)
def drawSidebar(self):
width = int(win_width/5)
height = int(win_height) # You're using win_height here, but window.height later. It's strange.
self.sidebar.blit(0, 0)
for i in range (0, len(self.pizza_images)):
divideby = 1.4 / (i + 1)
self.pizzas[i].blit(0, window.height - (round(width/divideby, 1)))
def getNumber(self, y):
if y > window.height - int(image_height):
self.number = 1
elif y > window.height - (int(image_height)*2):
self.number = 5
elif y > window.height - (int(image_height)*3):
self.number = 10
elif y > window.height - (int(image_height)*4):
self.number = 20
def addPoint(self):
self.points += self.number
self.label.text = 'Pizzas: %s' %self.points
但是为什么停在这里,这里大量使用了blit
。 Blit 适合一两个对象。但很快就很难跟踪你将所有内容“传输”到什么内容以及何处。您还在循环等中进行大量除法、加法和其他类型的计算。
记住,循环是渲染中的魔鬼。
如果你在某个地方有一个循环,你几乎肯定可以开始在那里寻找性能问题(任何人看到这个评论都会说“pff他不知道他在说什么”..是的我知道,但这是一个很好的初学者提示)。
我强烈建议您将图片放入 pyglet.sprite.Sprite()对象代替。他们跟踪位置、渲染,最重要的是,他们支持 batched rendering 。那是你们祖国的 chalice !如果说有什么可以在 pyglet 中节省性能的话……好吧……一般来说,3D 渲染就是批量渲染。
看,显卡的设计考虑到了一件事......采用一个巨大的数学方程并将其整个吞下。它特别擅长获取大量信息并将其拍摄到屏幕上。它不擅长执行多个命令。这意味着,如果您将许多较小的数据包发送回和第四个到显卡,由于开销和其他因素,它将执行接近最佳的无磨损。
因此,将图像放入 Sprite 中,并将这些 Sprite 放入批处理中,而不使用任何 for 循环和渲染资源加载..
这就是您的代码的样子:
class Main(object):
def __init__(self):
self.label = pyglet.text.Label('Pizzas: 0', font_size=100, color=(0, 0, 0, 255),
x=win_width//2, y=win_height - 100,
anchor_x='left', anchor_y='top')
self.points = 0
self.number = 1
self.background_layer = pyglet.graphics.OrderedGroup(0)
self.foreground_layer = pyglet.graphics.OrderedGroup(1)
self.batch = pyglet.graphics.Batch()
self.background_img = pyglet.sprite.Sprite(pyglet.resource.image('pizza_clicker.png'), batch=self.batch, group=self.background_layer)
self.background_img.width = (win_width/5)*4
self.background_img.height = win_height
self.background.x = int(win_width/5)
self.background.y = 0
sidebar_pattern = pyglet.image.SolidColorImagePattern(color=(100, 100, 100, 100))
self.sidebar = pyglet.sprite.Sprite(sidebar_pattern.create_image(width, height), batch=self.batch, group=self.background_layer)
self.sidebar.x = 0
self.sidebar.y = 0
self.pizzas = []
width = int(win_width/5)
height = int(win_height)
self.pizza_images = ('pizza_1.png', 'pizza_5.png', 'pizza_5.png', 'pizza_5.png')
for i in range (0, len(pizza_images)):
divideby = 1.4 / (i + 1)
resource = pyglet.sprite.Sprite(pyglet.resource.image(pizza_images[i]), batch=self.batch, group=self.foreground_layer)
resource.width = width
resource.height = round(width/1.4, 1) # Not sure why you're using width here.. meh.. keeping it -yolo-
resource.x = 0
resource.y = window.height - (round(width/divideby, 1))
self.pizzas.append(resource)
def draw(self):
# This is instead of doing:
# - self.background.draw()
# - self.sidebar.draw()
# - self.pizzas[i].draw()
self.batch.draw()
self.label.draw() # You could put this in a batch as well :)
def getNumber(self, y):
if y > window.height - int(image_height):
self.number = 1
elif y > window.height - (int(image_height)*2):
self.number = 5
elif y > window.height - (int(image_height)*3):
self.number = 10
elif y > window.height - (int(image_height)*4):
self.number = 20
def addPoint(self):
self.points += self.number
self.label.text = 'Pizzas: %s' %self.points
@window.event
def on_draw():
window.clear()
main.draw()
现在,代码并不完美。但它有望让您了解您应该走向的方向。我也没有执行这段代码,主要是因为我没有所有的披萨图像或时间。我可能会回到这里这样做,并整理我有的(最有可能的)拼写错误。
关于python - Pyglet 应用程序运行缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51098711/
我正在使用Python 2.6.6和pyglet 1.1.4。在我的“Erosion”文件夹中,有“Erosion.py”和一个名为“Images”的文件夹。在图像内部,有.png图像。一幅图像被命名
我有一个奇怪的问题。当 pyglet 应用程序启动时,它只绘制 1-2 帧然后卡住。 on_draw 事件刚刚停止发生。但是每次我移动鼠标或按键时,on_draw 事件也会调度。简而言之,我必须移动鼠
我有一个应用程序正在创建名为 Pizza Clicker 的 Cookie Clicker 的替代版本。它非常基本,但运行速度非常慢,我不明白为什么。 import pyglet window = p
因此,在我们的游戏中使用 Tkinter 后,我们决定转向 Pyglet。但我遇到的问题之一是运动,在 Tkinter 中我能够制作一个平滑的运动系统,但在 pyglet 中我所能做的就是让角色以一种
我正在使用 pyglet 的 Player 类在 python 中编写一个音频播放器。该模块只是对 Player 和 Source 类的测试,它不会产生任何结果。没有声音,没有错误,只有一个关于垂直同
我正在尝试使用 pyglet 制作一个简单的 GUI。 这是我的代码: button_texture = pyglet.image.load('button.png') button = pyglet
考虑以下示例: import pyglet def foo(): print("I'm in a loop...") def main(): w = pyglet.window.Win
我正在使用 pyglet (OpenGL) 库,我希望能够在不改变窗口大小的情况下改变虚拟分辨率。例如,一个 2x2 的框将在屏幕上绘制为 4x4 像素。我知道我可以找到正在绘制的所有内容并单独对其进
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
我非常喜欢 pyglet,但是抽象的基本单位是坐标向量,这很笨拙,而且不是我在设计复杂场景时想要的抽象级别。 是否有任何库“通常”与 pyglet 一起使用来管理形状并将它们组合到场景中?每个人都从头
我有一个用于在屏幕上显示文本的标签元素: nameLabel = pyglet.text.Label(name, font_name='Tahoma', x=50, y=50, font_size=1
我正在使用 pyglet 编写心理物理学实验。我使用的电脑有两个显示器。它们被配置为两个独立的 Xscreens,0 和 1,分别对应于我的工作站监视器和实验屏幕。我想让 pyglet 绘制到实验屏幕
在我使用 Python 和 pyglet 的游戏中,我有将事件向下传播到其成员的组: class Group(EventDispatcher): def __init__(self):
我制作了两个立方体视口(viewport),但它们都是正面正交投影,我需要其中一个来自侧面。这是绘图代码draw_small 正在绘制小型静态立方体dwar_big是大立方体的绘制,可以移动、缩放和旋
我目前正在开发一个项目,我一直在尝试将 pyglet 库中的标签字体更改为我在网上找到的字体,但我无法让它工作。我尝试在网上搜索一个小时,但似乎没有任何效果。添加了一些代码供引用: font.add_
所以我是一名 Python 初学者程序员,我一直在使用 pyglet,如果您运行此代码,我发现了一个问题: from pyglet.gl import * window = pyglet.window
我已经阅读了我能找到的所有内容,并查看了 pyglet 上游戏循环的许多示例,但我仍然不确定它是如何工作的或到底发生了什么。 (这些是我读过的文章...) http://www.pyglet.org/
我正在使用 Pyglet,并且我有一个包含在背景上移动的对象的小东西。它们都由图像(png 和 jpg)表示。 我创建了一个大小为 800x600 的非全屏窗口,它工作正常,但是当我切换到全屏时...
好吧,所以我对 pyglet 和 OpenGL 来说都是个新手,我想知道为什么这不起作用: def DrawCircle(cx, cy, r, segments): theta = 2*3.14159
我正在尝试使用 Pyglet 通过 OpenGL 渲染图像。到目前为止,我已经能够设置帧缓冲区和纹理、渲染到其中并将其保存为 PNG 图像。但我不知道如何使用 Pyglets 字体渲染。 import
我是一名优秀的程序员,十分优秀!