Re: [pygame] Drawing efficiency question
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] Question about sound effect playback
Sure, though I'm not clear on where that would be in the Python vs SDL boundary. I'm not prepared to go spelunking for it either, at least until I know I need optimization. Ideally pygame's Channel api would be extended to expose this directly! I don't have enough of a feel for pygame's release process to know how feasible that is. On Wed, Jul 14, 2021 at 4:50 PM Andrew Baker wrote: > I'd assume that deep under the hood, one should be able to advance > whatever read pointer to the soundbuffer is used by the channel. > > Is that correct? > > > On Wed, Jul 14, 2021, 15:51 Jasper Phillips > wrote: > >> Thanks Daniel, that works! Plus using soundarray should be faster than >> first converting to raw. >> >> So far I don't need to cache, but rollback netcode demands lots of CPU so >> I suspect I probably will end up optimizing this to improve robustness vs >> lag. >> >> A pity mixer won't let you start Channels partway through a Sound, as >> then there'd be no CPU cost. >> >> On Wed, Jul 14, 2021 at 9:15 AM Daniel Foerster >> wrote: >> >>> Instead of using the raw sound binary data and winging the slice, I'd >>> recommend throwing things into a sndarray. >>> >>> >>> def clip_sound(sound, start_time): >>> freq = pygame.mixer.get_init()[0] >>> offset = round(freq * start_time) >>> arr = pygame.sndarray.array(sound) >>> clipped = arr[offset:] >>> return pygame.sndarray.make_sound(clipped) >>> >>> >>> It would be worthwhile probably to cache the frequency and the converted >>> array and only do the slice + flip back to Sound but that's premature >>> optimization right now. >>> >>> On Wed, Jul 14, 2021, 03:15 Jasper Phillips >>> wrote: >>> >>>> Alas, that is precisely what I did: >>>> >>>> def clipEffect( effect, startTime ): >>>> raw = effect.get_raw() >>>> rawStart = int( len(raw) * startTime / effect.get_length() ) >>>> return mixer.Sound( raw[rawStart:] ) >>>> >>>> Depending on what sound effect I play the code either: >>>> - Works fine! >>>> - Horribly distorts the audio, though the original Sound plays fine... >>>> >>>> Hi Jasper. Try the fourth answer here >>>>> <https://stackoverflow.com/questions/57960451/how-can-i-play-a-portion-of-an-audio-file-in-a-loop-in-pygame>, >>>>> by Ted Klein Bergman. >>>>> On 7/13/2021 4:24 PM, Jasper Phillips wrote: >>>>> >>>>> I'm working on a networked action game with rollback netcode, and so I >>>>> need to play sound effects starting an arbitrary amount of time from the >>>>> beginning of the file so they sync up with game events. >>>>> >>>>> pygame.mixer.music does this via set_pos()... but apparently there's >>>>> no corresponding method when playing effects directly via a Channel. >>>>> Unfortunate, as I need to use Channels! >>>>> >>>>> The best I've come up with is to use Sound.get_raw(), trim the >>>>> starting bytes off then, create a new Sound. But this fails several >>>>> different ways, I'm guessing because I'm arbitrarily slicing the bytes and >>>>> there's some format details I don't know. >>>>> >>>>> >>>>> Does anyone have any tips for hacking raw Sound data, or perhaps some >>>>> better approach? >>>>> >>>>> -Jasper >>>>> >>>>>
Re: [pygame] Question about sound effect playback
Thanks Daniel, that works! Plus using soundarray should be faster than first converting to raw. So far I don't need to cache, but rollback netcode demands lots of CPU so I suspect I probably will end up optimizing this to improve robustness vs lag. A pity mixer won't let you start Channels partway through a Sound, as then there'd be no CPU cost. On Wed, Jul 14, 2021 at 9:15 AM Daniel Foerster wrote: > Instead of using the raw sound binary data and winging the slice, I'd > recommend throwing things into a sndarray. > > > def clip_sound(sound, start_time): > freq = pygame.mixer.get_init()[0] > offset = round(freq * start_time) > arr = pygame.sndarray.array(sound) > clipped = arr[offset:] > return pygame.sndarray.make_sound(clipped) > > > It would be worthwhile probably to cache the frequency and the converted > array and only do the slice + flip back to Sound but that's premature > optimization right now. > > On Wed, Jul 14, 2021, 03:15 Jasper Phillips > wrote: > >> Alas, that is precisely what I did: >> >> def clipEffect( effect, startTime ): >> raw = effect.get_raw() >> rawStart = int( len(raw) * startTime / effect.get_length() ) >> return mixer.Sound( raw[rawStart:] ) >> >> Depending on what sound effect I play the code either: >> - Works fine! >> - Horribly distorts the audio, though the original Sound plays fine... >> >> Hi Jasper. Try the fourth answer here >>> <https://stackoverflow.com/questions/57960451/how-can-i-play-a-portion-of-an-audio-file-in-a-loop-in-pygame>, >>> by Ted Klein Bergman. >>> On 7/13/2021 4:24 PM, Jasper Phillips wrote: >>> >>> I'm working on a networked action game with rollback netcode, and so I >>> need to play sound effects starting an arbitrary amount of time from the >>> beginning of the file so they sync up with game events. >>> >>> pygame.mixer.music does this via set_pos()... but apparently there's no >>> corresponding method when playing effects directly via a Channel. >>> Unfortunate, as I need to use Channels! >>> >>> The best I've come up with is to use Sound.get_raw(), trim the starting >>> bytes off then, create a new Sound. But this fails several different ways, >>> I'm guessing because I'm arbitrarily slicing the bytes and there's some >>> format details I don't know. >>> >>> >>> Does anyone have any tips for hacking raw Sound data, or perhaps some >>> better approach? >>> >>> -Jasper >>> >>>
Re: [pygame] Question about sound effect playback
Alas, that is precisely what I did: def clipEffect( effect, startTime ): raw = effect.get_raw() rawStart = int( len(raw) * startTime / effect.get_length() ) return mixer.Sound( raw[rawStart:] ) Depending on what sound effect I play the code either: - Works fine! - Horribly distorts the audio, though the original Sound plays fine... Hi Jasper. Try the fourth answer here > <https://stackoverflow.com/questions/57960451/how-can-i-play-a-portion-of-an-audio-file-in-a-loop-in-pygame>, > by Ted Klein Bergman. > On 7/13/2021 4:24 PM, Jasper Phillips wrote: > > I'm working on a networked action game with rollback netcode, and so I > need to play sound effects starting an arbitrary amount of time from the > beginning of the file so they sync up with game events. > > pygame.mixer.music does this via set_pos()... but apparently there's no > corresponding method when playing effects directly via a Channel. > Unfortunate, as I need to use Channels! > > The best I've come up with is to use Sound.get_raw(), trim the starting > bytes off then, create a new Sound. But this fails several different ways, > I'm guessing because I'm arbitrarily slicing the bytes and there's some > format details I don't know. > > > Does anyone have any tips for hacking raw Sound data, or perhaps some > better approach? > > -Jasper > >
[pygame] Question about sound effect playback
I'm working on a networked action game with rollback netcode, and so I need to play sound effects starting an arbitrary amount of time from the beginning of the file so they sync up with game events. pygame.mixer.music does this via set_pos()... but apparently there's no corresponding method when playing effects directly via a Channel. Unfortunate, as I need to use Channels! The best I've come up with is to use Sound.get_raw(), trim the starting bytes off then, create a new Sound. But this fails several different ways, I'm guessing because I'm arbitrarily slicing the bytes and there's some format details I don't know. Does anyone have any tips for hacking raw Sound data, or perhaps some better approach? -Jasper