Re: [pygame] Drawing efficiency question

2022-03-02 Thread Irv Kalb
Hi,

Thanks to everyone for the suggestions.  Many different things to try out.  
I'll probably start by eliminating all my checks and see how that goes first.

Irv

> On Mar 1, 2022, at 3:02 PM, Irv Kalb  wrote:
> 
> I am developing a game but I'm running into some cases where the game slows 
> down too much.  A few details ...
> 
> The game lives in a world whose size is much larger than what the user can 
> see in the window.  (For now, the world is 3000 x 3000, but the window is 640 
> x 640 - I could decide to change these later).  There is a central player who 
> is controlled by arrow keys.  When the user presses a key or keys to move in 
> a direction, the player is an animation that looks like its walking, but 
> always stays in the center of the screen - the view in the window scrolls in 
> the opposite direction.  There are "enemies" that live in this world, new 
> ones are generated all the time, and each moves semi-randomly in every frame. 
>  There are also a number of additional elements that must be drawn every 
> frame (e.g., walls in a maze and more).
> 
> The game is complicated by the fact that the world wraps around both 
> horizontally and vertically.  If you move off the top, you show up at the 
> bottom, go off the left and you appear on the right, etc.  In my current 
> version, in every frame I iterate through all drawable elements, and go 
> through some coordinate checking code to determine if the element is visible 
> within the window.  This code is more complicated than a simple 
> "colliderect()" because I have to account for the potential wrapping in all 
> directions.  If the element is within the viewable screen area, I draw it 
> (blit), otherwise, I don't do the draw.  I thought this would be a great 
> optimization.  But, I'm finding that as the number of enemies grows, the 
> overall game slows down.  I'm sure this has to do with the fact that in every 
> frame I check their movement (they cannot go through walls), move each to a 
> new location, and then decide whether to draw them or not.
> 
> I'm wondering if my code to check if an element is within the viewable area, 
> is actually doing more work than not bothering to check at all.  My question 
> is really about the efficiency of a call to blit in pygame when the thing 
> being drawn is outside the viewable area.  I actually have done some minor 
> tests, and the game seems to work a little better without doing the checking, 
> but I want to get opinions from anyone who might really know.
> 
> I will probably wind up limiting the number of enemies, but it would be good 
> to know about how efficiently pygame deals with potentially drawing outside 
> the window.
> 
> Thanks in advance,
> 
> Irv
> 
> 
> 



Re: [pygame] Drawing efficiency question

2022-03-02 Thread Paul Vincent Craven
Drawing thousands of sprites is pretty quick with OpenGL, but much harder
with Pygame. If you draw stationary sprites to a surface once, then draw
that surface to the screen each frame you can avoid a lot of drawing calls.

If collision detection is slowing you down, you can use something like a
SpatialHash to only check sprites that are near you.

The Arcade library has this stuff baked in, and as it is open source you
could always look at it to get ideas.

Paul Vincent Craven


On Wed, Mar 2, 2022 at 4:47 AM rockachu2  wrote:

> Perhaps you should reconsider your decision not to use a simple
> colliderect. It'd be much more efficient (as the general case is
> certainly not a high number of entities on the edge of the screen) to
> .colliderect() with the edges of the map, and process those specially.
>
> Also beware drawing very large amounts that you do not need to.
> Blit()ing onto a large surface, which you then display, will draw all
> the pixels each frame even if they are not visible. blit() accepts a
> rect argument to limit drawing, which you can take advantage of. You can
> also get away with not drawing a very large amount of pixels each frame
> by "erasing" underneath moving sprites.
>
> I would also second the request for you to profile. Often, performance
> bottlenecks in python are nonobvious. Lots of code that might look
> expensive is fast because it operates in optimized C, and code that
> looks innocent is actually slow because it is doing something behind the
> scenes that you do not expect.
>
> Wall collision code is often complicated and suspect.
>
>
> On 3/1/22 15:02, Irv Kalb wrote:
> > I am developing a game but I'm running into some cases where the game
> slows down too much.  A few details ...
> >
> > The game lives in a world whose size is much larger than what the user
> can see in the window.  (For now, the world is 3000 x 3000, but the window
> is 640 x 640 - I could decide to change these later).  There is a central
> player who is controlled by arrow keys.  When the user presses a key or
> keys to move in a direction, the player is an animation that looks like its
> walking, but always stays in the center of the screen - the view in the
> window scrolls in the opposite direction.  There are "enemies" that live in
> this world, new ones are generated all the time, and each moves
> semi-randomly in every frame.  There are also a number of additional
> elements that must be drawn every frame (e.g., walls in a maze and more).
> >
> > The game is complicated by the fact that the world wraps around both
> horizontally and vertically.  If you move off the top, you show up at the
> bottom, go off the left and you appear on the right, etc.  In my current
> version, in every frame I iterate through all drawable elements, and go
> through some coordinate checking code to determine if the element is
> visible within the window.  This code is more complicated than a simple
> "colliderect()" because I have to account for the potential wrapping in all
> directions.  If the element is within the viewable screen area, I draw it
> (blit), otherwise, I don't do the draw.  I thought this would be a great
> optimization.  But, I'm finding that as the number of enemies grows, the
> overall game slows down.  I'm sure this has to do with the fact that in
> every frame I check their movement (they cannot go through walls), move
> each to a new location, and then decide whether to draw them or not.
> >
> > I'm wondering if my code to check if an element is within the viewable
> area, is actually doing more work than not bothering to check at all.  My
> question is really about the efficiency of a call to blit in pygame when
> the thing being drawn is outside the viewable area.  I actually have done
> some minor tests, and the game seems to work a little better without doing
> the checking, but I want to get opinions from anyone who might really know.
> >
> > I will probably wind up limiting the number of enemies, but it would be
> good to know about how efficiently pygame deals with potentially drawing
> outside the window.
> >
> > Thanks in advance,
> >
> > Irv
> >
> >
> >
>


Re: [pygame] Drawing efficiency question

2022-03-02 Thread rockachu2
Perhaps you should reconsider your decision not to use a simple 
colliderect. It'd be much more efficient (as the general case is 
certainly not a high number of entities on the edge of the screen) to 
.colliderect() with the edges of the map, and process those specially.


Also beware drawing very large amounts that you do not need to. 
Blit()ing onto a large surface, which you then display, will draw all 
the pixels each frame even if they are not visible. blit() accepts a 
rect argument to limit drawing, which you can take advantage of. You can 
also get away with not drawing a very large amount of pixels each frame 
by "erasing" underneath moving sprites.


I would also second the request for you to profile. Often, performance 
bottlenecks in python are nonobvious. Lots of code that might look 
expensive is fast because it operates in optimized C, and code that 
looks innocent is actually slow because it is doing something behind the 
scenes that you do not expect.


Wall collision code is often complicated and suspect.


On 3/1/22 15:02, Irv Kalb wrote:

I am developing a game but I'm running into some cases where the game slows 
down too much.  A few details ...

The game lives in a world whose size is much larger than what the user can see in the 
window.  (For now, the world is 3000 x 3000, but the window is 640 x 640 - I could decide 
to change these later).  There is a central player who is controlled by arrow keys.  When 
the user presses a key or keys to move in a direction, the player is an animation that 
looks like its walking, but always stays in the center of the screen - the view in the 
window scrolls in the opposite direction.  There are "enemies" that live in 
this world, new ones are generated all the time, and each moves semi-randomly in every 
frame.  There are also a number of additional elements that must be drawn every frame 
(e.g., walls in a maze and more).

The game is complicated by the fact that the world wraps around both horizontally and 
vertically.  If you move off the top, you show up at the bottom, go off the left and you 
appear on the right, etc.  In my current version, in every frame I iterate through all 
drawable elements, and go through some coordinate checking code to determine if the 
element is visible within the window.  This code is more complicated than a simple 
"colliderect()" because I have to account for the potential wrapping in all 
directions.  If the element is within the viewable screen area, I draw it (blit), 
otherwise, I don't do the draw.  I thought this would be a great optimization.  But, I'm 
finding that as the number of enemies grows, the overall game slows down.  I'm sure this 
has to do with the fact that in every frame I check their movement (they cannot go 
through walls), move each to a new location, and then decide whether to draw them or not.

I'm wondering if my code to check if an element is within the viewable area, is 
actually doing more work than not bothering to check at all.  My question is 
really about the efficiency of a call to blit in pygame when the thing being 
drawn is outside the viewable area.  I actually have done some minor tests, and 
the game seems to work a little better without doing the checking, but I want 
to get opinions from anyone who might really know.

I will probably wind up limiting the number of enemies, but it would be good to 
know about how efficiently pygame deals with potentially drawing outside the 
window.

Thanks in advance,

Irv





RE: [pygame] Drawing efficiency question

2022-03-02 Thread Yann Thorimbert
If the ennemies are generated randomly, and if you are sure they are the 
bottleneck of the FPS, you could generate them dynamically as the character 
progresses through the world.


Otherwise, you can divide your world in multiples rects the size of the screen, 
and link each ennemy to the "screen" to which it belongs. Ennemies are then 
woke up when the actual screen approaches the rect of the ennemy, allowing you 
to double-loop over a domain with side size 600 times smaller approximately.


(well I wrote "ennemies" but of course this applies to any element that is more 
or less static with respect to the map)


De : owner-pygame-us...@seul.org  de la part de 
Rick van der Meiden 
Envoyé : mercredi, 2 mars 2022 08:42
À : pygame-users@seul.org
Objet : Re: [pygame] Drawing efficiency question

As your world gets bigger and has more objects, your game will slow down even 
more. (Even if you directly use openGL, I suspect, although I haven't used it 
myself). You will need a spatial index. I have some code that i'm willing to 
share, if you're interested (or anyone else here, drop me a line). You can 
probably find some other code on the web or you can code your own spatial 
index, it's not that hard and it's a good exercise.

Rick.


On Wed, 2 Mar 2022, 00:10 Irv Kalb, 
mailto:i...@furrypants.com>> wrote:
I am developing a game but I'm running into some cases where the game slows 
down too much.  A few details ...

The game lives in a world whose size is much larger than what the user can see 
in the window.  (For now, the world is 3000 x 3000, but the window is 640 x 640 
- I could decide to change these later).  There is a central player who is 
controlled by arrow keys.  When the user presses a key or keys to move in a 
direction, the player is an animation that looks like its walking, but always 
stays in the center of the screen - the view in the window scrolls in the 
opposite direction.  There are "enemies" that live in this world, new ones are 
generated all the time, and each moves semi-randomly in every frame.  There are 
also a number of additional elements that must be drawn every frame (e.g., 
walls in a maze and more).

The game is complicated by the fact that the world wraps around both 
horizontally and vertically.  If you move off the top, you show up at the 
bottom, go off the left and you appear on the right, etc.  In my current 
version, in every frame I iterate through all drawable elements, and go through 
some coordinate checking code to determine if the element is visible within the 
window.  This code is more complicated than a simple "colliderect()" because I 
have to account for the potential wrapping in all directions.  If the element 
is within the viewable screen area, I draw it (blit), otherwise, I don't do the 
draw.  I thought this would be a great optimization.  But, I'm finding that as 
the number of enemies grows, the overall game slows down.  I'm sure this has to 
do with the fact that in every frame I check their movement (they cannot go 
through walls), move each to a new location, and then decide whether to draw 
them or not.

I'm wondering if my code to check if an element is within the viewable area, is 
actually doing more work than not bothering to check at all.  My question is 
really about the efficiency of a call to blit in pygame when the thing being 
drawn is outside the viewable area.  I actually have done some minor tests, and 
the game seems to work a little better without doing the checking, but I want 
to get opinions from anyone who might really know.

I will probably wind up limiting the number of enemies, but it would be good to 
know about how efficiently pygame deals with potentially drawing outside the 
window.

Thanks in advance,

Irv





Re: [pygame] Drawing efficiency question

2022-03-01 Thread Rick van der Meiden
As your world gets bigger and has more objects, your game will slow down
even more. (Even if you directly use openGL, I suspect, although I haven't
used it myself). You will need a spatial index. I have some code that i'm
willing to share, if you're interested (or anyone else here, drop me a
line). You can probably find some other code on the web or you can code
your own spatial index, it's not that hard and it's a good exercise.

Rick.


On Wed, 2 Mar 2022, 00:10 Irv Kalb,  wrote:

> I am developing a game but I'm running into some cases where the game
> slows down too much.  A few details ...
>
> The game lives in a world whose size is much larger than what the user can
> see in the window.  (For now, the world is 3000 x 3000, but the window is
> 640 x 640 - I could decide to change these later).  There is a central
> player who is controlled by arrow keys.  When the user presses a key or
> keys to move in a direction, the player is an animation that looks like its
> walking, but always stays in the center of the screen - the view in the
> window scrolls in the opposite direction.  There are "enemies" that live in
> this world, new ones are generated all the time, and each moves
> semi-randomly in every frame.  There are also a number of additional
> elements that must be drawn every frame (e.g., walls in a maze and more).
>
> The game is complicated by the fact that the world wraps around both
> horizontally and vertically.  If you move off the top, you show up at the
> bottom, go off the left and you appear on the right, etc.  In my current
> version, in every frame I iterate through all drawable elements, and go
> through some coordinate checking code to determine if the element is
> visible within the window.  This code is more complicated than a simple
> "colliderect()" because I have to account for the potential wrapping in all
> directions.  If the element is within the viewable screen area, I draw it
> (blit), otherwise, I don't do the draw.  I thought this would be a great
> optimization.  But, I'm finding that as the number of enemies grows, the
> overall game slows down.  I'm sure this has to do with the fact that in
> every frame I check their movement (they cannot go through walls), move
> each to a new location, and then decide whether to draw them or not.
>
> I'm wondering if my code to check if an element is within the viewable
> area, is actually doing more work than not bothering to check at all.  My
> question is really about the efficiency of a call to blit in pygame when
> the thing being drawn is outside the viewable area.  I actually have done
> some minor tests, and the game seems to work a little better without doing
> the checking, but I want to get opinions from anyone who might really know.
>
> I will probably wind up limiting the number of enemies, but it would be
> good to know about how efficiently pygame deals with potentially drawing
> outside the window.
>
> Thanks in advance,
>
> Irv
>
>
>
>


Re: [pygame] Drawing efficiency question

2022-03-01 Thread Jasper Phillips
I've dealt with this in my own game, handling thousands of such drawn
elements. Based on that I have two general suggestions:

1) If you've got performance bottlenecks, very often they aren't where one
first suspects! Better to break out a profiler and measure. That said, I
don't have any experience with Python profilers because I don't have speed
issues, largely because of the next point...

2) The sort of optimizations you're trying are laborious, fragile, and
error prone. It sounds like you're using Pygame directly for 2D? If so, you
can vastly simplify things by switching to PyOpenGL underneath, using 3D
with a 2D "orthographic" projection. This both takes advantage of the GPU,
and simplifies your code because the paradigm handles all the things you're
worried about -- you simply set up what needs to be drawn, change their
position when needed... and that's it. Blitting is expensive, and with
OpenGL you can just avoid it.

There's a bit of up front learning cost if you're not familiar with these
tools, but the payoff comes quickly and is well worth it.

-Jasper

On Tue, Mar 1, 2022 at 3:10 PM Irv Kalb  wrote:

> I am developing a game but I'm running into some cases where the game
> slows down too much.  A few details ...
>
> The game lives in a world whose size is much larger than what the user can
> see in the window.  (For now, the world is 3000 x 3000, but the window is
> 640 x 640 - I could decide to change these later).  There is a central
> player who is controlled by arrow keys.  When the user presses a key or
> keys to move in a direction, the player is an animation that looks like its
> walking, but always stays in the center of the screen - the view in the
> window scrolls in the opposite direction.  There are "enemies" that live in
> this world, new ones are generated all the time, and each moves
> semi-randomly in every frame.  There are also a number of additional
> elements that must be drawn every frame (e.g., walls in a maze and more).
>
> The game is complicated by the fact that the world wraps around both
> horizontally and vertically.  If you move off the top, you show up at the
> bottom, go off the left and you appear on the right, etc.  In my current
> version, in every frame I iterate through all drawable elements, and go
> through some coordinate checking code to determine if the element is
> visible within the window.  This code is more complicated than a simple
> "colliderect()" because I have to account for the potential wrapping in all
> directions.  If the element is within the viewable screen area, I draw it
> (blit), otherwise, I don't do the draw.  I thought this would be a great
> optimization.  But, I'm finding that as the number of enemies grows, the
> overall game slows down.  I'm sure this has to do with the fact that in
> every frame I check their movement (they cannot go through walls), move
> each to a new location, and then decide whether to draw them or not.
>
> I'm wondering if my code to check if an element is within the viewable
> area, is actually doing more work than not bothering to check at all.  My
> question is really about the efficiency of a call to blit in pygame when
> the thing being drawn is outside the viewable area.  I actually have done
> some minor tests, and the game seems to work a little better without doing
> the checking, but I want to get opinions from anyone who might really know.
>
> I will probably wind up limiting the number of enemies, but it would be
> good to know about how efficiently pygame deals with potentially drawing
> outside the window.
>
> Thanks in advance,
>
> Irv
>
>
>
>


Re: [pygame] Drawing efficiency question

2022-03-01 Thread Greg Ewing
On 2/03/22 12:02 pm, Irv Kalb wrote:> I'm wondering if my code to check 
if an element is within the viewable area, is actually doing more work 
than not bothering to check at all.


If the drawing of each object is just a blit call, then your checks are
probably just duplicating what pygame is already doing itself much more
efficiently.

The only way to find out for sure is to try it, which it sounds like
you've already done and found it only makes a small difference.

To do better you'll need some kind of spatial index to quickly find
objects that might be in view. A simple way would be to divide the
world into a grid of cells, each one about the size of the window,
and maintain a collection of objects in each cell. Then you can
draw just the objects in cells that overlap the window.

--
Greg


Re: [pygame] Drawing efficiency question

2022-03-01 Thread Andrew Baker
Typically, entities outside of the viewable area may not be updates or may
update at a much reduced frequency.  This is true of even C++ games.

On Tue, Mar 1, 2022, 3:10 PM Irv Kalb  wrote:

> I am developing a game but I'm running into some cases where the game
> slows down too much.  A few details ...
>
> The game lives in a world whose size is much larger than what the user can
> see in the window.  (For now, the world is 3000 x 3000, but the window is
> 640 x 640 - I could decide to change these later).  There is a central
> player who is controlled by arrow keys.  When the user presses a key or
> keys to move in a direction, the player is an animation that looks like its
> walking, but always stays in the center of the screen - the view in the
> window scrolls in the opposite direction.  There are "enemies" that live in
> this world, new ones are generated all the time, and each moves
> semi-randomly in every frame.  There are also a number of additional
> elements that must be drawn every frame (e.g., walls in a maze and more).
>
> The game is complicated by the fact that the world wraps around both
> horizontally and vertically.  If you move off the top, you show up at the
> bottom, go off the left and you appear on the right, etc.  In my current
> version, in every frame I iterate through all drawable elements, and go
> through some coordinate checking code to determine if the element is
> visible within the window.  This code is more complicated than a simple
> "colliderect()" because I have to account for the potential wrapping in all
> directions.  If the element is within the viewable screen area, I draw it
> (blit), otherwise, I don't do the draw.  I thought this would be a great
> optimization.  But, I'm finding that as the number of enemies grows, the
> overall game slows down.  I'm sure this has to do with the fact that in
> every frame I check their movement (they cannot go through walls), move
> each to a new location, and then decide whether to draw them or not.
>
> I'm wondering if my code to check if an element is within the viewable
> area, is actually doing more work than not bothering to check at all.  My
> question is really about the efficiency of a call to blit in pygame when
> the thing being drawn is outside the viewable area.  I actually have done
> some minor tests, and the game seems to work a little better without doing
> the checking, but I want to get opinions from anyone who might really know.
>
> I will probably wind up limiting the number of enemies, but it would be
> good to know about how efficiently pygame deals with potentially drawing
> outside the window.
>
> Thanks in advance,
>
> Irv
>
>
>
>