Framer for Games: Sliding Blocks

Core mechanic: using Draggable layers and Framer’s updatePosition method to fix layer positions along a grid
Upcoming games and/or game mechanics in this series
Tune in Thursday mornings for a new entry in this series. I’d love to read your suggestions in the comments.
- Raid HQ Character Selection [Thursday, June 23]
- Endless Runner [Thursday, June 30]
- Guitar Hero [Thursday, July 7]
- Card Match [Thursday, July 14]
- Snake [Thursday, July 21]
- Dropping Ball Catcher [Thursday, July 28]
- Arcade Joystick [Thursday, August 4]
- Sliding Blocks [Thursday, August 11]
- Vertical Platformer [Thursday, August 18]
- Pong [Thursday, August 25]
- Tempest [Thursday, September 1]
Link to Framer Prototype
Remember those old-school puzzles where you moved blocks around to form some sort of picture? This is a digital prototype of that game, using numbers. Because that’s easier.

Game elements
This game only has one real element: the square game piece. The power lies in the prototype’s initialized data and loop that generates all nine pieces.
Initializing the game data
I create an array of numbers that will be cycled through later, and define the properties of each game piece that too will be created later.
# Global variables
# Array with numbers 1-9 arranged out of order
numbers = [7,3,6,5,8,2,1,4]
# Initialize cycle utility for later use in grid loop
cycler = Utils.cycle(numbers)
# Setup parameters for grid items
rows = cols = 3
gutter = 10
width = 200
height = 200
Parent grid wrapper
# Grid wrapper
wrapper = new Layer
backgroundColor: "transparent"
clip: true
width: width * cols + (cols * (gutter - 1))
height: height * rows + (rows * (gutter - 1))
Where the magic happens
A lot is happening here, but I’m hopeful you can step through it using the comments as guidance. I break it down a bit more below.
# Loop to generate grid
for rowIndex in [0...rows]
for colIndex in [0...cols]
# As long as the current grid item is not column 3 and row 3
if (colIndex * rowIndex != 4)
# Create new grid item using global values
cell = new Layer
width: width
height: height
x: colIndex * (width + gutter)
y: rowIndex * (height + gutter)
borderRadius: 2
parent: wrapper
backgroundColor: Utils.randomColor()
clip: yes
# Label each layer with the value from the numbers array
# The next value is queued up using the cycler function
Utils.labelLayer(cell, cycler())
cell.style = fontSize: "72px", color: "black"
# Make this layer draggable
cell.draggable.enabled = yes
# Lock its drag movement to the axis it is initially dragged upon
cell.draggable.directionLock = yes
# Prevent the layer from continuing its movement when depressed
cell.draggable.momentum = no
# Below code is pulled verbatim from Docs:
# layer.draggable.updatePosition(point
# Function: Round numbers to a set amount
round = (number, nearest) ->
Math.round(number / nearest) * nearest
# Drag in increments of 210px
cell.draggable.updatePosition = (point) ->
point.x = round(point.x, 210)
point.y = round(point.y, 210)
return point
- There’s a loop inside a loop, because we are generating boxes in columns that exist within rows
- We want boxes placed everywhere except in the last spot (i.e. the bottom right corner, or spot 9)
- Each box’s label should be the currently cycled number in the array
- We want the box to be draggable, but with several caveats, including directional limitations, removed momentum, and the equivalent of snapping to points in the grid
Framer/CoffeeScript mechanics highlighted here
- Event listeners
- Utility methods
- Control flow
- Global variables