Framer for Games: Side-Scrolling Endless Runner

Robert Mion
Framer
Published in
3 min readJun 30, 2016

Core mechanic: Effectively switching a layer’s states to generate the appearance of endless randomness

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 the Framer project

In most endless runner-style games, the player is locked to moving left or right — possibly also able to jump — while the world changes around them.

In attempts to recreate this mechanic — albeit in a much simpler fashion — I grant the player access to a box’s vertical position via a ‘Jump’ button, while a smaller box repeatedly zips by at a random rate.

Setting up the player and the ‘Jump’ button

The player’s box is a regular layer with one attached animation triggered when the ‘Jump’ button is clicked. When the animation finishes, another animation is triggered, returning the box to its initial state.

# Player and animations
player = new Layer
y: 803
x: 95
rotation: 0
backgroundColor: “white”
jumping = new Animation
layer: player
properties:
y: player.y — 300
rotation: 180
time: 0.2
falling = new Animation
layer: player
properties:
y: player.y
delay: 0.3
time: 0.3
jumping.onAnimationEnd ->
falling.start()
falling.onAnimationEnd ->
player.rotation = 0
# Jump Button
jumpBtn = new Layer
y: 1134
width: 750
backgroundColor: "black"
Utils.labelLayer(jumpBtn, "Jump")
jumpBtn.style = fontSize: "42px"
jumpBtn.on Events.Click, ->
jumping.start()

Configuring the obstacle

Just another simple layer, except this layer has an additional state, ‘passed’. I am also hooking into two events for this layer:

  1. change:x — if this layer overlaps the player’s box, it’s game over
  2. StateDidSwitch — if the game over screen was triggered, leave the game scene as is and update the game over screen to display the total number of jumps (stored in a counter variable discussed next). Otherwise (i.e. if the game over screen was not triggered), increment the jump counter variable and reset this layer, thereby continuing the game
# Obstacle
obstacle = new Layer
x: 750
y: 852
width: 151
height: 151
backgroundColor: “red”
obstacle.states.animationOptions = curve: “linear”
obstacle.states.add
passed:
x: -150
obstacle.on Events.StateDidSwitch, ->
if obstacle.states.current == “passed”
if gameOver.visible
Utils.labelLayer(gameOver, “Jumps: #{jumps}”)
gameOver.style = fontSize: “72px”
obstacle.states.switchInstant “default”
else if !gameOver.visible
jumps += 1
Utils.delay Utils.randomNumber(0,3), ->
obstacle.states.next()
obstacle.on “change:x”, ->
if (obstacle.x > player.x && obstacle.x < player.maxX) && (obstacle.y > player.y && obstacle.y < player.maxY)
gameOver.visible = yes

Keeping score

Score is stored in a variable and incremented each time the state of the small ‘obstacle’ box changes from ‘passed’ to ‘default’ — meaning it didn’t collide with the player’s box, further meaning the player successfully jumped over the small box. This is shown in the code above in the ‘else’ statement.

Start the game

To kick off the game, I use Framer’s Utils object’ delay method, passing in a random number between 0 and 3, at which time the obstacle layer will switch to its next state — in this case, ‘passed’.

# Initialize Game
Utils.delay Utils.randomNumber(0,3), ->
obstacle.states.next()

Framer/CoffeeScript mechanics highlighted here

  • Event listeners
  • Layer states
  • Global variables
  • Utility methods

--

--