Hi, I am pulling my hair out trying to understand what's wrong with my code. I created a sample code below using button class and have a few questions for you:
1) why my buttons still receive events even after I did this:
-- remove button and event listener
self.buttons[i]:removeEventListener(Event.MOUSE_DOWN, self.onClick,self)
self.buttons[i]:removeFromParent() |
2) Why do I need to remove events manually even though I removed the button from parent class? should not Gideros remove event automatically? looks like an extra step...
3) in my onClick event I have to put extra code like this to identify the instance of the button that actually dispatched event. Is there a better way of doing this?
for i=1,5 do
if self.buttons[i]:hitTestPoint(event.x, event.y) then
print ("onClick on button "..i)
....
event:stopPropagation()
end |
And here is my full sample. I create an array of buttons (5) and i want to remove onclick event and the button itself from stage once it is clicked on. The problem is it is "clicable" even though it is removed from stage.
GameScene = gideros.class(Sprite)
function GameScene:init()
self.buttons = {}
for i=1,5 do
-- create the up and down sprites for the button
local up = Bitmap.new(Texture.new("button_up.png"))
local down = Bitmap.new(Texture.new("button_down.png"))
-- create the button
self.buttons[i] = Button.new(up, down)
self.buttons[i].id = i
self:addChild(self.buttons[i])
self.buttons[i]:addEventListener(Event.MOUSE_DOWN, self.onClick,self)
self.buttons[i]:setPosition(50, 70*(i-1))
end
end
function GameScene:onClick(event)
for i=1,5 do
if self.buttons[i]:hitTestPoint(event.x, event.y) then
print ("onClick on button "..i)
-- remove button and event listener
self.buttons[i]:removeEventListener(Event.MOUSE_DOWN, self.onClick,self)
self.buttons[i]:removeFromParent()
event:stopPropagation()
end
end
end
stage:addChild(GameScene.new()) |
Comments
1) hitTestPoint is required. Right now it seems like unnecessary if, but it actually is giving you more flexibility, like if button is small, you can test it to more wider area. So you can keep small graphic but still make it clickable on small resolutions. Or detect if user pressed and then pulled the mouse cursor or touch away off the button to cancel click, etc.
2) Sprite stops receiving input events, like mouse, touch or key when it is removed from stage. And it is actually happening. In your case problem is, that while sprite is removed, it still returns true for hitTestPoint, and since you have not removed it from your self.buttons table, you still iterate through it and check for hitTestPoint. So you need not only to remove it from parent, but also remove from self.buttons table
3) Buttons class already provides internal event "click" which does the hitTestPoint checking and stopping propagation, etc.
4) I would recommend not to assign same event listener to all buttons and iterate through them, but have separate event listener for each one, like:
Fragmenter - animated loop machine and IKONOMIKON - the memory game
I have a few follow-up questions.
1) if I use anonymous function like in your example, how then I can remove listener for it? I was looking for that on the forum and I think someone said it is not possible without repeating the whole code or using named function.
2) how can I remove my button from scene and from buttons table? I thought this code will do this trick, no? self.buttons[i]:removeFromParent(). Are you saying that table does not count as a "parent"?
thanks guys!
to pass both infos when the event is triggered, there are many ways to do this (i also recently asked about how to pass multiple variables), read this thread e.g.:
http://www.giderosmobile.com/forum/discussion/comment/27288
Fragmenter - animated loop machine and IKONOMIKON - the memory game
But just to note, that the length of self.buttons will be decreased, so you better rewrite your loop like: