Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
scenemanager, howto: transition only after loading — Gideros Forum

scenemanager, howto: transition only after loading

keszeghkeszegh Member
edited March 2013 in General questions
so i try to use scenemanager, basically movefromright/left, it is ok on desktop, but on tablet it jumps always to the half of the screen and then slides, even in which case there is ugly tearing.
my scenes contain a lot of sprites and i think the problem is that when the scene is loaded already a lot of time have passed.
so how can i make sure that everything is loaded from the scene before starting the transition? i tried to put something at the end of the init function of the scene, so that only when it is reached does the enterframe of the scenemanager start (and it sets the timer to 0 at this point), but that does not help.

Comments

  • ar2rsawseenar2rsawseen Maintainer
    Maybe I did not understand the problem correctly, thats why I'm not sure it will help, but in SceneManager there are 4 events:
    • enterBegin: Dispatched when your new scene is about to enter the stage. You can initialize your variables here.
    • enterEnd: Dispatched after the transition of new scene has ended. Mostly, you add listeners and start your logic here.
    • exitBegin: Dispatched when your current scene is about to leave the stage. You can remove listeners and stop timers here.
    • exitEnd: Dispatched after your current scene has leaved the stage.
    The one you are looking for is enterEnd.

    Simply put this inside your init method
    self:addEventListener("enterEnd", self.onEnterEnd, self)
    And handle everything in onEnterEnd method ;)
  • @ar2rsawseen thanks,
    although i think my question was not clear, you encouraged me to start/stop touch and enterframe events upon enterEnd/exitBegin, which was necessarry anyway. as it did not stop the transition from lagging, i had the idea that maybe testing on device is not only different because of the computing power, but also screen size.
    so the solution turned out to be:
    in sceneManager transitions are computed from getContentWidth whereas i needed getDeviceWidth as my project is not scaled.
    i changed all occurrences of getContentWidth to getDeviceWidth in the transition functions of sceneManager and now it works quite as i would expect.
  • keszeghkeszegh Member
    edited March 2013
    Btw, why is it not possible to accept my own post as an answer? I think it happens many times that the poster finds the answer (usually inspired by the comments of other forumers).
  • hgvyas123hgvyas123 Guru
    Accepted Answer
    ohhh let me help

    "although i think my question was not clear, you encouraged me to start/stop touch and enterframe events upon enterEnd/exitBegin, which was necessarry anyway. as it did not stop the transition from lagging, i had the idea that maybe testing on device is not only different because of the computing power, but also screen size.
    so the solution turned out to be:
    in sceneManager transitions are computed from getContentWidth whereas i needed getDeviceWidth as my project is not scaled.
    i changed all occurrences of getContentWidth to getDeviceWidth in the transition functions of sceneManager and now it works quite as i would expect."


    accept now it is your answer :D

    :)
  • thanks,
    btw still when i first transition to a scene it usually happens that it appears mostly without transitioning, i think again because loading and creating the assets of the scene takes too much time in itself. the second time i transition into it, it works smoothly.
    so maybe it is a good idea to preload the assets of all scenes of the menu system at the very beginning (i have two a 2-page menu e.g.), i will experiment with that, maybe it will help first transitioning experience.

    Dislikes: pm1891

    +1 -1 (+0 / -1 )Share on Facebook
  • yup you are right as transition effect is time based and when you are loading any asset it will pause for few ms and that's why you can see this at the second time as the assets are already loaded you can't see any lag to avoid this obviously you need too load all assets before calling scenemanager:changescene

    :)
  • keszeghkeszegh Member
    edited March 2013
    as in the first menu page there is only one choice to change to, i could preload the next scene upon initializing the first scene.
    for that i added the following changes to scenemanager:

    in changescene function i changed the respective part to:

    if not self.preloaded or self.scene2==nil then
    self.scene2 = self.scenes[scene].new(options and options.userData)
    self.scene2:setVisible(false)
    end
    self:addChild(self.scene2)
    self.preloaded=false

    and i added:

    function SceneManager:preload(scene,options)
    self.scene2 = self.scenes[scene].new(options and options.userData)
    self.scene2:setVisible(false)
    self.preloaded=true
    end



    and i added at the end of my first scene's init function:
    sceneManager:preload("myNextScene")


    the problem with this is that you need to know in advance what will be the next scene. of course you can change the code more to preload any/all scene(s), which i did in another project, yet i wonder if there would be any better way to check when the assets are loaded and start transitioning only after that? that would save the overhead of loading many scenes into memory.
  • hgvyas123hgvyas123 Guru
    edited March 2013
    not sure but i think in all case we knows which scene we are going to load in advance and that is the reason why we can pass scene's name in scenemanager:changescene function.


    i think following trick will work
    function myScene:loadResource()
    	self.resource1 = Texture.new("blahblah.blah")
    end
    make this type of function on each and every scene and when you are about to change the scene call this func before calling scenemanager:changescene it will make sure to start transitioning after loading all assets for that scene.

  • @hgvyas123, if this works this could be also hidden in the scenemanager, like first make new scene2 and then do the rest.
    this way the assets in init function will be preloaded. or? (i would think that if normal functions are executed sequentially (next line of code called when previous finished)
    then we should process the second line of code after a scene.new only when init function ended loading assets.
    but then it is actually like this in scenemanager as in scenemanager.lua the timer reset to 0 is called only after the scene2.new line, so it should work as efficiently (and it is not efficient, first loading skips transitioning when too many assets) as your proposed trick (which i did not try). am i wrong?

    or maybe onenterframe of scenemanager should be removed/added inside the change function so that the above works as we would like? but again, tweening is set to on only after the scene2.new line, so this should not matter.
  • @hgvyas123
    i tried to put my
    sceneManager:preload("myNextScene")
    line right before the changeScene line, which should be basically equivalent to your trick, except that instead of loading the assets directly it runs the init function of the next scene, which loads the assets.
    yet when doing this way there is the usual skip of transition the first time. in any case i stick to preloading way before changescene will be called, if there is any better solution, let me know.
  • myScene:loadResource() is just one function and you are calling it to load any
    resources. it has nothing to do with scenemanager.



    :)

  • hgvyas123hgvyas123 Guru
    edited March 2013
    can you show any demo project as that method must have to work

    [edit]
    with few ms of pause before transition get start if there are much resources

    :)
  • it would be hard to show a compact example from my code.
    also, as i said, i did not try word-by-word your example as i have all the assets loaded upon init of that scene and all of them are called self.something, so putting all this loading into another function which is independent of my class would be a lot of rewriting. that's why i try your idea basically in the following way (by changing scenemanager as i said):
    line1: scene2.new --loads all the assets
    line2: changescene(to scene2) --does only the transition, without making new scene2

    i think this should be equivalent to your trick.
    also, i did not put the few ms pause inbetween the two lines, of course that should help, but is not a very efficient way as how could i guess how much time my preload needs on some specific machine? of course one can expect that it is not more than a few secs.

    if i will have more time and need i may try to try your trick verbatim, in hope it works differently, but now i don't have time for that.
  • btw your example won't work with sceneManager verbatim, as before calling changescene, i think there is no instance of the next scene, i.e. myScene does not exist, thus we cannot call myScene:loadResource().

    also, when i meant that we know in advance the next scene, i meant that we know next scene (scene2) already when entering current scene (scene1) - and so we can preload it already at this time -, which is not always the case. of course right before changing to scene2, we know what is scene2: )
  • "line1: scene2.new --loads all the assets
    line2: changescene(to scene2) --does only the transition, without making new scene2"

    yup i also think it is similar method

    ohhh and i had not said to put any delay actually sentence above is just one line as you are loading the assets and then calling transitions it will automatically put some delay over here according to this rule "next line of code called when previous finished"


    :)
  • keszeghkeszegh Member
    edited March 2013
    ok,
    now if only we knew how can we make sure that
    "next line of code called when previous finished"
    concept works 100% (i.e. gideros loads all assets in line 1 and THEN processes line2), as now this is not the case for me.
  • keszeghkeszegh Member
    edited March 2013
    @ar2rsawseen, I propose some minor change to sceneManager which may solve this issue with awkward skipping when loading of scene takes too long:
    instead of putting this line into init (of SceneManager):
    self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
    we should put it into changeScene let's say right after the line:
    self:addChild(self.scene2)

    also, we would remove this listener after transition ends by putting this line into onEnterFrame let's say after the line:
    dispatchEvent(self.scene2, "enterEnd")
    we should add:
    self:removeEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)

    i think this would improve much the smoothness of transitions of scenemanager, without the need of any preloading. also when there is no transition then it is quite unnecessary anyway to have an enterFrame listener that is granted to do nothing at all.
    what's your opinion? i did not test it thouroughly, but in practice it also seems like improving the visual feeling of transitions a lot.

  • ar2rsawseenar2rsawseen Maintainer
    @keszegh sure I'll try to discuss that with @atilim, but no promises :D

    I don't know right now what happens, if onEnterFrame is not defined in scene, etc. Will check it.

    But of course meanwhile you can clone SceneManager version here:
    https://github.com/gideros/Scene-Manager

    And provide your own version for community :)
  • Cloning might be an interesting thing, although many versions with minor changes are rarely useful (and i don't use github so far). In any case whatever we do (update scenemanager main branch or make a different clone) the necessary change can always be found in this topic: )
    About this:
    "I don't know right now what happens, if onEnterFrame is not defined in scene, etc. Will check it."
    I don't understand this, the onenterframe etc i wrote about are all for the scenemanager object and not for the scenes themselves. and as far as i've seen it is indeed only doing anything if self.tweening is true, i.e. there is a transition going on. (actually with adding/removing onenterframe, this tweening variable seems to be not necessary at all).
  • how come, it is stated (and was always, who knows?) clearly in my respetive post that we add these lines to SceneManager...
  • ar2rsawseenar2rsawseen Maintainer
    edited March 2013
    Probably not enough sleep, but I thought you meant adding onEnterFrame events to the scene objects being transitioned by SceneManager
  • no problem, and i was referring to the magic of post-editing-a-post.
  • ar2rsawseenar2rsawseen Maintainer
    :D :D :D then I misinterpreted that also, I really need to get some sleep :))
  • keszeghkeszegh Member
    @ar2rsawseen, @atilim, (maybe others)
    please help, i'm still struggling with this transition.
    so is there really no way to start transition only when all the textures are loaded/bitmaps are generated etc in the init function of the next scene?
    theoretically if the code processing is sequential, this would be good, but it is not working as i would expect.
    (in scenemanager i first make the new scene and only after that i add an eventlistener to do the transition, so it should work good but it does not)

    either proper sequential processing or a function like 'isloaded' for textures,bitmaps would solve the issue.

    because now the loading slows down the machines and transition is stuttering. the only other workaround would be to add some waiting time after loading the scene and before starting transition, but that's just stupid, the time needed would vary a lot along different phones, so either i set it low and then there is still stuttering on slow phones, or i set it high and then even on fast phones people have to wait a lot before the level begins.

    loading all textures and bitmaps for all levels at the beginning of the game seems to be not feasible, especially that the textures i need differ a lot along levels, altogether 1-2 hundred 512x512 textures, loading all of them to the memory seems to be too much, isn't it?
  • ar2rsawseenar2rsawseen Maintainer
    @keszegh the problem is that all transition and texture loading happens in the same enterframe draw.
    The quick and dirty fix to load textures before and only after to transition is to delay the transition using Timer, likes this:
    function SceneManager:changeScene(scene, duration, transition, ease)
    	if self.tweening then
    		return
    	end
     
    	if self.scene1 == nil then
    		self.scene1 = self.scenes[scene].new()
    		self:addChild(self.scene1)
    		dispatchEvent(self, "transitionBegin")
    		dispatchEvent(self.scene1, "enterBegin")
    		dispatchEvent(self, "transitionEnd")
    		dispatchEvent(self.scene1, "enterEnd")
    		return
    	end
     
    	self.duration = duration
    	self.transition = transition
    	self.ease = ease or defaultEase
     
    	self.scene2 = self.scenes[scene].new()
    	self.scene2:setVisible(false)
    	self:addChild(self.scene2)
     
    	Timer.delayedCall(1, function()
    		self.time = 0
    		self.currentTimer = os.timer()
    		self.tweening = true
    	end)
    end
    I've attached a test project, hope that helps ;)
    zip
    zip
    Transition.zip
    608K
  • keszeghkeszegh Member
    edited May 2013
    thanks for the fast reply.
    i don't understand one concept i think so i'm not sure if:
    is this method good for phones of all speed or just for the ones where scene loading stays below 1sec?

    edit: it would be 1 millisec, so i assume that it should work on all phones. it seems the point is to force that the things inside the delayed function will happen at least 1 enterframe later.
  • ar2rsawseenar2rsawseen Maintainer
    edited May 2013
    @keszegh that is exactly as you said in your edit
    is it working for you? :)

    I've used this trick to show Loading element when transitioning between scenes in new Mashballs update. It's very useful on slower phones, because then user gets immediate response from the click on button and is aware that something is happening
  • keszeghkeszegh Member
    it may indeed work, i have to make some testing before i can be sure.
    showing a small 'loading' sprite in some corner while loading is a good idea.
Sign In or Register to comment.