Background FX live session

Categories Actionscript, game art, Starling

Using my Open Source Particle Designer tool, Angulex to design the background effects in the MathSumRun Trophy Room.

After exploring a bit with the different designs, I settle for a simple colored background particles with some nice starlight textures. This is typical with my design process, I usually start and explore different and more complicated designs, then subtract elements that I find they have too much of a distraction characteristic. It’s a fine line from just enough decorum to over doing it.

The tool lets me explore different options with ease, but it does have some quirks and UI bugs (layering order mishaps). I (obviously) know how to bypass them and until I am releasing MathSumRun, I don’t think I will have the time to fix the bugs.

Also the different textures and backgrounds needed have to be hard-coded, which is probably the first thing I will need to change in the future (after bug-fixing).

For now, it does it’s job perfectly and I can focus on the development of my game 🙂

Share this
Facebooktwitter

Quick (dirty) buttons for your Starling app

Categories Actionscript, games, Starling

Sometimes you need to control parts of you app for testing so a a quick way to build some buttons in Starling is very useful. In my case, I needed to test different parts of MathSumRun and adding an external library for this purpose only is an overkill.

buttons controll

Here is the dirty code for this:

ActionScript

  1. package com.cosmindolha.mathsumrun
  2. {
  3.     //import com.cosmindolha.mathsumrun.DataDispatcher;
  4.     import com.utils.Delay;
  5.     import starling.display.Canvas;
  6.     import starling.display.Sprite;
  7.     import starling.events.Touch;
  8.     import starling.events.TouchEvent;
  9.     import starling.events.TouchPhase;
  10.     import starling.text.TextField;
  11.     /**
  12.      * ...
  13.      * @author Cosmin Dolha
  14.      */
  15.     public class AppControl extends Sprite
  16.     {
  17.         //private var disp:DataDispatcher;
  18.        
  19.         public function AppControl()
  20.         {
  21.             x = 1150;
  22.             y = 50;
  23.             //disp = DataDispatcher.getDisp();
  24.            
  25.             button("Game Over", onGameOver, 0, 0, 75);
  26.             button("Level Done", onLevelFinished, 0, 30, 75);
  27.             button("End Game", onGameEnded, 0, 60, 75);
  28.             button("Time Up!", onTimeUp, 0, 90, 75);
  29.            
  30.             incrButtons("Stage", onPrevStage, onNextStage, 120);
  31.             incrButtons("Level", onPrevLevel, onNextLevel, 150);
  32.             incrButtons("Qstn", onPrevQuestion, onNextQuestion, 180);
  33.  
  34.            
  35.         }
  36.         private function onPrevQuestion():void
  37.         {
  38.            
  39.         }
  40.         private function onNextQuestion():void
  41.         {
  42.            
  43.         }      
  44.         private function onPrevLevel():void
  45.         {
  46.            
  47.         }
  48.         private function onNextLevel():void
  49.         {
  50.            
  51.         }  
  52.         private function onPrevStage():void
  53.         {
  54.            
  55.         }
  56.         private function onNextStage():void
  57.         {
  58.            
  59.         }
  60.         private function onTimeUp():void
  61.         {
  62.             trace("on time up");
  63.         }      
  64.         private function onGameEnded():void
  65.         {
  66.             trace("on game end");
  67.         }
  68.         private function onLevelFinished():void
  69.         {
  70.             trace("level finished press");
  71.         }      
  72.         private function onGameOver():void
  73.         {
  74.             trace("game over press");
  75.         }
  76.         private function incrButtons(str:String, prevFunc:Function, nextFunc:Function, y:Number):void
  77.         {
  78.             button("< -", prevFunc, 0, y, 35);
  79.             var labelField:TextField = new TextField(35, 20, str, "Verdana", 9, 0xffffff, false);
  80.             labelField.touchable = false;
  81.             addChild(labelField);
  82.             labelField.x = 20;
  83.             labelField.y = y;
  84.             button("->", nextFunc, 40, y, 35);
  85.         }
  86.         private function button(str:String, func:Function, x:Number, y:Number, w:Number):void
  87.         {
  88.             var sp:Sprite = new Sprite();
  89.             sp.x = x;
  90.             sp.y = y;
  91.            
  92.             var canvas:Canvas = new Canvas();
  93.             canvas.beginFill(0xffffff);
  94.            
  95.             canvas.drawRectangle(0, 0, w, 25);
  96.             canvas.endFill();
  97.            
  98.             var txt:TextField = new TextField(w, 20, str, "Verdana", 9, 0xffffff, false);
  99.             txt.touchable = false;
  100.             canvas.alpha = .2;
  101.            
  102.             sp.addChild(canvas);
  103.             sp.addChild(txt);
  104.             sp.addEventListener(TouchEvent.TOUCH, onTouch);
  105.             function onTouch(e:TouchEvent):void
  106.             {  
  107.                 var touch:Touch = e.getTouch(stage, TouchPhase.BEGAN);
  108.                 if (touch == null) return
  109.                 func();
  110.                 canvas.alpha = .5;
  111.                 var returnDelay:Delay = new Delay(returnAlpha, 100);
  112.                 function returnAlpha():void
  113.                 {
  114.                     canvas.alpha = .2;
  115.                 }
  116.             }
  117.             addChild(sp);
  118.            
  119.         }
  120.     }
  121.  
  122. }

And the Delay class:

ActionScript

  1. package com.utils
  2. {
  3.     import flash.events.TimerEvent;
  4.     import flash.utils.Timer;
  5.     public class Delay
  6.     {
  7.         private var timer:Timer;   
  8.         private var delayedFunction:Function;
  9.         public function Delay(functionToDelay:Function, delayMilisec:Number)
  10.         {
  11.             this.delayedFunction = functionToDelay;
  12.             timer = new Timer(delayMilisec, 1);
  13.             timer.addEventListener(TimerEvent.TIMER_COMPLETE, callDelayedFunction);
  14.             timer.start();
  15.         }  
  16.         private function callDelayedFunction(event:TimerEvent):void
  17.         {
  18.             timer.removeEventListener(TimerEvent.TIMER_COMPLETE, callDelayedFunction);
  19.             delayedFunction();
  20.         }
  21.     }
  22. }
Share this
Facebooktwitter

Starling Particle Designer – HackTM2015

Categories Actionscript, games

This weekend I went to HackTM2015 and started the development of my Starling Particle Designer.

ParticleDesigner

This tool will be used to make better Particle Effects for my MathSumRun game.

The scope is to design the particle effects directly on my iPad, so I can push the effects to the limits, while still achieving good FPS.

The Starling Particle Designer source sits on GitHub at: ParticleDesigner

To test it on your iPad, you need to have a Jailbreak device and get the ipa file from here.
To install it on my iPad I use ifunbox.

Development is done for iPad 2 with iOS 6. Support for retina devices will be added at a later time.

Share this
Facebooktwitter

If you upgraded to Starling 1.7 and your app is broken, check your assets manager

Categories Actionscript

After updating to Starling 1.7, my game stopped compiling. After a quick debugging, I found the problem in the assets manager. Narrowing it down, it seems that the getTexture returns null if I try to load an atlas texture.

To fix it, change:

ActionScript

  1. var elemTexture:Texture = resources.assets.getTexture("elements");         
  2. var elemXml:XML = new XML(resources.assets.getXml("elements"));
  3. var elemAtlas:TextureAtlas = resources.assets.getTextureAtlas("elements");

To:

ActionScript

  1. var elemAtlas:TextureAtlas = resources.assets.getTextureAtlas("elements");

My assets are named: “elements.png” and “elements.xml”

In my game resources is a separate class that just loads all the elements, and the assets var is set to public, it looks like this:

ActionScript

  1. package com.cosmindolha.mathrun
  2. {
  3.     import flash.events.TimerEvent;
  4.     import flash.filesystem.File;
  5.  
  6.     import starling.events.Event;
  7.     import starling.utils.AssetManager;
  8.  
  9.     /**
  10.      * ...
  11.      * @author ... Cosmin Dolha ~ contact@cosmindolha.com
  12.      */
  13.     public class Resource
  14.     {
  15.         public var assets:AssetManager;
  16.        
  17.         private var disp:DataDispatcher;
  18.                
  19.         public function Resource(dd:DataDispatcher)
  20.         {
  21.             disp = dd;
  22.  
  23.             assets = new AssetManager();
  24.            
  25.             assets.keepAtlasXmls = true;
  26.    
  27.             var appDir:File = File.applicationDirectory;
  28.            
  29.             assets.enqueue(appDir.resolvePath("assets"));
  30.            
  31.             assets.addEventListener(Event.IO_ERROR, onError)
  32.  
  33.             assets.loadQueue(function(ratio:Number):void
  34.             {
  35.             if (ratio == 1.0)
  36.             {
  37.                 //trace("asstes loaded");
  38.                 disp.assetsLoaded();
  39.             }
  40.             });
  41.         }
  42.  
  43.         private function onError(e:Event):void
  44.         {
  45.                 trace(e.data);
  46.         }
  47.        
  48.     }
  49.  
  50. }
Share this
Facebooktwitter

Using JSON and actionscript 3 to display a leaderboard, back-end php and MySQL

Categories Actionscript, JSON

I have worked with XML for many years, now I had a chance to use JSON on a little pice of a project. The documentation might be confusing for many people so here is a simple easy to understand use of JSON with actionscript 3 and php, MySQL.

The idea is to list the top 10 users in a MySQL database based on their score.

Here is how the php part looks like:

  1. &lt; ?php include 'config.php'; include 'opendb.php'; $sql = "SELECT username, score FROM app_table ORDER BY score DESC LIMIT 10"; $result = mysql_query($sql); $objArray = array(); while ($row = mysql_fetch_assoc($result)) { $objArray[] = $row; } echo json_encode($objArray); include 'closedb.php'; ?&gt;

The trick is to save each result in an array $objArray[] so you will be able to properly use the JSON object in actionscript as an array.

In flash you would have to put a data grid component on the stage (ctr+f7 to open the components panel), name it myDataGrid.

ActionScript

  1. var serverAdress:String = "http://yourserver/"
  2. myDataGrid.columns = ["username", "score"];
  3. var request:URLRequest = new URLRequest();
  4. request.url = serverAdress + "top.php?"+Math.random();
  5. request.requestHeaders=[new URLRequestHeader("Content-Type", "application/json")];
  6. request.method=URLRequestMethod.GET;
  7. var loader:URLLoader=new URLLoader();
  8. loader.addEventListener(Event.COMPLETE, receive);
  9. function receive(e:Event):void
  10. {
  11. var myResults:Object = JSON.parse(e.target.data);
  12.  
  13. for (var i:int = 0; i &lt; myResults.length; i++)
  14. {
  15. myDataGrid.addItem(myResults[i]);
  16. }
  17.  
  18. }
  19. loader.load(request);

To see the top username you would do:

ActionScript

  1. trace(myResults[0].username);

Now I think this is a lot more simpler that dealing with XML, although XML might have it’s strong points, JSON is a lot smaller so especially when dealing with large sets of data, JSON will save bandwidth and also might save some processing time on the client (I have to test this out).

Share this
Facebooktwitter

Dynamic access your xml data

Categories Actionscript

Let’s say you have this xml data in an external file data.xml:

ActionScript

  1. <app>
  2.   <usa>
  3.    <Alabama pic="somepic.jpg" info="some info" />
  4.    <Alaska pic="somepic.jpg" info="some info" />
  5.    <Arizona pic="somepic.jpg" info="some info" />
  6.   </usa>
  7.  </app>

If you want to access your Alaska info data in actionscript, using just the name Alaska in a variable you can do:

ActionScript

  1. // assuming you loaded your external xml in xmlData
  2.  
  3. var country:String = "Alaska"
  4.  
  5. xmlData.usa.children().(name() == country).@info
Share this
Facebooktwitter

Record audio from your microphone (works on android too)

Categories Actionscript, android, Flash apps

Download fla, download apk file (for android mobiles)

Here is a little script that allows you to record audio from your microphone and play it back.

ActionScript

  1. package  {
  2.    
  3.     import flash.display.MovieClip;
  4.     import flash.events.Event;
  5.     import flash.media.SoundChannel;
  6.     import flash.media.Sound;
  7.     import flash.utils.ByteArray;
  8.     import flash.system.Security;
  9.     import flash.events.SampleDataEvent;
  10.     import flash.media.Microphone;
  11.     import flash.events.MouseEvent;
  12.     import flash.events.ActivityEvent;
  13.    
  14.     public class Rec extends MovieClip {
  15.        
  16.         private var mic:Microphone;
  17.         private var soundBytes:ByteArray;
  18.         private var soundMic:Sound;
  19.         private var micSoundChannel:SoundChannel;
  20.        
  21.         public function Rec()
  22.         {
  23.             micSoundChannel = new SoundChannel();
  24.             soundMic = new Sound();
  25.             soundBytes  = new ByteArray();
  26.             mic = Microphone.getMicrophone();
  27.             mic.setSilenceLevel(5, 1000);
  28.             mic.gain = 80; //0 to 100
  29.             mic.rate = 44;
  30.            
  31.             recOn.stop();
  32.             recOn.visible = false
  33.             activityMC.visible = false;
  34.            
  35.             speakRec.visible = false;
  36.             playButton.enabled = false;
  37.            
  38.             micButton.addEventListener(MouseEvent.CLICK, startRecording);
  39.             playButton.addEventListener(MouseEvent.CLICK, startPlayback);
  40.            
  41.             addEventListener(Event.ENTER_FRAME, onFrame);//
  42.         }
  43.         private function onFrame(e:Event)
  44.         {
  45.             if (mic.activityLevel > 0)
  46.             {
  47.                 activityMC.maskMC.scaleY = mic.activityLevel / 100;
  48.             }
  49.         }
  50.         private function startRecording(e:MouseEvent)
  51.         {
  52.             micButton.enabled = false;
  53.             playButton.enabled = true;
  54.            
  55.             recOn.visible = true;
  56.             activityMC.visible = true;
  57.            
  58.             recOn.play();
  59.            
  60.             soundBytes  = new ByteArray();
  61.            
  62.             mic.addEventListener(SampleDataEvent.SAMPLE_DATA, micRecord);
  63.            
  64.         }
  65.         private function startPlayback(e:MouseEvent)
  66.         {
  67.             micButton.enabled = true;
  68.             playButton.enabled = false;
  69.            
  70.             speakRec.visible = true;
  71.             activityMC.visible = false;
  72.             recOn.visible = false;
  73.             recOn.stop();
  74.            
  75.             mic.removeEventListener(SampleDataEvent.SAMPLE_DATA, micRecord);
  76.             mic.setLoopBack(false);
  77.  
  78.             soundBytes.position = 0;
  79.             soundMic.addEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler);
  80.            
  81.             micSoundChannel = soundMic.play();
  82.             micSoundChannel.addEventListener( Event.SOUND_COMPLETE, micPlaybackComplete );
  83.            
  84.         }
  85.         private function micRecord(e:SampleDataEvent)
  86.         {
  87.                while (e.data.bytesAvailable)
  88.             {
  89.                 var sample:Number = e.data.readFloat();
  90.                 soundBytes.writeFloat(sample);
  91.             }
  92.         }
  93.         function playbackSampleHandler(e:SampleDataEvent):void
  94.         {
  95.             for (var i:int = 0; i < 8192 && soundBytes.bytesAvailable > 0; i++)
  96.             {  
  97.                 var sample:Number = soundBytes.readFloat();
  98.                 e.data.writeFloat(sample);
  99.                 e.data.writeFloat(sample);
  100.                 //we write the data twice because there are 2 channels (stereo)
  101.             }
  102.         }
  103.         private function micPlaybackComplete(e:Event)
  104.         {
  105.             soundMic.removeEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler);
  106.             speakRec.visible = false;
  107.             playButton.enabled = true;
  108.         }
  109.     }
  110. }
Share this
Facebooktwitter

Access totalFrames from an external loaded swf

Categories Actionscript

Use UILoader to load the external swf and on the INIT event we will be able to get the loaded swf total frames. Don’t forget to drag the UILoader component (from the components panel, ctr+F7) into your library, and import fl.containers.*.

ActionScript

  1. import fl.containers.*;
  2.  
  3. var swfLoader:UILoader = new UILoader();
  4. swfLoader.scaleContent = false;
  5.  
  6. swfLoader.addEventListener(Event.INIT, loader_init);
  7.  
  8. function loader_init(evt:Event):void
  9. {
  10.     var mc:MovieClip = swfLoader.content as MovieClip;
  11.     trace(mc.totalFrames)
  12. }
  13.  
  14. var urlReq:URLRequest = new URLRequest("to_be_loaded.swf");
  15.  
  16. swfLoader.load(urlReq);

I recently used this technique to build video like player (play, stop, seek) for swf’s.

Share this
Facebooktwitter

Simple actionscript text animation engine

Categories Actionscript

This is a very basic text animation engine, but it allows you to build your own animation styles and it’s fairly easy to understand how it works.

Download the source file..

I developed this animation engine while working on the Semicolon Wars game. The whole purpose was to identify punctuations and blank spaces in any given sentence (it’s a punctuation game). Once the function worked as I wanted, I realized that I can use this function as an animation engine.

How it works.

It takes the string you want to animate and for each character in the string it creates a new MovieClip that contains a dynamic TextField.

ActionScript

  1. function animateText(textToAnimate:String, animationType:String){
  2. var totalCharacters:int = textToAnimate.length;
  3. for (var i:int = 0; i&lt; = totalCharacters; i++)
  4. {
  5. var myChar:charMc = new charMc();
  6. textContainer.addChild(myChar);
  7. var mcRef:MovieClip = myChar as MovieClip;
  8. mcRef.name = "myCharMc" + i;
  9. myChar.letterText.autoSize = TextFieldAutoSize.LEFT;
  10. myChar.letterText.text = textToAnimate.charAt(i);
  11. }
  12. }

To create the charMc class, create a dynamic textfield (embed the font, set the Anti-alias for animation), name it “letterText”. With the textfield selected hit “F8” (convert to symbol), type MovieClip, check the “Export to Actionscript” box and in the Class box name it “charMc”.

Now we have to arrange the MovieClips x, y positions.


ActionScript

  1. function animateText(textToAnimate:String, animationType:String)
  2. {
  3. //clean up
  4. while (textContainer.numChildren &gt; 1)
  5. {
  6. textContainer.removeChildAt(textContainer.numChildren-1);
  7. }
  8.  
  9. var margin:int = 20;
  10.  
  11. var cX:int = margin;
  12. var cY:int = margin;
  13.  
  14. var rightLimit:int = textContainer.width - margin;
  15. var totalCharacters:int = textToAnimate.length;
  16.  
  17. var metrics:TextLineMetrics;
  18.  
  19. for (var i:int = 0; i&lt; = totalCharacters; i++) {
  20. var myChar:charMc = new charMc();
  21. textContainer.addChild(myChar);
  22. var mcRef:MovieClip = myChar as MovieClip;
  23. mcRef.name = "myCharMc" + i;
  24. myChar.letterText.autoSize = TextFieldAutoSize.LEFT;
  25. myChar.letterText.text = textToAnimate.charAt(i);
  26. metrics = myChar.letterText.getLineMetrics(0);
  27.  
  28. if (cX &gt; rightLimit)
  29. {
  30. cY += metrics.height;
  31. cX = margin;
  32. var reverCounter:int = i;
  33. while (textToAnimate.charAt(reverCounter) != " ")
  34. {
  35. reverCounter--;
  36. }
  37. for (var lb:int = reverCounter+1; lb &lt; = i; lb++)
  38. {
  39. var myMc:MovieClip = textContainer.getChildByName("myCharMc" + lb) as MovieClip;
  40. myMc.y = cY;
  41. myMc.x = cX;
  42. metrics = myMc.letterText.getLineMetrics(0);
  43. cX += metrics.width;
  44. }
  45. }
  46. else
  47. {
  48. myChar.x = cX;
  49. myChar.y = cY;
  50. cX += metrics.width;
  51. }
  52. animateMc(mcRef, myComboBox.selectedItem.label, i*0.01);
  53. }
  54. }

The metrics = myMc.letterText.getLineMetrics(0); does the trick we need to correctly space the movieclips.

To animate we create a simple animateMc function:

ActionScript

  1. function animateMc(targetMc:MovieClip, animationType:String, delayAmount:Number){
  2.  
  3. switch(animationType){
  4. case "writeOn":
  5. TweenLite.from(targetMc, 1, {alpha:0, ease:Linear.easeOut, overwrite:true, delay:delayAmount});
  6. break;
  7. case "flyIn":
  8. TweenLite.from(targetMc, 1, {alpha:0, z:-500, ease:Sine.easeOut, overwrite:true, delay:delayAmount});
  9. break;
  10. case "3DSpin":
  11. targetMc.visible=false;
  12. targetMc.z = -500;
  13. var myPath:Array = new Array();
  14. myPath.push({z:-200, rotationX:randRange(-360, 360), rotationY:randRange(-360, 360), rotationZ:randRange(-360, 360)});
  15. myPath.push({z:-400, rotationX:randRange(-360, 360), rotationY:randRange(-360, 360), rotationZ:randRange(-360, 360)});
  16. Tweener.addTween(targetMc, {z:0, rotationX:0, rotationY:0, rotationZ:0, _bezier:myPath, time:3, transition:"easeoutquad", delay:delayAmount, onStart:tweenStart});
  17. break;
  18. case "randomColor":
  19. targetMc.visible=false;
  20. TweenLite.from(targetMc, 2, {tint:randomColors[randRange(0, randomColors.length)], rotationZ:randRange(-360, 360), ease:Linear.easeOut, overwrite:true, delay:delayAmount, onStart:tweenStart});
  21. break;
  22. }
  23.  
  24. function tweenStart(){
  25. targetMc.visible=true;
  26. }
  27.  
  28. }

Thanks to the TweenLite and Tweener tween engines you can easily animate any MovieClip propriety (3D position, alpha, color, blur etc).

Get the source files and make some great animations on your own.

Share this
Facebooktwitter