function spiking usage only first time called

Has anyone experienced a situation where some function you’ve written causes a spike the first time you run it in game, but not otherwise?

There’s a function that is basically a spell function, it does a bunch of hooha. I thought the spike was coming from the animation (multiple animated texture planes coming from an emitter) but after using the spell (function) a second, third, etc time the spike doesn’t occur.

I’m curious why that happens or at least SEEMS to happen.

The spike seems to be in the logic usage, but I’ll check again

loading the sprite objects?

I didn’t realize it had to appear on screen once through an add object call to be considered ‘loaded’, i figured it was just ‘loaded’ already

only if you spawn an instance and then kill it I think behind the camera somewhere on frame 1 etc it may fix that :smiley:

Thanks I was just thinking about that

So i have my logic ticker at 50 and this finishes in about 12 seconds on my computer with the frame rate dropping to 12 at the lowest and averaging at around 40, with probably 20~+ sprites with probably an average of 40 tiles per sprite animation

def sprite_list():
    list = []
    for object in logic.getSceneList()[0].objectsInactive:
            
            if 'sprite' in object:
                list.append(object)
                
    return list
    




def load_sprites():
     #by moving this world location line to the 'first frame' script, it seems to have made a bit of a difference
    logic.getSceneList()[0].objects['AssetsLevelSpawn'].worldPosition = [0,512,-512]
    
    cont = logic.getCurrentController()
    own = cont.owner
    
    
    
    if own['sprites'] == False:
    
        if own['counter'] < len(sprite_list()):
                        
            logic.getSceneList()[0].addObject(sprite_list()[own['counter']],logic.getSceneList()[0].objects['AssetsLevelSpawn'],200)  
            own['counter'] += 1
        
        else:
            own['sprites'] = True              
         
        
    
    if own['sprites'] == True:  
        logic.getSceneList()[0].objects['AssetsLevelSpawn'].worldPosition = [0,0,0]       
        spawn_local_level()
        own.endObject()

With the Benchmark tests I noticed that addObject() can result in more processing time, which spreads other several frames.

The Benchmark run adds a bunch of equal objects (e.g. 100). It adds the next bunch when the current frame rate stays below 60 for a given amount of time. The framerate is plotted to the console and shows the BGE needs quite a few frames to “recover”.

To me this is not unexpected as the scene graph gets modified and quite some management should happen. I just wonder why it spreads over several frames. Over all it was never problematic as long as the overall performance was fine. It is the goal of the benchmark to find the limits.

I’m not sure if that fits your situation

Remarks:

  • You do no need “if own[‘sprites’] == False” you can simply write “if not own[‘sprites’]:”. Similar the positive check: “if own[‘sprites’]:” in your case an “else:” would be sufficient too.
  • You can include an existence check too. “if not own.get(‘sprites’):” considers non-existence the same way as False.
  • As the property does not contain sprites I suggest to call it “sprites enabled” or similar.
  • You call sprites_list() twice, which let the code search the scene twice with the same result. Caching the first result in a variable is more efficient without a functional change.
  • I recommend getCurrentScene() rather than getSceneList()[0]. When you get overlay and background scenes the first scene is not necessarily the current one. Your code would fail as you can only copy objects from within the same scene the code is running in.
  • You can also use object names within addObject(). The bge will search the current scene for you the same way your code is doing it right now. This can make your code a bit simpler.

I hope it helps a bit

Thank you, your post definitely reminded me of a few things like the .getMethod which I never use. That being said, not really sure how to implement it in my situation as you suggest.

can you ever use ‘not’ in the case where something isnt a boolean? I feel like that is why i usually write out false and true; because i end up not being sure what x variable /is not/, you know what I mean?

i do see that I call sprites_list twice, so thanks for pointing that out.
but I thought that even if i cache as a variable, say

cahce = list_return_function()

that cache would technically just call the function everytime i wrote cache

as for the getCurrentScene thing, (while Im sure there’s a better way to do what I’ve done), I was actually having problems with that like months ago when I started doing python for BGE, and i just started using the scene by index and it hasn’t given me any trouble since

Caching search results
Holding the function in a variable will not help you here as it will still run twice as you have two calls to it.

i mean it like this:


...
        sprites = sprite_list()
        if own['counter'] < len(sprites): # first usage
            # second usage
            logic.getSceneList()[0].addObject(sprites[own['counter']],logic.getSceneList()[0].objects['AssetsLevelSpawn'],200)  
            own['counter'] += 1
        
        else:
            own['sprites'] = True              
...

Repeating the search makes sense when you can’t be sure the list changed between the usages and you want to get the updated list. This is not the case in your situation. It would be the case if you add or remove objects between the two usages.

Condition checking
When you are sure your property contains boolean values only, you do not need to explicit check for them. The “if” statement always expect a boolean condition.


a = True
if a:
   print("a was validated to True - one operation")

if a == True:
  print("a was compered against True, which is validated against True - two operations")

But there are more things to consider. In Python a validation expression as well as a compare operation include implicit type conversion. Therefore:

  • True -> True
  • False -> False
  • None -> False
  • 1 -> True
  • 1.0 -> True
  • other number -> False
  • String -> False
  • empty collection (list, dict) -> False
  • non-empty collection -> True

Get()
In your situation you should only get (and expect) a boolean value. Otherwise you get incorrect data in that property.

using get() is pretty straight-forward:


    if not own.get('sprites'):

I suggest to use this when the property is optional. Use the [] syntax when the property is mandatory (must exist before the call).

Get is a mighty tool. The real call is:
get(key, defaultvalue=None)

This means you can do things like that:


   if not own.get('sprites', False):

...
   count = own.get('counter', 0)

Be aware it returns a default value, it will not create a property. The property will still not be present, but you have a value you can process with.

Before you go and replace all [] with get() - creating a default value needs processing power. The default value will only be needed when the property is not present. You need to take into account the processing time of creating the default vs. the time you really need it. This means complex default values (like lists, custom classes) should be avoided for efficiency. In this case the [] syntax is better even when it requires additional verification checks.

thank you for the thing about python type conversions for expression validation! thank you thank you