Swap image on Tap event

Hi All,

I have a series of blue squares placed in a row on the screen. When a blue square is selected (tap event), it should be replaced with a yellow square. Currently, when a square is tapped, it is replaced with a yellow square, but the x,y coordinates of the yellow square are set to the x,y location of the tap event, not the x,y coordinates of the blue square that was tapped. Thus, it doesn’t fit perfectly over the original square, and the blue square underneath can be seen. (See screenshot image). I’ve spent hours on this. Can anyone assist me in figuring this out? Thanks in advance! Tom

Here’s my current code…

display.setStatusBar( display.HiddenStatusBar ) numSquares = 5 numSpaces = 6 totalsquareWidth = 0.9 \* display.contentWidth totalSpaceWidth = 0.1 \* display.contentWidth oneSquareWidth = 80 oneSpaceWidth = 20 local myLocation local function squareTapped(event) square = display.newImageRect("../images/1024x1024-yellow-square.png", oneSquareWidth, oneSquareWidth ) square.x = event.x -- Need x coord of blue square square.y = event.y -- Need y coord of blue square end squares = {} -- declare a table that all the square objects will be saved in local squareIndex = 0 for horzCount = 1, numSquares do -- will loop until the number represented by numSquares is reached squareIndex = squareIndex + 1 local square = display.newImageRect("../images/1024x1024ice-blue-square.png", oneSquareWidth, oneSquareWidth ) square.name = squareIndex local function onSquareTap(self, event) print("Tap event on: " .. self.name) square = display.newImageRect("../images/1024x1024-yellow-square.png", oneSquareWidth, oneSquareWidth ) --[[\>\>\>\>\>\>\> To Do: Get x, y of blue square that was tapped, and update x, y of yellow square \<\<\<\<\<\<\< --]] square.x = event.x -- Need to set x,based on blue square, not Tap event square.y = event.y -- Need to set y based on blue square, not Tap event return true end square.tap = onSquareTap square:addEventListener("tap", square) if(horzCount % 10 == 1) -- 1st object in the row, requires a preceeding spacer amount of space before first object then square.x = oneSpaceWidth + (oneSquareWidth) square.y = 100 myLocation = {myLocationIndex = squareIndex, myLocationX = square.x, myLocationY = square.y} print( myLocation.myLocationIndex, myLocation.myLocationX, myLocation.myLocationY) else square.x = (oneSpaceWidth + (oneSquareWidth)) + ((horzCount - 1) \* (oneSpaceWidth + oneSquareWidth)) square.y = 100 squares[squareIndex] = square squares[squareIndex].squareIndex = squareIndex -- This table keeps track of each individual square printed to the screen myLocation = {myLocationIndex = squareIndex, myLocationX = square.x, myLocationY = square.y} print( myLocation.myLocationIndex, myLocation.myLocationX, myLocation.myLocationY) end -- end if count is modulus 1 end -- end horzCount

Here’s a screenshot…

Here’s the Corona Simulator Output text.

18:02:36.700 18:02:36.700 Copyright (C) 2009-2016 C o r o n a L a b s I n c . 18:02:36.700 Version: 3.0.0 18:02:36.700 Build: 2016.2830 18:02:36.700 Platform: iPhone / x64 / 6.1 / GeForce 9500 GT/PCIe/SSE2 / 3.3.0 / 2016.2830 / en\_US | US | en\_US | en 18:02:36.700 Loading project from: C:\Users\Tom\Desktop\Mobile Development\swapImageOnTap 18:02:36.700 Project sandbox folder: C:\Users\Tom\AppData\Local\Corona Labs\Corona Simulator\Sandbox\swapimageontap-4AE556F91ED37EC4C5AE76ACC0AC017E\Documents 18:02:36.700 1 100 100 -- (index, x coord, y coord of blue squares) 18:02:36.700 2 200 100 18:02:36.700 3 300 100 18:02:36.710 4 400 100 18:02:36.710 5 500 100 18:02:36.710 ---------------------------------- 18:02:40.755 Tap event on: 1 18:02:47.335 Tap event on: 3

Try using tables to store the objects. Then it would be easier to retrieve them and also its values are the ‘updated values’ as it is pass by reference.

You can also look into ‘contentBounds’ of an object (good info but not so relevant to your case)

Sample :

local function tutorialSquare() -- Draw 'red squares' local redSquares = {} for i=1,10 do local square = display.newRect( 50, 75\*i, 50, 50 ) square:setFillColor( 1,0,0 ) redSquares[i] = square end local blueSquares = {} for i=1,10 do local square = display.newRect( 250, 75\*i, 50, 50 ) square:setFillColor( 0,0,1 ) blueSquares[i] = square -- listener function square:touch( event ) if event.phase == "began" then print( "You touched the square! at index " .. i ) -- Move this object to the 'red square' transition.to( square, { x = redSquares[i].x } ) return true end end square:addEventListener( "touch", square ) end end

Hi yosu,

Thank you for your response and for your example.

I’ll rework my code taking your code into consideration and see how it goes.

Thanks,

Tom

Check out this blog:

https://coronalabs.com/blog/2013/11/26/tutorial-techniques-for-swapping-images/

scottrules44,

Thanks for the link!  There is a boat-load of great information on that page.

I’m going to do some testing.

Thanks,

Tom

@RedEldorado

Do you actually need to use images for the squares?  My thinking would be to use display.newRoundedRect for the squares, with the fill colour set to blue, and then when the user taps on the square just set its fill colour to yellow.  It would be more efficient unless you specifically need the images for some reason.

Hi Appletreeman,

I probably don’t have to use images. I’ll keep display.newRoundedRect in mind, once I actually get this working.

Ultimately, this display will be comprised of multiple rows and columns, and when one is selected (or deselected), in addition to displaying a different color, it will write the identity of the object selected to a file or SQLite. So, in addition to swapping colors, this will require using tables to store all the objects in, code to identify the specific object that was selected, and code to save it to a file/db.

Thanks for your input.

Would recommend using a file instead of db (SQL). I used db last time, and it was noticeably slow which forced me to use a file instead. 

@RedEldorado: there are a few things you can do to solve this problem - as @Appletreeman indicated, you could use the setFillColor method (https://docs.coronalabs.com/api/type/ShapeObject/setFillColor.html) to simply change the coloring of the square. That’s a nice elegant solution, as it keeps the number of display objects you create as low as possible. It’s worth noting that you can use setFillColor on display.newImage objects, too - so if you wanted to use a PNG instead of a RoundedRect for whatever reason, you could still employ that same solution by using a single PNG that is all white for all your squares, and apply the blue/yellow tint as appropriate using setFillColor.

However, I think it’s important that you at least understand the other possible solution, as it will benefit you down the line as you create more complicated touch/tap handler functions. The “event” table that gets passed into a touch/tap handler function contains a bunch of key/value pairs - as you’ve discovered, event.x and event.y contain the X and Y coordinates of the touch event itself. But event.target is a reference to the display object that was touched and/or tapped - so event.target.x and event.target.y will give you the X and Y coordinates of the touched square. I also see that you used a table listener for your tap handler (meaning you get not only the event table passed into your function, but also a “self” variable that references the tapped object), so you could simply use self.x and self.y to get the X and Y coordinates of the tapped square. How you handle this problem is not so important (all these solutions will work equally well), but understanding the event tables getting passed to your handler functions will pay dividends over time.

One other unrelated thing I’ve noticed: you use the variable “square” a whole lot, and don’t always localize it. This could potentially lead to issues down the line where you’re unable to manipulate one of your display objects because you’ve overwritten the variable used to point to it. You’re putting your squares into a table, which is great - and why this isn’t likely to be an actual problem for you in this particular project (at least not yet), but it’s good to try and establish good habits surrounding scoping your variables. Using the same variable name over and over without localizing it every time can lead to unexpected (and potentially difficult to debug) issues later on. Just my two cents of uninvited advice. :wink:

@schroederapps,

Thanks for your detailed response and feedback regarding my original code. Unfortunately, the code is a bit of a hodgepodge and needs to be rebuilt from the ground up.

* Applying a colored tint to a png sounds interesting. I’ll have to check that out.

* Using “self.x and self.y to get the X and Y coordinates of the tapped square” is another great idea.

As per using “square” a lot, and not always localizing them, yeah, I’m still working on getting a grasp on the whole localization and scope conceptualization. Square started out as just a convenient reference and cascaded from there.

I appreciate your feedback!  Thanks

@yosu, thanks for the file (over SQL) recommendation, for speed. Figuring out how to save all the data is going to be another big learning curve. Thanks.

@schroederapps,

Using “self.x and self.y to get the X and Y coordinates of the tapped square” works great, answered my question and solved my problem!

Thanks!

Thank you all for your responses!  I appreciate it.

Tom

Try using tables to store the objects. Then it would be easier to retrieve them and also its values are the ‘updated values’ as it is pass by reference.

You can also look into ‘contentBounds’ of an object (good info but not so relevant to your case)

Sample :

local function tutorialSquare() -- Draw 'red squares' local redSquares = {} for i=1,10 do local square = display.newRect( 50, 75\*i, 50, 50 ) square:setFillColor( 1,0,0 ) redSquares[i] = square end local blueSquares = {} for i=1,10 do local square = display.newRect( 250, 75\*i, 50, 50 ) square:setFillColor( 0,0,1 ) blueSquares[i] = square -- listener function square:touch( event ) if event.phase == "began" then print( "You touched the square! at index " .. i ) -- Move this object to the 'red square' transition.to( square, { x = redSquares[i].x } ) return true end end square:addEventListener( "touch", square ) end end

Hi yosu,

Thank you for your response and for your example.

I’ll rework my code taking your code into consideration and see how it goes.

Thanks,

Tom

Check out this blog:

https://coronalabs.com/blog/2013/11/26/tutorial-techniques-for-swapping-images/

scottrules44,

Thanks for the link!  There is a boat-load of great information on that page.

I’m going to do some testing.

Thanks,

Tom

@RedEldorado

Do you actually need to use images for the squares?  My thinking would be to use display.newRoundedRect for the squares, with the fill colour set to blue, and then when the user taps on the square just set its fill colour to yellow.  It would be more efficient unless you specifically need the images for some reason.

Hi Appletreeman,

I probably don’t have to use images. I’ll keep display.newRoundedRect in mind, once I actually get this working.

Ultimately, this display will be comprised of multiple rows and columns, and when one is selected (or deselected), in addition to displaying a different color, it will write the identity of the object selected to a file or SQLite. So, in addition to swapping colors, this will require using tables to store all the objects in, code to identify the specific object that was selected, and code to save it to a file/db.

Thanks for your input.

Would recommend using a file instead of db (SQL). I used db last time, and it was noticeably slow which forced me to use a file instead.