Framer for Games: Sliding Blocks

Part 8 of Framer for Games series

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.

  1. Raid HQ Character Selection [Thursday, June 23]
  2. Endless Runner [Thursday, June 30]
  3. Guitar Hero [Thursday, July 7]
  4. Card Match [Thursday, July 14]
  5. Snake [Thursday, July 21]
  6. Dropping Ball Catcher [Thursday, July 28]
  7. Arcade Joystick [Thursday, August 4]
  8. Sliding Blocks [Thursday, August 11]
  9. Vertical Platformer [Thursday, August 18]
  10. Pong [Thursday, August 25]
  11. 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.

A simulation of this prototype: numbered square pieces moving along a grid

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