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:
It’s concentration powered by Box2D!!
How would you improve the game?
Look at the source code (uncommented – I’ll tell you later why…)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
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 radToDeg:Number=57.2957795; 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); } } addEventListener(Event.ENTER_FRAME,update); stage.addEventListener(MouseEvent.CLICK,destroyBrick); } 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); addChild(bodyDef.userData.tile); 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(); idle.addEventListener(TimerEvent.TIMER, process); } return false; } private function process(e:TimerEvent):void { idle.removeEventListener(TimerEvent.TIMER, process); stage.addEventListener(MouseEvent.CLICK,destroyBrick); 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(); addChild(debugSprite); 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; b.GetUserData().tile.rotation=b.GetAngle()*radToDeg; } } world.DrawDebugData(); } } } |
A complete prototype in a few more than 100 lines, hope to see some good games out of it.
They can be easily customized to meet the unique requirements of your project.





(13 votes, average: 4.77 out of 5)






This post has 9 comments
serhat
thank you for this wonderful application. I have good idea about this application :)
MC
“invalid file format”… i have flash CS4, is this CS5?
codeBeast
Hi Emanuele.
This is superb. We are in the “edutainment” business ie: teaching English through interactive muyltimedia apps. This is great for that – we used memory pairs before so this is a nice twist. We will add graphics, sounds a timer and levels with the typical padlock menus and perhaps a facebook button to post highscores etc… If you’re interested we can send the link when done. We love your stuff.
Emanuele Feronato
@MC: yes, it’s 5.5 but you can download the free CS6 trial and open it.
@codeBeast: yeah, send me the link, I am doing something similar
Bojan
Here is some idea. You can make something like spell a word, for example lets take a word “Bomb” and when you open all boxes in correct order all blocks get some impulse or word “Red” and when you do it in a right order all block become red and so on.
Veera
nice…
i used it for memory match
When Box2D meets Concentration – Emanuele Feronato « eaflash
[...] on http://www.emanueleferonato.com Share this:TwitterFacebookLike this:LikeBe the first to like [...]
codeBeast
Forgot to ask. IMPORTANT: I am creating game templates and therefore creating tens if not hundreds of games. They are 1024 * 720. BUT every game I ever see is a lot smaller not even 800 * 600. Is there a reason for that. Am I going to have problems using Box2d on games of that size ie: performance issues and why are other games not bigger? Cheers
Anil Canli
Hi,
These are great. But I have just started box2d and I’m looking for your blogs. I need you to write box2d version for your blogs. Because I’m newbie on this and I have downloaded so many versions to check which one matches with your codes :)
Thanks in advance