Issue #20 resolved

Change Order of Update calls within Group

huhwhozat
created an issue

The order in which updates occur is causing some problems in various areas such as collision and view.focus. I propose the following change:

-- From Group.lua

-- passes startFrame events to member sprites

    startFrame = function (self, elapsed)
        if not self.active then return end
        elapsed = elapsed * self.timeScale
        if self.onStartFrame then self:onStartFrame(elapsed) end

        for _, spr in pairs(self.sprites) do
            if spr.active then spr:startFrame(elapsed) end
        end
    end,

    -- passes update events to member sprites

    update = function (self, elapsed)
        if not self.active then return end
        elapsed = elapsed * self.timeScale

                -- move this line:
        -- if self.onUpdate then self:onUpdate(elapsed) end

        for _, spr in pairs(self.sprites) do
            if spr.active then spr:update(elapsed) end
        end

                -- to here:
        if self.onUpdate then self:onUpdate(elapsed) end
    end,

    -- passes endFrame events to member sprites

    endFrame = function (self, elapsed)
        if not self.active then return end
        elapsed = elapsed * self.timeScale

                -- and this line:
        -- if self.onEndFrame then self:onEndFrame(elapsed) end

        for _, spr in pairs(self.sprites) do
            if spr.active then spr:endFrame(elapsed) end
        end

                -- to here:
        if self.onEndFrame then self:onEndFrame(elapsed) end
    end,

This causes the group onUpdate and onEndFrame to occur after the group's children. Though this may seem counter-intuitive it allows for (imho) better organization as sweeping changes that need to happen after the children update are now feasible. onStartFrame is left as is to allow large changes before the children update. With this change, Elu was able to fix view.focus so that it does not stutter, and I was able to do collision within the.view.onUpdate() instead of onEndFrame.

Comments (6)

  1. Chris Klimas repo owner

    I thought it over, and I think the most sensical model is to use event bubbling, where the parent always sees an event after its children do. I'm trying to think of a case where you would want a parent to react before a child, but I can't come up with anything. So we'd change startFrame to act like what you're proposing for update and endFrame.

  2. huhwhozat reporter

    I... don't know. I can't think of a solid use case either, but it just feels wrong to not allow for code on either side. I guess the way I'd like to see it ideally is that there are no hooks like onUpdate, instead when a class is extended, the extension overrides the update method and calls the superclass' update from withing its own.

  3. Chris Klimas repo owner

    The model I want to go with is that all on* events fire before the class's built-in behavior. My reasoning is that if you set physics properties in an onUpdate, they ought to go into effect that frame, not the next one. It's sort of a moot point as it only really has implications for sprites' onUpdate, since the rest of the built-in classes just pass on the event to any on* handler.

    That said, if you want finer control, you can do this:

    update = function (self, elapsed)
       -- do stuff
       superclass.update(self, elapsed)
       -- do more stuff
    end
    

    Where superclass is whatever class you're inheriting from, e.g. Tile or Animation.

    My bias is that like a third of the bugs I hit working with Flixel involved leaving off a super.update() somewhere... and this was when I was working in FlashDevelop, which is supposed to insert them for you! So the on* handlers are designed to be a foolproof solution to that.

  4. Log in to comment