Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Performance issues on subsequent scene reloads. — Gideros Forum

Performance issues on subsequent scene reloads.

AstirianAstirian Member
edited May 2018 in Bugs and issues
Hi guys! I am inches away from releasing my game but the last problem remains.

I've done a pass on the game to minimise GLOBALS, where I have them I localise them before use etc... I've double checked my array loops on onEnterFrame and made sure I'm calling as much as I can on update with self (GameScene).

My issue is that the first round runs relatively well but subsequent retries and further rounds get slower and slower. I'm nilling everything I can get my hands on (GAME, self.world, self.player, self.rt etc...) in the gameOver() but it doesn't seem to be helping.

Is there a clean-up function I can use? Do I need to transition to a different scene first? Or manually mop up every child in self.game before I move?

I'm also calling collectgarbage("collect") on init() and gameOver(), is that a bad idea?

I'm sort of stretching the framework here so I don't have a lot of room to maneuver (lots of getPixel() calls to draw on my render target) but the first scene always behaves itself, it's just the scene reset seems to be holding onto some stuff I guess.
sceneManager:changeScene(scenes[3], 1, SceneManager.fade, easing.linear)

is what I'm using to make the transition to another round or reload the current one.

Comments

  • So, typing stuff out on here seems to help haha! I think I might not be getting rid of all my eventListeners, I'm only calling self:removeEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)...

    I'm guessing sceneManager isn't getting rid of that stuff automagically?

    But if that's the case, does it mean I need to go around killing all my textures and sounds etc...? I would have assumed that's baked into sceneManager...
  • AstirianAstirian Member
    edited May 2018
    Same with bump, if I nil the bump world, does it kill its children? (fun sentence!)
  • I've also got 9 timers and a bunch of those have Event.COMPLETE triggers. Not to mention the events on my touch controls... When a MovieClip finishes should I nil that too? Got a bunch of these as well... chartboost:addEventListener(Event.AD_RECEIVED ...)
  • One last consideration, if I have instantiated NPC classes in ENEMIES, is making ENEMIES = nil sufficient? Or do I need to loop through the array and firstly removeChild() and then set all children to nil?
  • AstirianAstirian Member
    edited May 2018
    OK, last comment, honest. If I do something like this (just for argument's sake):
    self.rt = RenderTarget.new(background:getWidth(), background:getHeight())
    GameScene.renderTarget = self.rt
    If I then subsequently do self.rt = nil then GameScene.renderTarget no longer exists right? As I'm assuming it's pointing to the same object (self.rt) in memory.

    And again, is nilling sufficient or should I be removeChilding it first?
  • antixantix Member
    Accepted Answer
    @Astirian If you are going to reuse things then you just need to reset them, not destroy them and recreate them. Whenever making reusable classes.. resetting (or cleaning up) them is one of the things you need to build in right from the beginning.

    With bump for example...
    -- remove all items from bump collision world
    local bump = BUMP
    local items, len = bump:getItems()
    if len > 0 then
      for i = 1, len do
        local item = items[i]
        bump:remove(item)
      end
    end
    Personally I would make the RenderTarget a global and localize it when required, but I'm fond of making global vars.. they really arent; the evil they are portrayed to be :D

    For example your enemies class. In my opinion it is so much easier to make it global. I would have something like..
    Enemies = Core.class(Sprite)
     
    function Enemies:init()
      self.actors = {}
      -- other startup stuff goes here
    end
     
    -- dispose of all enemies
    function Enemies:reset()
      local actors = self.actors
      if #actors > 0 then
        for i = actors, 1, -1 do
          local actor = actors[i]
          actor:removeFromParent() -- remove sprite from parent
          -- dispose of other actor stuff here
        end
      self.actors = {} -- our actors list is now empty
      end
    end
     
    -- create a new enemy
    function Enemies:newEnemy(options)
      local actors = self.actors
      local actor = Pixel.new(0xff0000, 1, 32, 32)
      self:addChild(actor)
      -- init other actor stuff here
      actors[#actors + 1] = actor
    end
     
    -- update all enemies
    function Enemies:update(dt)
      local actors = self.actors
      if #actors > 0 then
        for i = actors, 1, -1 do
          local actor = actors[i]
          -- process actor ai etc here
        end
      end
    end
    Then in my main.lua..
    ENEMIES = Enemies.new()
    The ENEMIES can then be reuses an infinite number of times just by calling it's reset() function and then using self.enemies = ENEMIES when you recreate your game scene.

    In your scenes you need to stop all of their listeners. Here is the basic game scene that I use, where I remove my listeners in onTransitionOutBegin()
    Game = Core.class(Sprite)
     
    function Game:init()
      GAME = self -- make this scene a global variable
     
      self:startUp()
     
      self:addEventListener("enterBegin", self.onTransitionInBegin, self)
      self:addEventListener("enterEnd", self.onTransitionInEnd, self)
      self:addEventListener("exitBegin", self.onTransitionOutBegin, self)
      self:addEventListener("exitEnd", self.onTransitionOutEnd, self)
    end
     
    function Game:onTransitionInBegin() -- initialize variables here
    end
     
    function Game:onTransitionInEnd() -- add listeners, start logic
      self:addEventListener(Event.ENTER_FRAME, self.update, self)
    end
     
    function Game:onTransitionOutBegin() -- stop timers, remove listeners
      self:removeEventListener(Event.ENTER_FRAME, self.update, self)
    end
     
    function Game:onTransitionOutEnd() -- removed from stage, cleanup
      self:removeEventListener("enterBegin", self.onTransitionInBegin, self)
      self:removeEventListener("enterEnd", self.onTransitionInEnd, self)
      self:removeEventListener("exitBegin", self.onTransitionOutBegin, self)
      self:removeEventListener("exitEnd", self.onTransitionOutEnd, self)
    end
     
    function Game:startUp() -- initialize scene
      self:reset()
    end
     
    -- reset all game stuff before starting a new game
    function Game:reset()
      self.mode = 'menus'
      self.paused = false
    end
     
    -- update every frame
    function Game:update(e)
      if self.paused then return end -- don't process anything if the game is paused
      local dt = e.deltaTime
      local mode = self.mode
      if mode == 'playing' then
        -- process main game logic
      elseif mode == 'gameover' then
        -- process gameover
      elseif mode == 'menus' then
        -- process menus
      else
      end
    end
    Without seeing your code it's hard to tell what might be going wrong. However.. you should only have one ad thing happening so a global chartboost instance I would think.

    Hopefully I've provided a little insight. All these topics and more will be in my Gideros EBook when I finish it ;)

    Likes: Apollo14, Astirian

    +1 -1 (+2 / -0 )Share on Facebook
  • Thanks again @antix, this is incredibly useful stuff. I think I'm just about getting my coding standards to the point where I'm starting to realise that I've been extremely messy! :smiley:

    In retrospect, I think maybe Apple's SpriteKit is very forgiving with memory management and scene transitions and so on but teaches some baaad habits. I like being responsible for my class uhm... cleanliness? :)

    So it looks like I have more work to do, just when I thought I had it licked, more learnings are to be had, you're like a Gideros Yoda man.

    I will most assuredly be buying your book when it's finished!

    Likes: antix, Apollo14

    +1 -1 (+2 / -0 )Share on Facebook
  • antixantix Member
    @Astirian when I first started in Gideros I never cleaned up after myself either ;)

    Likes: Astirian

    +1 -1 (+1 / -0 )Share on Facebook
  • totebototebo Member
    If I showed you the source code to No Brakes 1 you would both cry!

    Likes: antix, Astirian

    My Gideros games: www.totebo.com
    +1 -1 (+2 / -0 )Share on Facebook
Sign In or Register to comment.