replacing an image when it is tapped

hi, i am building a “bubble wrap” game where you need to pop as many bubbles as possible in a set amount of time. this is my first attempt at the corona SDK so please make your help as dumb-ed down as possible xD

i created my menu and made it load the actual game, i am now trying to make the bubbles “pop”. to do this i am trying to replace the image with a “bubbleDown.png” image, my problem is that when i hit a bubble anywhere on the screen it creates a new image of “bubbleDown” near the top left of the screen :confused:   can anyone tell me what i am doing wrong please?

 -----------------------------------------------------------------------------------------

– view2.lua


local storyboard = require( “storyboard” )

local scene = storyboard.newScene()


– BEGINNING OF YOUR IMPLEMENTATION

– 

– NOTE: Code outside of listener functions (below) will only be executed once,

–         unless storyboard.removeScene() is called.

– 


– Called when the scene’s view does not exist:

function scene:createScene( event )

    local group = self.view

    

    – create a white background to fill screen

    local bg = display.newImage(‘bgG.png’ )

    local titleBar = display.newRect(0,0,display.contentWidth,15)

    titleBar:setFillColor(75,0,0)

    

    – all objects must be added to group (e.g. self.view)

    group:insert( bg )

    group:insert( titleBar )

    -------------------------------create the bubbles------------------------------------------

    local count = 1

    local bubble = {}

    for i=9,display.contentWidth,19 do

      for j=19,display.contentHeight,19 do

      bubble[count] = display.newImage(‘bubble.png’ )

      bubble[count].x = i

      bubble[count].y = j

      group:insert( bubble[count] )

      bubble[count]:addEventListener(“tap”, bubbleTap)

      count = count+1

    end

    end

    

    

    -------------------------------------------------------------------------------------------

end

– Called immediately after scene has moved onscreen:

function scene:enterScene( event )

    local group = self.view

    

    – do nothing

    

end

– Called when scene is about to move offscreen:

function scene:exitScene( event )

    local group = self.view

    

    – INSERT code here (e.g. stop timers, remove listenets, unload sounds, etc.)

    

end

– If scene’s view is removed, scene:destroyScene() will be called just prior to:

function scene:destroyScene( event )

    local group = self.view

    

    – INSERT code here (e.g. remove listeners, remove widgets, save state variables, etc.)

    

end

function bubbleTap( event )

local self = event.target

self = display.newImage( ‘bubbleDown.png’ )

end


– END OF YOUR IMPLEMENTATION


– “createScene” event is dispatched if scene’s view does not exist

scene:addEventListener( “createScene”, scene )

– “enterScene” event is dispatched whenever scene transition has finished

scene:addEventListener( “enterScene”, scene )

– “exitScene” event is dispatched whenever before next scene’s transition begins

scene:addEventListener( “exitScene”, scene )

– “destroyScene” event is dispatched before view is unloaded, which can be

– automatically unloaded in low memory situations, or explicitly via a call to

– storyboard.purgeScene() or storyboard.removeScene().

scene:addEventListener( “destroyScene”, scene )


return scene

any help would be more than appreciated :slight_smile:

This is because you are not setting the x and y coordinates of the new image.   

function bubbleTap( event ) local self = event.target self = display.newImage( 'bubbleDown.png' ) self.x = event.x self.y = event.y end

Not only that, you cannot “change” the image an object uses. If you it to appear that the image is changing, you will need to remove the original object and put a new one in it’s place (it happens quickly enough to create the illusion).

Try changing your “create the bubbles” code in createScene to add this:

--this allows us to replace the bubble in the table later on bubble[count].index = count

Then change bubbleTap function to this:

function bubbleTap( event ) local oldBubble = event.target local count = oldBubble.index --replace the old bubbles place in the table with the new bubble bubble[count] = display.newImage( 'bubbleDown.png' ) --and place the new bubble in the old bubbles location on screen bubble[count].x = oldBubble.x bubble[count].y = oldBubble.y --make sure the new bubble has the same index as the old one bubble[count].index = count bubble[count]:addEventListener("tap", bubbleTap) --add the new bubble to the scene group scene.view:insert(bubble[count]) --no longer need the old bubble, so remove it oldBubble:removeSelf() end

That should allow you to replace the image while keeping your table structure intact (unless I’ve missed something).

that worked like a dream thanx :slight_smile:

only issue i had was it doesnt like the event listener being added… i will cross that bridge later today when i need it :L

DELETED

When I first typed it in I had a typo, which was a quotation mark after the word bubbleTap in the addEventListener call. I presume you removed that (or saw that code after I’d edited it out)?

 

Otherwise, I don’t see any reason why it wouldn’t let you add the event listener.

i think i read something in the API about not being able to add event listeners inside events

i have another problem now, i tried to get the bubbles to return to their original image after 5 seconds, used the same code, almost

i dont think the timer.performWithDelay is working because now the image doesnt appear to change at all :confused:

function bubbleTap( event ) local oldBubble = event.target local count = oldBubble.index bubble[count] = display.newImage( 'bubbleDown.png' ) bubble[count].x = oldBubble.x bubble[count].y = oldBubble.y bubble[count].index = count --bubble[Count]:addEventListener("tap", bubbleTap) scene.view:insert(bubble[count]) oldBubble:removeSelf() timer.performWithDelay(5000, bubbleUnPop(bubble[count])) end function bubbleUnPop( event ) local oldBubble = event local count = oldBubble.index bubble[count] = display.newImage( 'bubble.png' ) bubble[count].x = oldBubble.x bubble[count].y = oldBubble.y bubble[count].index = count --bubble[Count]:addEventListener("tap", bubbleTap) scene.view:insert(bubble[count]) oldBubble:removeSelf() end

any ideas?

Regarding adding listeners in a listener, the docs say something like “if you add a listener in a listener, the new listener will get called immediately after the first listener function exits”, causing it to get called right away.

To get around it, the new listener should be added on a delay, using a performWithDelay and a “closure”, something like

[lua]

    timer.performWithDelay( 100, function() bubble[Count]:addEventListener(“tap”, bubbleTap) end, 1)   – slight delay so this listener is exited before adding new listener

[/lua]

This appears to also be needed (a closure) on the code line

[lua]    timer.performWithDelay(5000, function() bubbleUnPop(bubble[count])) end, 1)   – 5 second delay before calling [/lua]

Without the closure in the delay call, bubbleUnPop is getting called immediately…

thanks mpappas, worked perfectly, 

do variables pass over to new scenes?.. for a score screen/score board

check out this article:
http://www.coronalabs.com/blog/2012/08/07/managing-state-between-scenes/

btw. just curious, but i wonder why you didnt solve the imageswap with an imagesheet and sequences. i mean, of course it is working flawlessly your way too, but what if you want to add a bit of animation in the bubble popping, plus you would save some texture ram, even tho texture ram might not be a problem here.

thanx, i actually found that article right before you posted the link… and i have no idea what an image sheet is… this app is the first time i have done any coding that involves more than a java console window so anything involving images i have been guessing from the start

lol

i dont suppose there’s a more efficient way to create the bubbles? the way i have done it causes a delay between the user hitting play and the scene loading

could you post your most current complete code,
i’d like to have a look on it as i dont understand the need for a delay.

imagesheets are awesome by the way (as long as you use a spritesheet generator like texturepacker, making them manually can become an endless pain when you got a more complex project), 
here is a quick beginners guide
http://www.coronalabs.com/blog/2013/05/14/sprites-and-image-sheets-for-beginners/

this is my finished game scene. what i was wandering is if there is a more efficient way to create the bubbles when the scene loads for the first time. currently i am using 2 for loops and it is causing a delay (lag)

----------------------------------------------------------------------------------------- -- -- view2.lua -- ----------------------------------------------------------------------------------------- local storyboard = require( "storyboard" ) local scene = storyboard.newScene() local pop = audio.loadStream('pop.mp3') local unPop = audio.loadStream('unpop.mp3') local load = audio.loadStream('load.mp3') local bubble = {} local timed = 10 local score = 0 local Dscore local Dtime ----------------------------------------------------------------------------------------- -- BEGINNING OF YOUR IMPLEMENTATION -- -- NOTE: Code outside of listener functions (below) will only be executed once, -- unless storyboard.removeScene() is called. -- local Dscore ----------------------------------------------------------------------------------------- -- Called when the scene's view does not exist: function scene:createScene( event ) local group = self.view -- create a white background to fill screen local bg = display.newImage('bgG.png' ) local titleBar = display.newRect(0,0,display.contentWidth,20) titleBar:setFillColor(75,0,0) --create the score Dscore = display.newText("Score: ".. score, 0, 0, native.systemFont, 14) --create the time Dtime = display.newText("Time: ".. timed, 0, 0, native.systemFont, 14) Dtime.x = display.contentWidth -30 -- all objects must be added to group (e.g. self.view) group:insert( bg ) group:insert( titleBar ) -------------------------------create the bubbles------------------------------------------ local count = 1 audio.rewind(load) audio.play(load) for i=9,display.contentWidth,19 do--bubble horizontal for j=30,display.contentHeight,19 do--bubble verticle bubble[count] = display.newImage('bubble.png' ) bubble[count].index = count bubble[count].x = i bubble[count].y = j group:insert( bubble[count] ) bubble[count]:addEventListener("tap", bubbleTap) count = count+1 end end ------------------------------------------------------------------------------------------- end -- Called immediately after scene has moved onscreen: function scene:enterScene( event ) local group = self.view -- do nothing end -- Called when scene is about to move offscreen: function scene:exitScene( event ) local group = self.view -- INSERT code here (e.g. stop timers, remove listenets, unload sounds, etc.) end -- If scene's view is removed, scene:destroyScene() will be called just prior to: function scene:destroyScene( event ) local group = self.view -- INSERT code here (e.g. remove listeners, remove widgets, save state variables, etc.) end function bubbleTap( event ) local oldBubble = event.target local count = oldBubble.index audio.rewind(pop) audio.play(pop) bubble[count] = display.newImage( 'bubbleDown.png' ) bubble[count].x = oldBubble.x bubble[count].y = oldBubble.y bubble[count].index = count --bubble[Count]:addEventListener("tap", bubbleTap) scene.view:insert(bubble[count]) updateScore() oldBubble:removeSelf() timer.performWithDelay(1500, function() bubbleUnPop(bubble[count]) end) end function bubbleUnPop( event ) local oldBubble = event local count = oldBubble.index audio.rewind(unPop) audio.play(unPop) bubble[count] = display.newImage( 'bubble.png' ) bubble[count].x = oldBubble.x bubble[count].y = oldBubble.y bubble[count].index = count timer.performWithDelay( 100, function() bubble[count]:addEventListener("tap", bubbleTap) end, 1) scene.view:insert(bubble[count]) oldBubble:removeSelf() end function countdown () if timed == 0 then gameEnd() else timed = timed -1 Dtime:removeSelf() Dtime = display.newText("Time: ".. timed, 0, 0, native.systemFont, 14) Dtime.x = display.contentWidth -30 end end function updateScore() score = score+1 Dscore:removeSelf() Dscore = display.newText("Score: ".. score, 0, 0, native.systemFont, 14) end function gameEnd( event ) storyboard.gotoScene( "view3", {params = {scored = score}}) end timer.performWithDelay(1000, countdown, 60) ----------------------------------------------------------------------------------------- -- END OF YOUR IMPLEMENTATION ----------------------------------------------------------------------------------------- -- "createScene" event is dispatched if scene's view does not exist scene:addEventListener( "createScene", scene ) -- "enterScene" event is dispatched whenever scene transition has finished scene:addEventListener( "enterScene", scene ) -- "exitScene" event is dispatched whenever before next scene's transition begins scene:addEventListener( "exitScene", scene ) -- "destroyScene" event is dispatched before view is unloaded, which can be -- automatically unloaded in low memory situations, or explicitly via a call to -- storyboard.purgeScene() or storyboard.removeScene(). scene:addEventListener( "destroyScene", scene ) ----------------------------------------------------------------------------------------- return scene

look at the “create the bubbles” block of code

wow your loop gave me headaches,
but i doubt it’s the reason for the lag.
nevertheless it is really hard to “read” and understand.
plus your app needs to look up contentHeight and contentWidth many many times (what might be part of the lag, but i doubt it).

you might want to give this a try

[lua]

    local bOffsetX = 9

    local bOffsetY = 30

    local bDist = 19

    local bRows = 10 --or whatever number of rows is desired

    local bColumns = 10 --or whatever

    for a=1, bRows do

        for b=1, bColumns do

           

            local myBubble = display.newImage(‘bubble.png’ )

                  

            myBubble.x = (bDist * (b-1)) + bOffsetX

            myBubble.y = (bDist * (a-1)) + bOffsetY

            myBubble.index = count

            myBubble.isPopped = false

            myBubble:addEventListener(“tap”, bubbleTap)

            

            bubble[count] = myBubble

            group:insert(myBubble)

            count = count+1

        end

    end

[/lua]

oh wait, you dont neeed the isPopped part, that was copy and paste from my rewriting the whole thing with spritesheets what will follow in a few moments.

here we go,
a really simple prototype of the bubblewrap game,

Instead of replacing the image it’s using Sprites and Sequences to change the look of the bubble.
take what you like from it, i think some things are just a bit clearer constructed.
its not lagging.

https://github.com/juicefoozle/bubblewrap

it’s the pure gamemechanics, so, there is no game end, no sounds, no ui, no storyboard implementation.

But when i started i found these short and very puristic examples the easiest to learn from and the easiest to extend and modify to my needs.
i fully commented it, even tho i guess you already understand most of it, i thought it might be helpful if someone else new to corona might check this thread out.

cheers,
Michael

This is because you are not setting the x and y coordinates of the new image.   

function bubbleTap( event ) local self = event.target self = display.newImage( 'bubbleDown.png' ) self.x = event.x self.y = event.y end

Not only that, you cannot “change” the image an object uses. If you it to appear that the image is changing, you will need to remove the original object and put a new one in it’s place (it happens quickly enough to create the illusion).

Try changing your “create the bubbles” code in createScene to add this:

--this allows us to replace the bubble in the table later on bubble[count].index = count

Then change bubbleTap function to this:

function bubbleTap( event ) local oldBubble = event.target local count = oldBubble.index --replace the old bubbles place in the table with the new bubble bubble[count] = display.newImage( 'bubbleDown.png' ) --and place the new bubble in the old bubbles location on screen bubble[count].x = oldBubble.x bubble[count].y = oldBubble.y --make sure the new bubble has the same index as the old one bubble[count].index = count bubble[count]:addEventListener("tap", bubbleTap) --add the new bubble to the scene group scene.view:insert(bubble[count]) --no longer need the old bubble, so remove it oldBubble:removeSelf() end

That should allow you to replace the image while keeping your table structure intact (unless I’ve missed something).

that worked like a dream thanx :slight_smile:

only issue i had was it doesnt like the event listener being added… i will cross that bridge later today when i need it :L

DELETED