{"id":500,"date":"2011-11-23T23:08:18","date_gmt":"2011-11-23T22:08:18","guid":{"rendered":"http:\/\/www.aymericlamboley.fr\/blog\/?p=500"},"modified":"2014-11-01T14:58:14","modified_gmt":"2014-11-01T13:58:14","slug":"box2d-sound-spectrum","status":"publish","type":"post","link":"http:\/\/www.aymericlamboley.fr\/blog\/box2d-sound-spectrum\/","title":{"rendered":"Box2D Sound Spectrum"},"content":{"rendered":"<p>This week is really challenging : my second year school project has started this week. It&#8217;s a team project with a graphic designer, a designer, a project manager and me as a developer. Our concept sounds very promising!<\/p>\n<p>No matter, this short introduction explained that I&#8217;m really busy, so this experimentation <strong>is not perfect<\/strong> due to a lack of time&#8230;<br \/>\nAnyway, <strong><a href=\"http:\/\/www.aymericlamboley.fr\/blog\/wp-content\/uploads\/2011\/11\/index.html\" target=\"_blank\">click here<\/a><\/strong> to see a sound spectrum made with Box2D and the Citrus Engine using BitmapData.<\/p>\n<p><!--more--><\/p>\n<p>To create this effect, I used Box2D <em>ApplyImpulse<\/em> method on my Bars. I also used one Rope Joint by bar to link them all to an horizontal platform and try to not make them bounces everywhere. Uncomment the line <em>box2D.visible = true;<\/em> to see box2d objects with joints (don&#8217;t forget to comment stage bitmap addChilded).<br \/>\nThere is a bug, sometimes objects pass between two bars and move them. I tried to change some object params like density, friction, restitution&#8230; but can&#8217;t find a good result.<\/p>\n<p>Here is a part of the code :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport Box2DAS.Common.V2;\r\n\r\n\timport graphics.BarEqualizerArt;\r\n\timport graphics.ElementCircleArt;\r\n\timport graphics.ElementSquareArt;\r\n\r\n\timport objects.BarEqualizer;\r\n\timport objects.Element;\r\n\r\n\timport utils.Const;\r\n\r\n\timport com.citrusengine.core.CitrusEngine;\r\n\timport com.citrusengine.core.State;\r\n\timport com.citrusengine.objects.platformer.Platform;\r\n\timport com.citrusengine.physics.Box2D;\r\n\r\n\timport flash.display.Bitmap;\r\n\timport flash.display.BitmapData;\r\n\timport flash.media.SoundMixer;\r\n\timport flash.utils.ByteArray;\r\n\timport flash.utils.setTimeout;\r\n\t\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class SoundSpectrumState extends State {\r\n\t\t\r\n\t\tprivate var _ce:CitrusEngine;\r\n\t\t\r\n\t\tprivate var _vectBars:Vector.<BarEqualizer>;\r\n\t\t\r\n\t\tprivate var _ba:ByteArray;\r\n\r\n\t\tpublic function SoundSpectrumState() {\r\n\t\t\t\r\n\t\t\tsuper();\r\n\t\t\t\r\n\t\t\t_ce = CitrusEngine.getInstance();\r\n\t\t\t\r\n\t\t\t_vectBars = new Vector.<BarEqualizer>();\r\n\t\t\t_ba = new ByteArray();\r\n\t\t}\r\n\t\r\n\t\toverride public function initialize():void {\r\n\t\t\t\r\n\t\t\tsuper.initialize();\r\n\t\t\t\r\n\t\t\tConst.bmpDStage = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0);\r\n\t\t\tConst.bmpDStage.draw(stage);\r\n\t\t\t\r\n\t\t\tvar bmpStage:Bitmap = new Bitmap(Const.bmpDStage);\r\n\t\t\t\/\/addChild(bmpStage);\r\n\t\t\t\r\n\t\t\tvar box2D:Box2D = new Box2D(\"Box2D\");\r\n\t\t\tbox2D.visible = true;\r\n\t\t\tadd(box2D);\r\n\t\t\t\r\n\t\t\tvar borderLeft:Platform = new Platform(\"borderLeft\", {y:stage.stageHeight >> 1, height:stage.stageHeight});\r\n\t\t\tadd(borderLeft);\r\n\t\t\t\r\n\t\t\tvar borderRight:Platform = new Platform(\"borderRight\", {x:stage.stageWidth, y:stage.stageHeight >> 1, height:stage.stageHeight});\r\n\t\t\tadd(borderRight);\r\n\t\t\t\r\n\t\t\tvar borderTop:Platform = new Platform(\"borderTop\", {x:stage.stageWidth >> 1, width:stage.stageWidth});\r\n\t\t\tadd(borderTop);\r\n\t\t\t\r\n\t\t\tvar borderBottom:Platform = new Platform(\"borderBottom\", {x:stage.stageWidth >> 1, y:350, width:stage.stageWidth});\r\n\t\t\tadd(borderBottom);\r\n\t\t\t\r\n\t\t\tvar barEqualizer:BarEqualizer;\r\n\t\t\tfor (var i:uint = 0; i < Const.NBR_BAR; ++i) {\r\n\t\t\t\tbarEqualizer = new BarEqualizer(\"barEqualizer\" + i, {x:22.5 + Const.BarEqualizerWidth * i, y:stage.stageHeight, width:Const.BarEqualizerWidth, height:Const.BarEqualizerHeight, view:BarEqualizerArt});\r\n\t\t\t\tadd(barEqualizer);\r\n\t\t\t\t_vectBars.push(barEqualizer);\r\n\t\t\t\tbarEqualizer.initJoint(borderBottom, 22.5 + Const.BarEqualizerWidth * i);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t_ce.sound.playSound(\"music\");\r\n\r\n\t\t\tsetTimeout(_addElements, 2500);\r\n\t\t}\r\n\t\t\r\n\t\tprivate function _addElements():void {\r\n\t\t\t\r\n\t\t\tvar element:Element;\r\n\t\t\tfor (var j:uint = 0; j < 12; ++j) {\r\n\t\t\t\telement = new Element(\"Element\" + j, {x: 40 + 40 * j, y:50, radius:Math.random() > 0.5 ? Const.ELEMENT_RADIUS : 0});\r\n\t\t\t\telement.view = element.radius == Const.ELEMENT_RADIUS ? ElementCircleArt : ElementSquareArt;\r\n\t\t\t\tadd(element);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\t\r\n\t\toverride public function update(timeDelta:Number):void {\r\n\t\t\t\r\n\t\t\tsuper.update(timeDelta);\r\n\t\t\t\r\n\t\t\tSoundMixer.computeSpectrum(_ba, true);\r\n\t\t\t\r\n\t\t\tfor (var i:uint = 0; i < Const.NBR_BAR; ++i) {\r\n\t\t\t\t\r\n\t\t\t\t_vectBars[i].body.ApplyImpulse(new V2(0, -_ba.readFloat() * Const.STRENGTH), _vectBars[i].body.GetWorldCenter());\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\toverride public function destroy():void {\r\n\t\t\t\r\n\t\t\tsuper.destroy();\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>The Box2D Bar class :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package objects{\r\n\r\n\timport Box2DAS.Common.V2;\r\n\timport Box2DAS.Dynamics.Joints.b2RopeJoint;\r\n\timport Box2DAS.Dynamics.Joints.b2RopeJointDef;\r\n\r\n\timport com.citrusengine.objects.PhysicsObject;\r\n\timport com.citrusengine.objects.platformer.Platform;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class BarEqualizer extends PhysicsObject {\r\n\r\n\t\tpublic function BarEqualizer(name:String, params:Object = null) {\r\n\t\t\t\r\n\t\t\tsuper(name, params);\r\n\t\t}\r\n\t\t\t\r\n\t\toverride public function destroy():void {\r\n\t\t\t\r\n\t\t\tsuper.destroy();\r\n\t\t}\r\n\r\n\t\toverride public function update(timeDelta:Number):void {\r\n\t\t\t\r\n\t\t\tsuper.update(timeDelta);\r\n\t\t}\r\n\r\n\t\toverride protected function createBody():void {\r\n\t\t\t\r\n\t\t\tsuper.createBody();\r\n\t\t\t\r\n\t\t\t_body.SetFixedRotation(true);\r\n\t\t}\r\n\t\t\r\n\t\tpublic function initJoint(platform:Platform, posX:uint):void {\r\n\t\t\t\r\n\t\t\tvar jointDefPlatform:b2RopeJointDef = new b2RopeJointDef();\r\n\t\t\tjointDefPlatform.Initialize(body, platform.body, body.GetPosition(), new V2(posX \/ _box2D.scale, platform.body.GetPosition().y));\r\n\t\t\t\r\n\t\t\tvar joint:b2RopeJoint = b2RopeJoint(_box2D.world.CreateJoint(jointDefPlatform));\r\n\t\t\tjoint.m_maxLength = 3;\r\n\t\t}\r\n\r\n\t}\r\n}<\/pre>\n<p>And Bar graphics art : <\/p>\n<pre lang=\"actionscript3\" line=\"1\">package graphics {\r\n\r\n\timport utils.Const;\r\n\r\n\timport flash.display.BitmapData;\r\n\timport flash.display.DisplayObject;\r\n\timport flash.events.Event;\r\n\timport flash.geom.Point;\r\n\timport flash.geom.Rectangle;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class BarEqualizerArt extends AArt {\r\n\r\n\t\tpublic function BarEqualizerArt() {\r\n\r\n\t\t\tsuper();\r\n\t\t\t\r\n\t\t\t_art.graphics.clear();\r\n\t\t\t_art.graphics.beginFill(Math.random() * 0xFFFFFF);\r\n\t\t\t_art.graphics.drawRect(0, 0, Const.BarEqualizerWidth, Const.BarEqualizerHeight);\r\n\t\t\t_art.graphics.endFill();\r\n\r\n\t\t\t_bmpD = new BitmapData(Const.BarEqualizerWidth, Const.BarEqualizerHeight);\r\n\t\t\t_bmpD.draw(_art);\r\n\t\t}\r\n\r\n\t\toverride protected function _ef(evt:Event):void {\r\n\t\t\t\r\n\t\t\tvar point:Point = new Point((this as DisplayObject).localToGlobal(new Point()).x - Const.BarEqualizerWidth * 0.5, (this as DisplayObject).localToGlobal(new Point()).y - Const.BarEqualizerHeight * 0.5);\r\n\t\t\tConst.bmpDStage.applyFilter(_bmpD, _bmpD.rect, point, _setBitmapFilter());\r\n\t\t\tConst.bmpDStage.fillRect(new Rectangle(point.x, 0, Const.bmpDStage.width, Const.bmpDStage.height), 0);\r\n\t\t\tConst.bmpDStage.copyPixels(_bmpD, _bmpD.rect, point, null, null, true);\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>Objects drop (after music start) don't use the bitmap data to render graphics but a simple Sprite. This is not optimized!<br \/>\nTo make it properly use only one bitmap data (no sprite) and one enter frame in the stat class. Then call a render method on each object (bars and other objects). Finally think to use  : bitmapData.lock() and bitmapData.unlock() (and make your bitmap data update between them) for a better control.<\/p>\n<p><a href=\"http:\/\/www.aymericlamboley.fr\/blog\/wp-content\/uploads\/2011\/11\/SoundSpectrum.zip\">The zip file<\/a>.<\/p>\n<p>If I have some time to focus on it, I will make some improvements... but it's not my priority. You should have enough information to make a cool Sound Spectrum with box2d \ud83d\ude09<br \/>\n<a href=\"http:\/\/www.youtube.com\/watch?v=zPqVFfT4Kck\" target=\"_blank\"><br \/>\nOh and the music is an Abba cover song, made by Therion!<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This week is really challenging : my second year school project has started this week. It&#8217;s a team project with a graphic designer, a designer, a project manager and me as a developer. Our concept sounds very promising! No matter, this short introduction explained that I&#8217;m really busy, so this experimentation is not perfect due &hellip; <a href=\"http:\/\/www.aymericlamboley.fr\/blog\/box2d-sound-spectrum\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Box2D Sound Spectrum<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[4,115,51,33,114],"tags":[20,15,95,96,27,103,34,104,105],"_links":{"self":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/500"}],"collection":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/comments?post=500"}],"version-history":[{"count":12,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/500\/revisions"}],"predecessor-version":[{"id":1285,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/500\/revisions\/1285"}],"wp:attachment":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/media?parent=500"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/categories?post=500"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/tags?post=500"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}