(Not Using Pysics) How do you write a snapToGrid() function?

Hi all,

I’ve a block sliding game, all working nicely as far as logic goes.
At the moment I have calculated a “padding” around all the tiles/bricks to help detect when they are nearing other tiles/bricks and then if needs be the moving tile/brick stops.

However, it’s all a bit messy.

If the player slides the tiles/bricks to quickly and they don’t stop perfectly within the grid lines, the bricks only need to be 1 or 2 units/pixels out and the other bricks around it wont move.

I thought to solve this, and make the user experience more friendly, I could snap a brick/tile to a column or row when it’s anchor is near the column/row centre.

All the maths already exist in my game.

I’ve used a transition.moveTo() function, which does what it says, but then I can’t free the brick.

The code is run through on a mili-second by mili-second basis, so I can’t wrap a loop or counter around it.

I’ve tried setting a property to the tile such as brick.snapped = true. But as the code runs in miliseconds, al that happens is I nudge the brick and tile before it’s identified as being near and snapped back again.

-- SNAP TO GRID local function snapToGridVertical(brickIn) local snapToZone = 10 local brick = brickIn -- test if brick is 1x3 tall or 1x2 tall if( brick.height == mod.gvBrick\_1x3 + (brick.strokeWidth \* 2 ) ) then print("Brick is 1x3 Vertical") if (brick.y \>= (mod.setRow\_1(brickIn) - snapToZone) and brick.y \<= (mod.setRow\_1(brickIn) + snapToZone)) then transition.moveTo( brick, { y = mod.setRow\_1(brickIn), time=500} ) end elseif( brick.height == mod.gvBrick\_1x2 + (brick.strokeWidth \* 2 ) )then print("Brick is 1x2 Vertical") end end

Thanks in advance for your help.

Ange

you can try to look over roaming gamers free template for a puzzle-slide game.

https://marketplace.coronalabs.com/app-templates/sliding-puzzle-game-templates

I have some old old code from a slider puzzle I did several years ago, but it is very old-school…  and I think in that code, it was a simple-slide-puzzle game, I just assigned an event listener to each tile object (puzzle piece).  Then on a touch event on any of the pieces, code would look for an empty cell either vertically or horizontally from the tapped-piece’s position in the grid.  Once found it would shift that piece one cell in that direction and snap into place.

You likely will find the free sample code of roaming gamer most helpful.

good luck with your game.

Hiya, thanks for taking the time to reply.
I did originally look at this game and code. There is no actual “sliding” going on, the tile you click on identifies where the empty place is and jumps to it.

But thanks all the same for suggesting.

:slight_smile: Ange

Not sure if this will help, but some short code to give you some ideas on how to snap image into place.

The functions are from snippets I found years ago on the forum, tweaked a little by me messing around with it.

local function POINT\_IN\_RECT( pointX, pointY, rect ) local left = rect.x - (rect.width/2) local top = rect.y - (rect.height/2) if pointX \>= left and pointX \<= left + rect.width and pointY \>= top and pointY \<= top + rect.height then return true else return false end end local spot = display.newRect(200, 200, 80, 80) local img = display.newImageRect("Textures/anyImage.png", spot.width, spot.height) img.x = 100 img.y = 100 img.initX = img.x img.initY = img.y function img:touch( event ) if event.phase == "began" then self.markX = self.x self.markY = self.y elseif event.phase == "moved" then self.x = (event.x - event.xStart) + self.markX self.y = (event.y - event.yStart) + self.markY elseif event.phase == "ended" then if POINT\_IN\_RECT( img.x, img.y, spot ) then -- =========================================================================== -- IF MORE THEN HALF OF THE IMAGE HAS BEEN DRAGGED INTO THE LOCATION -- (A RECTANGLE), ONCE LET GO, EITHER JUST ASSIGN THE DRAGGED OBJECT X,Y TO -- THE SPOT(RECTANGLES) X,Y ..... OR A LITTLE MORE 'JUICE' AND USE A QUICK -- TRANSTION TO SNAP IT INTO PLACE -- =========================================================================== -- YOU CAN DO THIS --img.x = spot.x --img.y = spot.y -- OR BETTER ,YOU CAN DO THIS transition.to(img, {time = 100, x = spot.x, y = spot.y}) -- =========================================================================== -- this can be improved on in several ways, using transitions easing properties -- which can give the transition action a little more bounce. -- you can also improve the collision detection (maybe detect rect within a rect) -- rather then just the center point of the image -- =========================================================================== else -- return image to its starting postion transition.to(img, {time = 200, x = img.initX, y = img.initY}) end end return true end img:addEventListener( "touch", img )

I think this might be close to what you are trying to do.

Good Luck

You can also quantize your position (based on your tile dimensions, say), by doing

local floor = math.floor function Quantize (x, y) local col = floor((x - Left) / CellWidth) -- these other names are values you've defined local row = floor((y - Top) / CellHeight) -- or computed beforehand, of course return col, row -- will be 0-based end function ToPosition (col, row) local x = Left + col \* CellWidth local y = Top + row \* CellHeight return x, y end

You can get the contentBounds of your objects or add / subtract half the dimensions if you want to quantize a corner, which sounds right if trying to avoid intrusions.

ToPosition () is to go the other way, getting the top-left corner of your cell, though you could obviously adjust that if, say, the center was more useful.

Hey there,

I am so pleased you posted this, I’ve been “playing” and my approach has resulted into something similar using the transitions.

So it feels nice to know my logic has resulted in the right direction, even if my path was not a direct line there but zigzagging all the way along.

I’ve not used a rectangle by which to compare my objects positioning to, just it’s x,y values but this does give me food for thought. 

Thanks
Angela