[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]

## (Not Using Pysics) How do you write a snapToGrid() function? Started by AngelaMcCall Dec 12 2019 01:24 PM

5 replies to this topic
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

### AngelaMcCall

[GLOBAL: userInfoPane.html]
AngelaMcCall
• Enthusiast

• 52 posts
• Corona SDK

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
```

Ange

[TOPIC: post.html]
#2

### cyberparkstudios

[GLOBAL: userInfoPane.html]
cyberparkstudios
• Contributor

• 577 posts
• Corona SDK

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.

[TOPIC: post.html]
#3

### AngelaMcCall

[GLOBAL: userInfoPane.html]
AngelaMcCall
• Enthusiast

• 52 posts
• Corona SDK

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.

:-) Ange

[TOPIC: post.html]
#4

### cyberparkstudios

[GLOBAL: userInfoPane.html]
cyberparkstudios
• Contributor

• 577 posts
• Corona SDK

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

• sporkfin likes this

[TOPIC: post.html]
#5

### StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
• Contributor

• 842 posts
• Corona SDK

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.

• sporkfin and AngelaMcCall like this

[TOPIC: post.html]
#6

### AngelaMcCall

[GLOBAL: userInfoPane.html]
AngelaMcCall
• Enthusiast

• 52 posts
• Corona SDK

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

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

• AngelaMcCall likes this

[topic_controls]

[/topic_controls]