Marcin Bunsch

Lead Software Dev at Groove

< Back to home

Dotz

tl;dr You can check out the game here.

Recently, to learn new programming techniques, I've been reading up on game development.

I thought it would be a fun experiment to try to clone an existing game, so I would be able to focus on the game engine and code, with the hard part of game design already done. During vacation, I've been playing Dots by Betaworks, which is why I chose it as a source of inspiration.

I've decided to build it in CraftyJS and Brunch as a build tool. I've also added jQuery for some basic DOM manipulation.

Here's the result, which I've named Dotz: http://marcinbunsch.github.io/dotz. It is a simplified clone, so it only consists of one level in which you have to connect as many dots as possible in 20 moves.

As I found the whole experiment mighty interesting, I also thought it would be fun to highlight a few interesting problems I bumped into and how I solved them.

The Init

To start up the scene in Crafty, you call Crafty.init with the width and height of the scene, and the DOM element which will hold the scene.

var el = document.getElementById('container')
Crafty.init(300, 300, el)

All following code examples assume that the scene is already initialized.

The Dot

The first, most obvious thing, is drawing a dot. I started up with a single dot entity, achieving a dot via border-radius:

Crafty.e("2D, DOM, Color")
  .color('red')
  .css({ 'border-radius': '10px' })
  .attr({ x: 10, y: 10, w: 20, h: 20 })

This draws red dot on the scene with a radius of 20 px, located at [10, 10].

Crafty.e creates a new instance of a component. An instance can be a mixture of multiple components, in this case it's 2D, DOM and Color. You can also create your own components.

The Grid

The next step was to draw the grid of dots. At this point I decided to introduce gravity. Crafty makes it really simple - you need to tell crafty that this instance supports gravity and which component is a blocker. I've introduced a new component using Crafty.c, called Platform, which will stop the fall.

Crafty.c("Platform")

// Platform instance
Crafty.e("2D, DOM, Color, Platform")
  .color('#ccc')
  .attr({ x: 0, y: 100, w: 100, h: 2 })

// Dot
Crafty.e("2D, DOM, Color, Gravity")
  .gravity("Platform")
  .gravityConst(0.5)
  .color('red')
  .css({ 'border-radius': '10px' })
  .attr({ x: 10, y: 10, w: 20, h: 20 })

Once you run this, the red dot will appear at [10,10] and fall until it touches the Platform at [10, 100].

What is really awesome, is that you can make different entities have the Platform component. I've used this to stack dots on top of each other, like this:

Crafty.c("Platform")

// Platform instance
Crafty.e("2D, DOM, Color, Platform")
  .color('#ccc')
  .attr({ x: 0, y: 100, w: 100, h: 2 })

// First Dot
Crafty.e("2D, DOM, Color, Gravity, Platform")
  .gravity("Platform")
  .gravityConst(0.5)
  .color('red')
  .css({ 'border-radius': '10px' })
  .attr({ x: 10, y: 10, w: 20, h: 20 })

// Second Dot
Crafty.e("2D, DOM, Color, Gravity, Platform")
  .gravity("Platform")
  .gravityConst(0.5)
  .color('red')
  .css({ 'border-radius': '10px' })
  .attr({ x: 10, y: 40, w: 20, h: 20 })

This makes two dots appear and fall until the bottom one touches the platform. The top one stops as soon as it touches the bottom one. Stacking achieved with no extra coding required - win!

However, the problem I've reached here was that I wanted the dots to be separated by empty space. Crafty's gravity does not respect the margins from css, so I took another approach. Instead of doing dots, I've drawn squares, with dots drawn inside the squares. The squares became the entity which would handle gravity, collision and mouse events, and the dot was just a div centered within the square. Check out the Dot class in the Dotz source code to see the actual solution.

So when you look at the grid of dots in Dotz, what you actually see is actually 8 columns of stacked squares and an invisible platform underneath.

The Line

In Dots, when the player touches a dot and starts moving the finger around the stage, a line is drawn between the center of the dot and the location of the finger.

When working on this, I bumped into a problem very quickly. Crafty does not facilitate drawing lines between two points on the stage. However, it does expose rotation of entities:

Crafty.e("2D, DOM, Color")
  .attr({ rotation: 45, x: 10, y: 10, w: 100, h: 1 })

This draws a line at a 45 degree angle.

Luckily, there's always math. By knowing the start point (the center of the pressed dot) and the end point (location of the mouse or finger) I can calculate the length and angle of the line. Here's an excerpt from the Dotz source code which does this:

drawToLocation: (x,y) =>
  distance_x = x - @startPoint.x
  distance_y = y - @startPoint.y

  sum = Math.pow(distance_x, 2) + Math.pow(distance_y, 2)
  length = Math.sqrt(sum)

  angle = Math.atan2(distance_y, distance_x) * 180 / Math.PI

  @entity.attr({
    w: length,
    rotation: angle
  })

@startPoint is the location where the Line starts, @entity is the Crafty entity which gets modified as the mouse or finger moves around the stage.

The Move

The last step was connecting all previous elements. This is where I moved away from Crafty and into game logic.

The rules are following:

  1. You may only connect dots of the same color
  2. The dots must be adjacent on the x or y axis, not diagonally.
  3. You cannot connect dots that are already connected.
  4. When you move back on the line, you deselect the last dot. I call this backtracking
  5. Once the mouse of finger are released and if the dots has at least one connection, remove all connected dots from the stage and drop replacements on the top

All of this logic was done in the Move class. It is the most complex class in Dotz - it's using all game engine elements mentioned before. I won't go into it here, as I'm focusing more on Crafty in this article, but if you are interested, I recommend you check it out on github.

The End

I have to say, cloning an existing game is a FANTASTIC programming exercise. Because game design has been done, you can focus on the code and the tools that you're using.

CraftyJS is a very capable framework for 2D games. It gets extra points for seamless support of touch events. If you're interested in giving CraftyJS a go, here's a great article on DailyJS by the creator of Crafty: Making Games with JavaScript and Crafty

Side note - Brunch is great, and I've ended up building my own skeleton for easier bootstrapping of hacks: http://github.com/marcinbunsch/hackstrap-brunch.

I hope you've enjoyed this write-up. If you have any questions, hit me up on Twitter.