0
\$\begingroup\$

I'm using Pygame for Python 2 and I have the following code:

self.radius = 100
self.light = pygame.Surface((2*self.radius, 2*self.radius), pygame.SRCALPHA)
self.light.fill((0, 0, 0, 0))
pygame.draw.circle(self.light, (255, 255, 255), (self.radius, self.radius), self.radius)
alphas = pygame.surfarray.pixels_alpha(self.light)
for x, col in enumerate(alphas):
    for y, pixel in enumerate(col):
        pixel = 255 - f.distance(pygame.Rect(x, y, 1, 1), pygame.Rect(self.radius, self.radius, 1, 1))

Basically this code creates a new surface, makes it transparent so that it doesn't interfere with the background, draws a circle on it, and then makes two nested for cycles, going through all of the pixels. The problem is, these fors are too slow. How can I improve their performance?

\$\endgroup\$
  • 1
    \$\begingroup\$ Can you explain what those 2 for loops are doing? What is "f"? Why do you need to process every pixel? What are you trying to accomplish? Maybe you chose the wrong way to do it. \$\endgroup\$ – Candid Moon _Max_ Mar 1 '17 at 0:45
  • \$\begingroup\$ I'm trying to make a light in the game. To do it, I'm making a circle, and using those for loops to change all of the pixels' alpha, depending on the distance from the source, so that the light power will become lower and lower until it won't exist anymore when very distant from the center. \$\endgroup\$ – altermetax Mar 1 '17 at 13:28
  • 1
    \$\begingroup\$ Create a texture offline that has all the images representing the shades you need to have and use that instead. Maybe you don't need 256 levels, maybe 16 or 32 would be enough. \$\endgroup\$ – Vaillancourt Mar 1 '17 at 14:18
3
\$\begingroup\$

Your problem here is that this does not work for CPU, it should be done using GPU, probably you can access it in pygame. It's the work of pixel shader and it works on very low level, with thousands of microprocessors that have no memory - that what makes it so fast to process each pixel.

When you are trying to do it in loops - it's complexity is O(n * m), so you are asking your processor to go through 1920 * 1080 items on 1 thread, for example, it's a resolution. Which makes it 2073600 times of CPU cycles, which is quite long. When GPU would take them one by one in 320 threads (it depends on card model) or more. Plus python is very slow in comparison to C or C++, so writing game on it might be quite difficult. Though python is written in C, so maybe there are shaders in pygame - you should check this out.

Can't you use semi-transparent texture for that? Also, you can try to find better algorithm that is probably O(n * log2(m)). I would also limit the amount of pixels to process to only area that pixels can be lit.

And the last thing, if you are changing textures of sprites on the background - it's bad because you would have to turn them back when area is not lit. So it's better to draw some texture over it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.