Skip to content
Niket Shah edited this page Mar 12, 2019 · 15 revisions

Rapid Router Documentation

Things you need to know about the app.

Introduction

Rapid Router is an educational game aimed at children aged between five and twelve years with the goal of teaching the basic programming mechanisms. It presents children with the challenge to guide a van on a virtual street map to its destination, while having to avoid driving off the street or crossing red lights. The van receives its instructions through a program written either in the visual programming language Blockly or Python. Blockly consists of blocks representing program statements and control structures, such as if-statements or loops, which can be composed into a program via dragging and dropping, connecting them together, etc.

Glossary

Command (program.js)

Command is a program instruction such as move forward, turn left, repeat, if etc.

Stack (program.js)

Stack is last-in-first-out structure used to store the commands for program execution. Commands themselves can push to the stack as they are executed.

AnimationQueue (animation.js)

animationQueue is a 2D array of animations. Each subarray is executed atomically (you can only pause between subarrays). Example shown below:

[  
   [  
      {  
         "type":"playSound",
         "description":"starting sound",
         "animationLength":820
      }
   ],
   [  
      {  
         "type":"playSound",
         "description":"starting engine"
      },
      {  
         "type":"highlight",
         "description":"Blockly highlight: move_forwards",
         "blockId":1
      },
      {  
         "type":"van",
         "id":0,
         "vanAction":"FORWARD",
         "fuel":98,
         "description":"van move action: FORWARD"
      }
   ],
   [  
      {  
         "type":"van",
         "id":0,
         "destinationID":0,
         "vanAction":"DELIVER",
         "fuel":98,
         "description":"van delivering"
      },
      {  
         "type":"playSound",
         "description":"stopping engine"
      },
      {  
         "type":"popup",
         "id":0,
         "popupType":"WIN",
         "popupMessage":"Congratulations! You've aced it. ",
         "totalScore":20,
         "maxScore":20,
         "routeCoins":{  
            "whole":10,
            "half":0,
            "zero":0
         },
         "instrCoins":{  
            "whole":10,
            "half":0,
            "zero":0
         },
         "pathLengthScore":10,
         "maxScoreForPathLength":10,
         "instrScore":10,
         "maxScoreForNumberOfInstructions":10,
         "performance":"scorePerfect",
         "pathScoreDisabled":false,
         "description":"win popup"
      },
      {  
         "type":"playSound",
         "description":"win sound"
      },
      {  
         "type":"onStopControls",
         "description":"onStopControls"
      },
      {  
         "type":"playSound",
         "description":"stopping engine"
      }
   ]
]

Model (model.js)

Model contains the state of the program, like:

  • Map
  • Van
  • Timestamp
  • Traffic lights
  • Cows

How do the Blockly / Python programs control the character animations?

In short, when the Play button is clicked, following things happen:

  1. Code written by user is compiled into Commands (one block translates to one command) which are placed on the stack of a Program.
  2. Commands are executed modifying the Model and adding to animationQueue
  3. Animations from the queue are performed

As the program is run, each command is popped off the stack and executed. Complex commands can push new elements (commands) onto the stack, for example repeat or if will push their bodies.

There are two timers in model.

  • movementTimestamp is incremented on movement of the van and is used for calculating puffing up time at the moment
  • timestamp is incremented on any action that results in highlighting a block such as moving forward, checking loop conditions

Drawing

Grid coordinate system

The map of the game is a 10 by 8 grid. The origin of the map is bottom left corner. Location of different map elements are specified using this coordinate system. These coordinates are hereafter called grid coordinates.

Raphael coordinate system

Our game is animated using RaphaelJS, a javascript library for creating and animating svgs. All the elements on the map are drawn on a Raphael canvas object. The origin of a Raphael object is the top left corner. When creating an object on the canvas, the top left corner of the border of the object is placed on the specified coordinates. For example, the van shown in the picture was created using the following code.

paper.image(ocargo.Drawing.raphaelImageDir + CHARACTER_URL, 100, 100, CHAR_HEIGHT, CHAR_WIDTH);

Road letters

Road letter is a set of letter combination that represents the orientation of the road segment placed. Straight road segments are either placed horizontally(H) or vertically(V). Orientation of turns are determined relative to the centre point of the turn. L-shape turn is represented by UR as there are connections to the top and right node from the centre node. T-shape junction is considered to be down as the middle branch points downwards. The mapping of letters to orientation is shown in the table below.

Road letters Picture
H
V
UL
UR
DL
DR
up
down
left
right

Character's height and width

Height and width referenced in the code refers to the character when it's facing right. However, when you create a Raphael object for the character, you need to specify the size the other way round as all the characters are by default facing up.

paper.image(ocargo.Drawing.raphaelImageDir + CHARACTER_URL, 0, 0, CHAR_HEIGHT, CHAR_WIDTH);

How is the character placed on the map?

The character is always placed on the left lane facing away from the origin node. calculateCharacterInitialPosition() returns the location where the character should be first placed, then the character is rotated about the centre of the grid to be on the right side of the grid. At last, the svg is rotated 90 degrees clockwise to face away from the CFC as it originally faces up.

Is it the same for CFC?

Yes, the only difference is that the offset for CFC is constant.

Animation

animationQueue

animationQueue is a 2D array which stores animation object that specifies what animation or sound to be played next. stepAnimation() will perform all the animations in the same subarray, and wait until the animation with the longest duration to finish before moving on to the next subarray.

Animate character's movement

TurnLeft/TurnRight/TurnAround

Each turning animation is equivalent to a rotation of the character svg about a point, which shares the same y-coordinate as the centre of the character svg. The rotation point's coordinates are expressed in character svg's coordinate system, which allows us to reuse the transformation for different turns (van facing different direction at the beginning of the turn).

As the size and shape of the svg will affect the location of the rotation points, the coordinates can be determined by calling getRotationPointXForXXXX() and getRotationPointY() methods, these will take into account the height and width of the svg canvas of the characters. Below shows the calculation in detail.

coorinates of centre of svg = (height/2, width/2)
rotationPointX = centre.x + radius
rotationPointY = centre.y