Best way to change images on touch?

Hello again,

i wanted to ask, what is the best way there is for changing images on touch or collision, whatever? Please share your expertise)

i need to change images for one object and so i dont have to add listeners again, is there a way to do it? [import]uid: 16142 topic_id: 18670 reply_id: 318670[/import]

I’m sure there are other ways to do this, and I’m not sure if this is the best/right way to do it, but when I have a display object that needs to change image (while retaining all of its properties, including the listeners assigned to the object), I make the display object into a display group with two images. I assign properties to the display group, and then I keep one of the images set to alpha = 0 and the other one set to alpha = 1. I change/swap the alpha value when the image needs to change.

Naomi
[import]uid: 67217 topic_id: 18670 reply_id: 71753[/import]

thanks, thats definetly works too

but i’d want to see more examples)
and there’s my way:
[lua]local img = display.newImage(“planet1.png”)
local img2 = display.newImage(“planet2.png”)
img2.isVisible = false
img.isHitTestable = true

local function onTouch(event)

if event.phase == “ended” then

img.isVisible = not img.isVisible
img2.isVisible = not img2.isVisible
end
end

img:addEventListener(“touch”, onTouch)[/lua] [import]uid: 16142 topic_id: 18670 reply_id: 71760[/import]

Hey, @darkconsoles, here’s a quickie. I haven’t tested it, but something like below is what I meant:

[lua]local myImgGroup = display.newGroup()
local img = display.newImage(“planet1.png”)
local img2 = display.newImage(“planet2.png”)
myImgGroup:insert(img)
myImgGroup:insert(img2)
myImgGroup.isHitTestable = true
myImgGroup.imgVisible = true
myImgGroup[1].alpha = 1
myImgGroup[2].alpha = 0
local function onTouch(event)
if event.phase == “ended” then
if (myImgGroup.imgVisible == true) then
myImgGroup[1].alpha = 0 – img to be invisible
myImgGroup[2].alpha = 1 – img2 to be visible
myImgGroup.imgVisible = false
else
myImgGroup[1].alpha = 1 – img to be visible
myImgGroup[2].alpha = 0 – img2 to be invisible
myImgGroup.imgVisible = true
end
end
end
myImgGroup:addEventListener(“touch”, onTouch)[/lua]

I hope this helps.

Naomi [import]uid: 67217 topic_id: 18670 reply_id: 71766[/import]

Hey,

Depending on the size of the image (and how many you’re using) a sprite sheet can actually be really useful. (Because changing the image is a one line thing then.)

This doesn’t work in all cases but I felt it was worth mentioning.

Peach :slight_smile: [import]uid: 52491 topic_id: 18670 reply_id: 71786[/import]

Naomi, I noticed you are using the “.alpha” property and your custom property “.imgVisible” to control/determine visibility. Did you know about the “.isVisible” property that each display object already has?

http://developer.anscamobile.com/content/objectisvisible [import]uid: 94868 topic_id: 18670 reply_id: 71790[/import]

Hey, Peach, spritesheet would work great too.

Hey, Screeming Leaf, I was using custom property “.imgVisible” to demonstrate how toggling between the two could work, but yeah, “.isVisible” would work perfectly fine too (and no need to use alpha, but apply .isVisible to the individual pieces). When I was putting it quickly together, I thought I’d include how we could add a property to a group and use it to trigger things to the group (or pieces inside the group).

Cheers,
Naomi [import]uid: 67217 topic_id: 18670 reply_id: 71804[/import]

ahhh! Sounds good. [import]uid: 94868 topic_id: 18670 reply_id: 71808[/import]

Just hitting this question myself now.

Are there any better ways that have become available since the last post? Perhaps within the Corona API? (haven’t found one yet myself)

What about just removing / recreating the image? I’m guessing the listeners might need resetting then perhaps even if the new display object had the same name?

Is there a way to kind of create a new image against the same variable and “hold onto” the listeners so they don’t have to be reset?

PS. If you can’t keep the same display object it also kind of implies in Storyboard you can’t stick to object creation in the createScene function, i.e. you’d have to move this to the enterScene function.
[import]uid: 140210 topic_id: 18670 reply_id: 106339[/import]

I think using image sheets and changing the “frame” is really the best method now. Three reasons why:

  1. They’re built into Corona as a core element of the graphics pipeline. This means that you *don’t* need to include the entire “sprite” library in your project just to swap a few images, as would have been necessary for this method in the past.

  2. You should be using them regardless, for graphical efficiency. So you’re already mostly finished by just implementing image sheets.

  3. The remaining step… the actual swap… is a one-line command. The object keeps its references, listeners, and everything else intact, so it’s far less likely you’ll create other potential errors as could happen if you try to delete and then recreate objects.

Hope this helps!

Brent Sorrentino
Ignis Design [import]uid: 9747 topic_id: 18670 reply_id: 106366[/import]

thanks for a great pointer Brent - hadn’t used these yet - I’ll dig in and try this out… [import]uid: 140210 topic_id: 18670 reply_id: 106380[/import]

Glad I read this thread… I was just trying to figure out this myself, and never thought of using sprite sheets… seems like a no-brainer now! :slight_smile: [import]uid: 114363 topic_id: 18670 reply_id: 106446[/import]

I think Brent’s suggestion is to actually use the new “Image Sheets” (c.f. sprites)… [import]uid: 140210 topic_id: 18670 reply_id: 106448[/import]

@greg886, true, I didn’t catch that originally. I read Peach’s comment about sprite sheets above and since I am using build 2011.704, sprite sheets would seem to work in my case.

I did read about Image Sheets and they sound like a better solution for what I need… I do need to place a lot of objects on the screen for my next project. I guess I will investigate further with a newer build.

thanks! [import]uid: 114363 topic_id: 18670 reply_id: 106450[/import]

oh…how do you actually “swap” (change) the frameIndex when using Image Sheets?

That is I have the initial sheet & image displayed, and now in an “enterScene” method (storyboard) want to change the newImageRect object from frameIndex 1 to frameIndex 2?
[import]uid: 140210 topic_id: 18670 reply_id: 106451[/import]

Here’s the command you need:

object:setFrame( frame )

Brent Sorrentino [import]uid: 9747 topic_id: 18670 reply_id: 106454[/import]

Hi Brent - I just got a “attempt to call method ‘setFrame’ (a nil value) stack traceback:” when I tried this?

I’m on: Version 2012.811 (2012.12.8)

local chest\_imageSheet = graphics.newImageSheet( "media/images/chest\_imageSheet.png", options ) oldChest = display.newImageRect(scene.view, chest\_imageSheet, 1, 40, 34 ) oldChest:setReferencePoint( display.TopLeftReferencePoint ) oldChest.x, oldChest.y = display.contentWidth \* 0.55, display.contentHeight \* 0.75 oldChest:setFrame(2) [import]uid: 140210 topic_id: 18670 reply_id: 106458[/import]

This code looks fine, but can you try it outside of Storyboard? “scene.view” looks like Storyboard code to me. I confess that I’m really not familiar with Storyboard, and there seem to be many things that must be set up in a very specific way (or specific order) when using it. It’s possible that your image sheet isn’t being declared in the proper “stage” of your Storyboard setup, thus it can’t reverse-locate the imageSheet declaration.

Anyway, try this code in a blank Corona project with no additions… just this base code. If you get the same error, let me know. I use “:setFrame” in my own non-Storyboard apps and it works perfectly.

Brent
[import]uid: 9747 topic_id: 18670 reply_id: 106459[/import]

Actually get the same error when all I have in main.lua is the following. Maybe a bug or a change in API on the recent daily build I have?

Is there a way to show all function methods on an object? (should the below code show functions?

local options = {width = 40,height = 34,numFrames = 2, sheetContentWidth = 40,sheetContentHeight = 68}  
local chest\_imageSheet = graphics.newImageSheet( "media/images/chest\_imageSheet.png", options )  
-- oldChest = display.newImageRect(scene.view, chest\_imageSheet, 1, 40, 34 )  
oldChest = display.newImageRect(chest\_imageSheet, 1, 40, 34 )  
oldChest:setReferencePoint( display.TopLeftReferencePoint )  
oldChest.x, oldChest.y = display.contentWidth \* 0.55, display.contentHeight \* 0.75  
oldChest:setFrame(2) -- TODO: testing - delete afterwards  
  
-- ==\> attempt to call method 'setFrame' (a nil value)  
  
function dump(path,t,depth)  
 for k,v in pairs(t) do  
 print(path..k..' = ', v, " ", type(v))  
 if (type(v) == "table") then  
 if depth \<= 0 then return end  
 dump(path..k..'.',v,depth-1)  
 end  
 end  
end  

Actually “Utils.dump(“oldChest :”, oldChest, 5)” gives the following:

oldChest :\_proxy = userdata: 0xbbb6414 userdata  
oldChest :\_class = table: 0x181c740 table  
oldChest :\_class.removeEventListener = function: 0x18f0570 function  
oldChest :\_class.initProxy = function: 0x18f0550 function  
oldChest :\_class.addEventListener = function: 0x18dee20 function  
oldChest :\_class.\_\_index = table: 0x181c740 table  
oldChest :\_class.\_\_index.removeEventListener = function: 0x18f0570 function  
oldChest :\_class.\_\_index.initProxy = function: 0x18f0550 function  
oldChest :\_class.\_\_index.addEventListener = function: 0x18dee20 function  
oldChest :\_class.\_\_index.\_\_index = table: 0x181c740 table  
oldChest :\_class.\_\_index.\_\_index.removeEventListener = function: 0x18f0570 function  
oldChest :\_class.\_\_index.\_\_index.initProxy = function: 0x18f0550 function  
oldChest :\_class.\_\_index.\_\_index.addEventListener = function: 0x18dee20 function  
oldChest :\_class.\_\_index.\_\_index.\_\_index = table: 0x181c740 table  
oldChest :\_class.\_\_index.\_\_index.\_\_index.removeEventListener = function: 0x18f0570 function  
oldChest :\_class.\_\_index.\_\_index.\_\_index.initProxy = function: 0x18f0550 function  
oldChest :\_class.\_\_index.\_\_index.\_\_index.addEventListener = function: 0x18dee20 function  
oldChest :\_class.\_\_index.\_\_index.\_\_index.\_\_index = table: 0x181c740 table  
oldChest :\_class.\_\_index.\_\_index.\_\_index.\_\_index.removeEventListener = function: 0x18f0570 function  
oldChest :\_class.\_\_index.\_\_index.\_\_index.\_\_index.initProxy = function: 0x18f0550 function  
oldChest :\_class.\_\_index.\_\_index.\_\_index.\_\_index.addEventListener = function: 0x18dee20 function  
oldChest :\_class.\_\_index.\_\_index.\_\_index.\_\_index.\_\_index = table: 0x181c740 table  
  

[import]uid: 140210 topic_id: 18670 reply_id: 106462[/import]

Strange. In my apps, I use different size image frames, and thus define them individually instead of just “numFrames=”. Maybe you could try this? It might make a difference.

local options = {  
 frames = {  
 { x=, y=, width=, height= },  
 { x=, y=, width=, height= }  
 },  
 sheetContentWidth=, sheetContentHeight=  
}  

Brent Sorrentino
Ignis Design
[import]uid: 9747 topic_id: 18670 reply_id: 106465[/import]