# When Box2D meets Concentration

There are a lot of Concentration games around the web, but… what happens when Box2D meets concentration? Tiles stack and fall down, moving from their starting position and making it harder to remember tile position.

Take this prototype:

How would you improve the game?

Look at the source code (uncommented – I’ll tell you later why…)

```package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;
public class Main extends Sprite {
private var world:b2World=new b2World(new b2Vec2(0,10),true);
private var worldScale:Number=30;
private var pickedTiles:int=0;
private var tiles:Array=[2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19];
private var pickedBodies:Array=new Array();
private var idle:Timer;
public function Main() {
for (var i:int=1; i<=tiles.length*10; i++) {
var from:int=Math.floor(Math.random()*tiles.length);
var to:int=Math.floor(Math.random()*tiles.length);
var temp:int=tiles[from];
tiles[from]=tiles[to];
tiles[to]=temp;
}
debugDraw();
wall(320,470,600,20);
wall(10,280,20,400);
wall(630,280,20,400);
for (i=0; i<6; i++) {
for (var j:int=0; j<6; j++) {
brick(170+60*i,120+60*j,60,60,j*6+i);
}
}
}
private function wall(pX:Number,pY:Number,w:Number,h:Number):void {
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.position.Set(pX/worldScale,pY/worldScale);
var polygonShape:b2PolygonShape=new b2PolygonShape();
polygonShape.SetAsBox(w/2/worldScale,h/2/worldScale);
var fixtureDef:b2FixtureDef=new b2FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.density=2;
fixtureDef.restitution=0.4;
fixtureDef.friction=0.5;
var theWall:b2Body=world.CreateBody(bodyDef);
theWall.CreateFixture(fixtureDef);
}
private function brick(pX:Number,pY:Number,w:Number,h:Number,val:int):void {
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.position.Set(pX/worldScale,pY/worldScale);
bodyDef.type=b2Body.b2_dynamicBody;
bodyDef.userData=new Object();
bodyDef.userData.tile=new Tile();
bodyDef.userData.tile.buttonMode=true;
bodyDef.userData.tile.gotoAndStop(1);
bodyDef.userData.picked=false;
bodyDef.userData.tileValue=val;
var polygonShape:b2PolygonShape=new b2PolygonShape();
polygonShape.SetAsBox(w/2/worldScale,h/2/worldScale);
var fixtureDef:b2FixtureDef=new b2FixtureDef();
fixtureDef.shape=polygonShape;
fixtureDef.density=2;
fixtureDef.restitution=0.4;
fixtureDef.friction=0.5;
var theWall:b2Body=world.CreateBody(bodyDef);
theWall.CreateFixture(fixtureDef);
}
private function destroyBrick(e:MouseEvent):void {
if (pickedTiles<2) {
var pX:Number=mouseX/worldScale;
var pY:Number=mouseY/worldScale;
world.QueryPoint(queryCallback,new b2Vec2(pX,pY));
}
}
private function queryCallback(fixture:b2Fixture):Boolean {
var touchedBody:b2Body=fixture.GetBody();
if (touchedBody.GetUserData()!=null && ! touchedBody.GetUserData().picked) {
pickedBodies.push(touchedBody);
pickedTiles++;
touchedBody.GetUserData().picked=true;
touchedBody.GetUserData().tile.gotoAndStop(tiles[touchedBody.GetUserData().tileValue]);
}
if (pickedTiles==2) {
stage.removeEventListener(MouseEvent.CLICK,destroyBrick);
idle=new Timer(1000);
idle.start();
}
return false;
}
private function process(e:TimerEvent):void {
idle.removeEventListener(TimerEvent.TIMER, process);
if (tiles[pickedBodies[0].GetUserData().tileValue]==tiles[pickedBodies[1].GetUserData().tileValue]) {
removeChild(pickedBodies[0].GetUserData().tile);
removeChild(pickedBodies[1].GetUserData().tile);
world.DestroyBody(pickedBodies[0]);
world.DestroyBody(pickedBodies[1]);
}
else {
pickedBodies[0].GetUserData().tile.gotoAndStop(1);
pickedBodies[1].GetUserData().tile.gotoAndStop(1);
pickedBodies[0].GetUserData().picked=false;
pickedBodies[1].GetUserData().picked=false;
}
pickedBodies=new Array();
pickedTiles=0;
}
private function debugDraw():void {
var debugDraw:b2DebugDraw = new b2DebugDraw();
var debugSprite:Sprite = new Sprite();
debugDraw.SetSprite(debugSprite);
debugDraw.SetDrawScale(worldScale);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
debugDraw.SetFillAlpha(0.5);
world.SetDebugDraw(debugDraw);
}
private function update(e:Event):void {
world.Step(1/30,10,10);
world.ClearForces();
for (var b:b2Body=world.GetBodyList(); b; b=b.GetNext()) {
if (b.GetUserData()) {
b.GetUserData().tile.x=b.GetPosition().x*worldScale;
b.GetUserData().tile.y=b.GetPosition().y*worldScale;
}
}
world.DrawDebugData();
}
}
}```

A complete prototype in a few more than 100 lines, hope to see some good games out of it.

215 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 10000000
// 2 Cars
// 2048
// Avoider
// Ballz
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Breakout
// Bricks
// Columns
// CubesOut
// Dots
// DROP'd
// Dudeski
// Eskiv
// Filler
// Fling
// Globe
// HookPod
// Hundreds
// InkTd
// Iromeku
// Lumines
// Magick
// MagOrMin
// Maze
// Memdot
// Nano War
// Nodes
// o:anquan
// Ononmin
// Pacco
// Phyballs
// Platform
// Poker
// Pool
// Poux
// Pudi
// qomp
// Racing
// Renju
// SameGame
// Security
// Sling
// Slingy
// Sokoban
// Splitter
// Sproing
// Stack
// Stairs
// Stringy
// Sudoku
// Tetris
// Threes
// Toony
// Turn
// TwinSpin
// vvvvvv
// Wordle
// Worms
// Yanga
// Zhed
// zNumbers