How do i go about making user tap to place tiles?

Hey! So i’m working on a game and in the game the user will be able to place up to 6 tiles. 

Check out what i mean in this video … Go to 2:10 – He is picking up the plants but what i want is to place a tile. 

https://www.youtube.com/watch?v=l3K63-2MRWc

Another example would be this video in the TylerMakes series. Check out 18:26 . That’s exactly what i want.

https://www.youtube.com/watch?v=m-3YqgLSVAU

Is this possible without any plugins? Just in one file ( Main.lua ) Just be able to place white tiles on a black screen? 

Does anyone have a sample project of this?

NOTE – Tiles will be 10x10 pixels. If that helps.

Hope to hear from you soon!

–SonicX278

Just have an object which can listen for touch events (listening to Runtime is not good practice) and calculate which tile space it is over. You will need to do some basic maths to work out where the touch is, but you should be able to trial and error that into shape.

Can you start me off in the correct direction with some code?

–SonicX278

I have put together something ( nothing very good ) 

So this code lets you draw a 20x20 box. But it puts it where ever you tap. What i want is the kind of thing that’s happening in the TylerMakes tutorial series in my first post.

local tile = {} local tCounter = 1 local BG = display.newRect( display.contentCenterX, display.contentCenterY, display.actualContentWidth, display.actualContentHeight ) local function createTiles(event) if event.phase == "ended" then tile[tCounter] = display.newRect( event.x, event.y, 20, 20 ) tile[tCounter]:setFillColor( 0, 0, 0 ) tile[tCounter].value = tCounter tCounter = tCounter + 1 end end BG:addEventListener( "touch", createTiles )

Thanks!

Let’s say you want to divide the screen into 50x50 squares, you would say that the x and y of any tap on the screen needs to be divided by the number of pixels in any column and row. So, if the screen is (just for this example) 100x100 pixels, with your game having 10x10 rows and columns of squares - if the user taps at location 15x25 that would be the second row and third column. To get column=2 and row=3 from the code you would do:

local numRows, numCols = 10,10 local colWidth, rowHeight = 10,10 local userTapX, userTapY = 15, 25 local userTapCol = math.floor( userTapX / colWidth ) + 1 local userTapRow = math.floor( userTapY / rowHeight ) + 1

The reason I am using floor() and not round() is because an x or y which is higher than a .5 of a value will give you the correct column or row for the tile, but a value of .5 will give you the wrong one. Eg: if the userTapX = 13 it would give you 1 as the column, but userTapX=17 would give you 2. Always round down and add 1 to get the correct value.

So here is a little example of what I’m talking about:

local columnCount = 25 local cellWidth = display.actualContentWidth / columnCount local cellHeight = cellWidth local rowCount = math.ceil( display.actualContentHeight / cellHeight ) for x=0, columnCount do display.newLine( x\*cellWidth,0 , x\*cellWidth,display.actualContentHeight ).strokeWidth = 2 end for y=0, rowCount do display.newLine( 0,y\*cellHeight , display.actualContentWidth,y\*cellHeight ).strokeWidth = 2 end Runtime:addEventListener( "touch", function(e) local c = math.floor( e.x / cellWidth ) + 1 local r = math.floor( e.y / cellHeight ) + 1 print( "Column: "..c, " Row: "..r ) end )

Alternately, you could create the grid as objects, and have them be “tappable”:

local row = 3 local column = 2 local cellWidth = 32 local cellHeight = cellWidth local cell = {} local centerX = display.contentCenterX-50 local centerY = display.contentCenterY-100 local function flipSize(obj) local function objReturn() obj:setFillColor(.75,.5,.25) transition.to(obj,{time=250, alpha=1, xScale=1}) end transition.to(obj,{time=500, xScale=.1, onComplete=objReturn}) end local function handleTile(self, event) if event.phase == "ended" then flipSize(self) print("self.idx = "..self.idx.." self.idy = "..self.idy) return true end end local function createGrid() for x = 1, row do -- column cell[x] = {} for y = 1, column do --row cell[x][y] = display.newRect(x\*cellWidth, y\*cellHeight,cellWidth,cellHeight) cell[x][y].strokeWidth = 1 cell[x][y]:setStrokeColor(1) cell[x][y]:setFillColor(0) cell[x][y].x = y\*(cellWidth)+centerX cell[x][y].y = x\*(cellHeight)+centerY cell[x][y].idx = x cell[x][y].idy = y cell[x][y].tapped = false cell[x][y].type = "ground" cell[x][y].isVisible = true cell[x][y].isHitTestable = true cell[x][y].touch = handleTile cell[x][y]:addEventListener("touch", cell[x][y]) end end end createGrid()

This is a useful option if you’re using sprites, and want to optimize performance by creating all objects at level generation, rather than create them upon user interaction.

Thanks all of you!

@Alex@Panc, Is there a way of your method but just down to just bare bones? Like no shortcuts? 

–SonicX278

Ok so i figured most of it out but im having trouble trying to figure out how this part works…

for x = 1, row do -- column cell[x] = {} for y = 1, column do --row

In this function.

local function createGrid() for x = 1, row do -- column cell[x] = {} for y = 1, column do --row cell[x][y] = display.newRect( x\*cellWidth, y\*cellHeight, cellWidth, cellHeight ) cell[x][y].strokeWidth = 1 cell[x][y]:setStrokeColor(1) cell[x][y]:setFillColor(0) cell[x][y].x = y\*(cellWidth)+centerX cell[x][y].y = x\*(cellHeight)+centerY cell[x][y].touch = handleTile cell[x][y]:addEventListener("touch", cell[x][y]) end end end createGrid()

Any explanation would be awesome!

Thanks!

–SonicX278

Your variable naming is a bit off for the places in the tables you’re using them, but that’s just looping through the columns and then the rows within the columns. The cell[x] = {} is creating a row within the column table.

Actually, a slight performance improvement (with the variable fix) is to do it like this, to avoid extraneous references:

local columns, rows = 2, 3 local cells = {} local function createGrid() for x = 1, columns do -- columns                 local xPos = x\*cellWidth -- pre-calc the position so the multiplication is not over done                 local rowtbl = {} -- pre-create the table as variable to avoid referencing it too often cells[x] = row\_tbl for y = 1, rows do --row local rect = display.newRect( xPos, y\*cellHeight, cellWidth, cellHeight ) rect.strokeWidth = 1 rect:setStrokeColor(1) rect:setFillColor(0) rect.x = y\*(cellWidth)+centerX rect.y = x\*(cellHeight)+centerY rect.touch = handleTile rect:addEventListener("touch", cell[x][y]) rowtbl[y] = rect -- allow direct referencing of the rect when setting it's values end end end createGrid()

In fact, if you were to make sure that all the cells are in the same display group, you don’t need rows and columns at all. You just place them and work out their location from their index in the group. This is fine as long as you don’t move them around in the group or add anything else to mess up their indices.

local columns, rows = 2, 3 local cells = display.newGroup() function cells:getTileAt( col, row ) return cells[ (col-1)\*columns + row ) end local function createGrid() for x = 1, columns do local xPos = x\*cellWidth-cellWidth\*.5+centerX for y = 1, rows do local yPos = y\*cellHeight-cellHeight\*.5+centerY local rect = display.newRect( cells, xPos, yPos, cellWidth, cellHeight ) rect.strokeWidth = 1 rect:setStrokeColor(1) rect:setFillColor(0) rect.touch = handleTile rect:addEventListener( "touch", rect ) rect.getColRow = getRowCol rect.index = cells.numChildren end end end createGrid()

@horacebury this looks intriguing. To be honest, I never thought about optimizing my grid generation, as I assumed a 2d array rendered graphically was simple enough. I’m looking forward to poking around with this while recovering from turkey overload.

I try to optimise as much as possible and after a while it becomes second nature. The reason is because table lookups can be slow in Lua, so when referencing a table on a table on a table on another table it gets to be a performance penalty. I’ve read (on the blog, etc) that where-ever possible you should use the most direct reference to something that you can. So, when iterating over items, it’s always best to grab a reference to them and their container if you’re going to do more than once thing with them. I don’t have a link to hand, but I’m sure “Lua performance” googling would surface useful info.

Having said that, this is probably a good place to start: https://forums.coronalabs.com/topic/15165-tips-optimization-101/

@horacebury we are of the same mind. I’ve been doing some simple testing with table iteration over the last two weeks with the same ideas in mind. Trying to squeeze every last drop out of Lua mem while rendering as many tiles as possible. I know Caleb P has made grand inroads on this front, and we are all looking forward to his tilemap shader!

I’ve been (unsuccessfully) poking around starcrunch’s relatively new table plugin. We were also talking about how hash tables are faster than arrays:

https://stackoverflow.com/questions/12020984/hash-table-why-is-it-faster-than-arrays

Just have an object which can listen for touch events (listening to Runtime is not good practice) and calculate which tile space it is over. You will need to do some basic maths to work out where the touch is, but you should be able to trial and error that into shape.

Can you start me off in the correct direction with some code?

–SonicX278

I have put together something ( nothing very good ) 

So this code lets you draw a 20x20 box. But it puts it where ever you tap. What i want is the kind of thing that’s happening in the TylerMakes tutorial series in my first post.

local tile = {} local tCounter = 1 local BG = display.newRect( display.contentCenterX, display.contentCenterY, display.actualContentWidth, display.actualContentHeight ) local function createTiles(event) if event.phase == "ended" then tile[tCounter] = display.newRect( event.x, event.y, 20, 20 ) tile[tCounter]:setFillColor( 0, 0, 0 ) tile[tCounter].value = tCounter tCounter = tCounter + 1 end end BG:addEventListener( "touch", createTiles )

Thanks!

Let’s say you want to divide the screen into 50x50 squares, you would say that the x and y of any tap on the screen needs to be divided by the number of pixels in any column and row. So, if the screen is (just for this example) 100x100 pixels, with your game having 10x10 rows and columns of squares - if the user taps at location 15x25 that would be the second row and third column. To get column=2 and row=3 from the code you would do:

local numRows, numCols = 10,10 local colWidth, rowHeight = 10,10 local userTapX, userTapY = 15, 25 local userTapCol = math.floor( userTapX / colWidth ) + 1 local userTapRow = math.floor( userTapY / rowHeight ) + 1

The reason I am using floor() and not round() is because an x or y which is higher than a .5 of a value will give you the correct column or row for the tile, but a value of .5 will give you the wrong one. Eg: if the userTapX = 13 it would give you 1 as the column, but userTapX=17 would give you 2. Always round down and add 1 to get the correct value.

So here is a little example of what I’m talking about:

local columnCount = 25 local cellWidth = display.actualContentWidth / columnCount local cellHeight = cellWidth local rowCount = math.ceil( display.actualContentHeight / cellHeight ) for x=0, columnCount do display.newLine( x\*cellWidth,0 , x\*cellWidth,display.actualContentHeight ).strokeWidth = 2 end for y=0, rowCount do display.newLine( 0,y\*cellHeight , display.actualContentWidth,y\*cellHeight ).strokeWidth = 2 end Runtime:addEventListener( "touch", function(e) local c = math.floor( e.x / cellWidth ) + 1 local r = math.floor( e.y / cellHeight ) + 1 print( "Column: "..c, " Row: "..r ) end )