Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
onEnterFrame removal troublesome. — Gideros Forum

onEnterFrame removal troublesome.

AstirianAstirian Member
edited November 2017 in Bugs and issues
Hey guys,

I'm stumped on this right now; Trying to reset my level but my update function continues and errors out some Bump stuff. So I figure I need to remove the event listener on reset, but it doesn't work. Here's some code:
function GameScene:addEventListeners()
	self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end
 
function GameScene:removeListeners(s)
print(s)
print(self)
print(GameScene)
 
	s:removeEventListener(Event.ENTER_FRAME, s.onEnterFrame, s)
end
In my NPC class's update loop (triggered from GameScene:onEnterFrame on a GAME_STARTED bool):
if LIVES > 1 then
	GameScene:removeListeners(GameScene)
else
...
I'm not great around the whole event listening concept to be honest.

But basically the new level loads an then swiftly crashes when GAME_STARTED is set to true and it will try to finish the previous round's update loop...

Comments

  • piepie Member
    edited November 2017 Accepted Answer
    Maybe i am wrong, but it seems to me that in the second snippet you are using a global class as a parameter (and as base class) for your function.
    I am Sorry I am on mobile right now so it's hard to write it out... :)
    I think that in your NPC function you need to call the gamescene with its instance name (not the class name).
    if you're using scene manager it may be scenemanager.scene1
    Edit: another option could be to ask the NPC instance to get its parent (which somewhere in the hierarchy of sprites is the scene) using self:getParent() - where self, if placed inside the NPC base class refers to the instance of NPC class which is executing the code.

    Likes: Astirian

    +1 -1 (+1 / -0 )Share on Facebook
  • @pie is correct, your'e doing it wrong :D

    When you create your game scene you must be calling GameScene.new() so you would need to use that instance when removing listeners, like this..
    GAME_SCENE = GameScene.new()
     
    GAME_SCENE:removeListeners()
    Which would work without errors I think.

    Are you using SceneManager in your project?

    Likes: Astirian

    +1 -1 (+1 / -0 )Share on Facebook
  • jdbcjdbc Member
    edited November 2017
    Try this:
    GameScene = Core.class(Sprite)
     
    -- Create game scene
    function GameScene:init()
            ...
    	self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame,self)
    end
     
    function GameScene:onEnterFrame()
           -- Update your player, ...
    end
     
    function GameScene:removeListeners() 
    	self:removeEventListener(Event.ENTER_FRAME, self.onEnterFrame,self)
            ...
    end
    Call removeListeners when you are going to change the current scene. For example:
    -- Player is dead
    self:removeEventListeners()
     
    -- Change scene now using SceneManager.
    I have also published the full source code of my game Square Dots published in Android and iOS but GPL 3 license for education purposes. You can learn from it, this is the way I have built most of my games.

    https://github.com/jdbcdev/Dots

  • jdbcjdbc Member
    edited November 2017

    I guess your problem is you need to understand class (use . as separator) and objects methods (use : as separator) in Object Oriented Programming. For instance:

    GameScene.staticFunction1() is a class function. You have to call in this way:
    GameScene.staticFunction1()
    Below function does not need to create a object of GameScene, you can use it anywhere in your Gideros project.

    Besides GameScene:removeListener() is a function of one instance of the GameScene. You must use
    self:removeListener()
  • @pie is correct, your'e doing it wrong :D

    When you create your game scene you must be calling GameScene.new() so you would need to use that instance when removing listeners, like this..
    GAME_SCENE = GameScene.new()
     
    GAME_SCENE:removeListeners()
    Which would work without errors I think.

    Are you using SceneManager in your project?
    Ahh... Yes I am. Let me see if I understand this.

    I'm instantiating scenes like this in main.lua:
    	scenes = {"logo", "menu", "game", "score"}
     
    	sceneManager = SceneManager.new({
    		["logo"] = LogoScene,
    		["menu"] = MenuScene,
    		["game"] = GameScene,
    		["score"] = ScoreScene
    		})
     
    	stage:addChild(sceneManager)
    So when do this from NPC.lua's update function:
    	o = self:getParent()
            o2 = o:getParent()
    	o3 = o2:getParent()
    	o4 = scenes[3]
    	o5 = game
     
            print(o)
    	print(o2)
    	print(o3)
    	print(o4)
    	print(o5)
     
    	GameScene:removeListeners(o4)
    Which calls this in GameScene.lua:
    function GameScene:removeListeners(s)
        print(s)
        print(self)
        print(GameScene)
     
        print(self.onEnterFrame)
     
        s:removeEventListener(Event.ENTER_FRAME, s.onEnterFrame, s)
    end
    I'm past the _userdata error but now s is nil I think, and I'm not sure why as s is the instantiated scene right?

    The memory addresses (or pointers?) for the variables above are interesting (obviously they change on every run but you get the idea :) )

    o = 0x115cf748
    o2 = 0x115bc090
    o3 = 0x1159f1d0
    o4 = game
    o5 = nil

    self and GameScene are 0x115c52e8 (which I assume is the base class directly?)

    I'm guessing that passing in 'game' is not correct?

    Interestingly trying GAME = sceneManager.game is nil...
  • antixantix Member
    edited November 2017 Accepted Answer
    To access one class from another I just use global variables. Even though many people frown on this it isn't as bad as it might seem. In my game class for instance...
    function Game:init()
      GAME = self -- makes this instance available to ALL other things
    end
    So that line of code makes that instance of the game class available to ALL instances of ALL other classes in your project.
    function npc:update()
      local game = GAME -- not strictly required but good if multiple calls will be used
      game:removeListeners(o4)
    end
    That is guaranteed to work :)

    Let us know how you get on ;)

    Might I ask why every npc instance has it's own EnterFrame event?

    Likes: Astirian

    +1 -1 (+1 / -0 )Share on Facebook
  • @antix Thanks I'll give that a crack when I get home from work.

    To answer your question, I don't have an onEnterFrame function in the NPC class, but my game scene's onEnterFrame calls the NPC's update function.

    So basically, here we're saying to the NPC instance (on the update run where it tries to reset the round):
      local game = GAME -- not strictly required but good if multiple calls will be used
      game:removeListeners(o4)
    locally use game (which points to the GAME instance form init) and send it a reference to o4, which itself is a direct reference to the instance created when I initially create my sceneManager array in main? (I.e. scenes[3])
  • Yep that's correct.

    So I still don't quite get your code though. This line..
    s:removeEventListener(Event.ENTER_FRAME, s.onEnterFrame, s)
    seems to read that the object s has an ENTER_FRAME event listener attached to it.

    Likes: Astirian

    +1 -1 (+1 / -0 )Share on Facebook
  • jdbcjdbc Member
    edited November 2017
    @antix Thanks I'll give that a crack when I get home from work.

    To answer your question, I don't have an onEnterFrame function in the NPC class, but my game scene's onEnterFrame calls the NPC's update function.

    So basically, here we're saying to the NPC instance (on the update run where it tries to reset the round):
      local game = GAME -- not strictly required but good if multiple calls will be used
      game:removeListeners(o4)
    locally use game (which points to the GAME instance form init) and send it a reference to o4, which itself is a direct reference to the instance created when I initially create my sceneManager array in main? (I.e. scenes[3])
    Just use my code above, easier and using only local variables in every scene. I have done all my games using these code and I have several ones.

    In the main.lua the following code to create scenes using SceneManager:
    scenes = {"menu", "game"}
     
    	sceneManager = SceneManager.new({
                    ["menu"] = MenuScene,
    		["game"] = GameScene,
    		})
     
    	stage:addChild(sceneManager)
     
    	local currentScene = scenes[1]
     
    	local timer = Timer.new(1000, 1)
    	timer:addEventListener(Event.TIMER, 
    				function()
    		                        ...
    					sceneManager:changeScene(currentScene)
    				end)
    	timer:start()
    Only use global variables with constants or global objects.

    Likes: Astirian

    +1 -1 (+1 / -0 )Share on Facebook
  • Thanks guys, got it working. :)

    Likes: antix

    +1 -1 (+1 / -0 )Share on Facebook
Sign In or Register to comment.