Reputation: 788
I'm trying to get a code to print small rectangles all over my screen in pygame with the help of for loops, but having trouble. I have solved parts of it with this code but it looks ugly and preforms bad:
x = 0
y = 0
for y_row in range(60):
y = y + 10
pygame.draw.rect(screen, GREEN, [x, y, 5, 5], 0)
for x_row in range(70):
pygame.draw.rect(screen, GREEN, [x, y, 5, 5], 0)
x = x + 10
x = 0
To start of, I do not believe I have to assign a value to x and y if I just can figure out how to implement the value of y_row and x_row at x and y's places instead, now it increases with 1, it should increase with 10, than I can implement it instead.
Another problem with the code is that it leaves a blank row at the top, this is because I had to add the y = y + 10 above the pygame draw, otherwise it just printed one rectangle there witch made it more visible.
The template I'm using to get the code working you can find Here.
Upvotes: 2
Views: 2154
Reputation: 2549
Drawing 4,200 rectangles to the screen every 60th of a second is probably a significant task for the CPU. I suspect that the pygame.draw.rect()
function is fairly high-level and calls are not batched by pygame making it sub-optimal, there is a hint in the documentation (https://www.pygame.org/docs/ref/draw.html#pygame.draw.rect) that Surface.fill(color, rect=None, special_flags=0)
can be hardware accelerated and may be a faster option if you're filling the rectangles.
Note: the code examples below are pseudo ... just means you need to fill in the gaps.
You only need 1 call to pygame.draw.rect
per iteration of the loop not 2 as you have now, e.g.
for row in rows:
y = ...
for col in cols:
x = ...
... draw rect ...
One easy win for performance is to not draw anything that's off-screen, so test your x
, y
coordinates before rendering, e.g:
screen_width = 800
screen_height = 600
for ...
y = y += 10
if y > screen_height:
break
for ...
x += 10
if x > screen_width:
break
... draw block ...
The same approach could also be used (with a continue
) to implement an offset (e.g a starting offset_x
, offset_y
value) where rectangles with negative x
, y
values are not rendered (the test is not x < 0
however, but x < -block_size
).
There's nothing wrong with calculating the x
and y
values from a loop index as you are doing, it's often useful to have an index (for example the index [row][col]
might give you the location of data for a tile in a 2D matrix representing game tiles). I would calculate the x
, y
values myself from the indexes using a multiplier (this also solves the blank first row issue):
block_size = 10
for row in ...
y = row * block_size
if y > screen_height:
break
for col in ...
x = col * block_size
if x > screen_width:
break
... draw block ...
If you're using Python2 then you might consider using xrange
to predefine the loop ranges to improve performance (though I imagine only a small amount and as always with optimization testing the performance difference is key). For example:
rows = xrange(60)
cols = xrange(70)
for row in rows:
...
for cols in cols:
... draw block ...
Upvotes: 2
Reputation: 4017
As @bshuster13 mentioned you can use pythons range()
function and pass an optional step and stop argument to create a list containing arithmetic progressions.
numberOfRows = 60
numberOfColumns = 70
stepBetweenRects = 10
for y in range(0, numberOfRows * stepBetweenRects, stepBetweenRects):
for x in range(0, numberOfColumns * stepBetweenRects, stepBetweenRects):
pygame.draw.rect(screen, GREEN, (x, y, 5, 5), 0)
Upvotes: 2