Archive for the 'Flash' Category

Bruce Eckel on Flash

Sunday, February 18th, 2007

Here a great post of Bruce Eckel (author of “Thinking in…” books) on Java, Ajax and surprisingly: Flash.

So here’s my question. Allow for a moment the possibility that, after 10 years, Java is not going to take over the world of RIAs. Further allow that Ajax is just “how JavaScript was supposed to work in the first place,” but that the limitations imposed by browsers, HTML and CSS committees seem unlikely to let it expand beyond its current bounds. What are we going to use to build RIAs? [...] The only obvious solution is Flash.

Simon Brocklehurst pointed out that there are more ugly Flash interfaces than good ones, although I think he is talking about the old do-all-by-yourself hackery of Flash 7-8 since there isn’t many Flex 2 web apps out there yet. I wonder if he saw Picnik.

Eckel highlight a really interesting point: to use Flash as a domain specific language. Do in Flash the interface for your Java/Python/C application. We are waiting for you, Apollo.

Plick time tracker

Sunday, February 11th, 2007

Since I was looking for a way to organize my tasks, I’ve made:
Plick – Time tracker, a tool that help to keep track of what to do and the time spent on doing that.

The main features are the simplicity and that it help to stay in the schedule.

Using Plick is simple:
just specify a task and the time you think will be required to do that (eg: “clean room 15″ = clean the room in 15 minutes)
then, when you are doing that, just click on it and the timer will start.
Plick will keep track of the time spent on each task, in this way you can see if you spent much time than you expected, helping you to make better previsions.

plick.jpg

Memory leaks playing Shoutcast/Icecast streams in Flash

Saturday, February 3rd, 2007

Update: Zach Callear has published a complete shoutcast player in flash without memory leaks based on the tricks described in this post.

Update: For those interested in an easy streaming solution, try haxeVideo.

Trying to play music on the Wii, I've encountered a problem in the flash Sound object.

While you listen to an mp3 in streaming mode: snd.loadSound(url, true), flash will keep in memory the music played.
A Shoutcast/Icecast stream like an Internet radio, is like a never ending mp3, witch take a large amount of memory, and eventually make the player crash. In the Wii this happen after few minutes.

After some googling, I've found that the only solution is to reload the stream after some time, freeing the buffer.
On a pc this can be made every 30 minutes, but on the Wii every 2 minutes.

To avoid the pause when flash reload the stream, is possible to preload in the background another Sound object, and then crossfade the two. In this way there is only an imperceptible glitch due to the lack of synchronization of the two streams.

So here how to do a radio player in flash without the memory leak:

  1. In a Sound object snd1 load the stream
  2. After some time (2 minutes on the Wii, depending on the bitrate), start loading another Sound object, snd2
  3. After a "buffer time" (depending on the connection, 10 second should be fine) fade the two Sound
  4. Free the fist sound snd1 = null
  5. Repeat from step 2

Remember that you have to pass a movieclip to the Sound object:

Actionscript:
  1. var snd1 = new Sound(_root.sndMc1);

And when you free the object you have to wait a frame for the garbage collector to free the memory:

Actionscript:
  1. snd1 = null;
  2. //next frame..
  3. snd1 = new Sound(_root.sndMc1);

Update: You can reload the same stream in another Sound object in this way:

Actionscript:
  1. snd2.loadSound("http://server:8000/;"+Math.random());

Without the ";"+Math.random() Flash will reuse the same connection

Here the source code of a proof-of-concept player:
Internet radio flash player

Listening to music on the Wii

Saturday, February 3rd, 2007

Update: Zach Callear has published a complete shoutcast player in flash without memory leaks. I haven't tested it yet but it should works in the wii browser.

Update: Now it's needed only a shoutcast server, I'm working on removing the web server too

Wii I own a Wii!
And I'm playing more with the opera browser+flash than with Zelda...
My first experiment is to stream music from the pc to the Wii.

So here a quick how to:

Note: I've encountered some problems because of a weird bug in the flash Sound object, witch I'll explain in the next post. Update: here the post.
There are still some imperceptible "glitches" every two minutes, but the overall quality is good.

Notice that the player hasn't any interface yet and its required to run three(!) servers. In the next days I'll try to improve those things.

Requirements

You need:

It is possible to swap every item in the list with a Mac/Linux alternative, I'll leave it to google.

The server(s)

Download and install the SHOUTcast server.

In sc_serv.ini change the password and make it private:

CODE:
  1. Password=changeme
  2. PublicServer=never

Now start the server.

This has to run on the same machine of the webserver due to the security restrictions of the flash player.
We need two servers because flash refuse to open another connection to the same server. (And we need to do that to avoid memory leaks)

Stream

Download and install the Shoutcast winamp plugin.

Start winamp.

Select Options->Preferences->DSP/Effect->Nullsoft SHOUTcast Source DSP
and put the new password and the server port (8000 by default)

Shoutcat plugin settings
Now the music you listen will be streamed to the shoutcast servers.

The player

Now, get the swf player:
Shoutcast stream flash player

It hasn't any interface yet, I'll do that in the next days.

Put the swf in your web server and pass your ip as a flashVar in wiinamp.html:

HTML:
  1. <param name="movie" value="stream.swf" />
  2. <param NAME=FlashVars VALUE="stream1=http://192.168.1.33:8000/" />
  3. <embed src="stream.swf" FlashVars="stream1=http://192.168.1.33:8000/" />
  4. </object>

8000 and 8002 are the ports of 8000 is the port of the stream servers.

Listen

In the Wii Internet Channel open http://*yourip*/wiinamp.html and relax :)

To Do

  • An interface for the player
  • try Icecast to get rid of the second server and the webserver (for now it made flash unstable)

Landcraft

Wednesday, December 27th, 2006

Landcraft landscape generator

This is a STUNNING landscape generator in Flash.
I've thought about doing something like this so many times, but I didn't know from where to start :) I wonder how many games can be made with it.

Visit: Landcraft - landscape generator in Flash

Flash constant frame rate

Friday, December 8th, 2006

A common problem in flash games, especially if there are some heavy graphics effects, is to handle the frame rate correctly. Even if it is possible to set a desired frame rate, the flash player will only try to keep it, but the actual frame rate may vary.
I've googled for some way to solve this problem, and I've found two different solutions.

One is to set the fps to somethings high, like 100fps, and then try to slow down the frame rate to the desired value with a busy-loop:

Actionscript:
  1. starttime = newDate()
  2. onEnterFrame=function(){
  3.    var currtime=new Date()
  4.    var ttime=currtime-starttime
  5.    while(ttime<1000/DESIREDFRAMERATE){
  6.       var currtime = new Date()
  7.       var ttime=currtime-starttime
  8.    }
  9.    starttime=new Date()
  10. }

In this way, however, some flash player's activities like garbage collection will be slowed down too, and this often lead to browser crashes. This is better explained in an interesting comment in a post on the Andrè Michelle blog by the user Troy Gilbert.

So the better way is to set the fps to something high, and then check when the interval 1000/frames_per_seconds is lapsed:

Actionscript:
  1. function onEnterFrame() {
  2.         var dtime:Number = getTimer() - this.lastFrameTime;
  3.         if(dtime> (1000/FRAMERATE)) {
  4.             var skipCount = 0;
  5.             while(dtime> (1000/FRAMERATE) && skipCount <MAX_FRAME_SKIP) {
  6.                 skipCount++;
  7.                 this.onEnterRealFrame();
  8.                 this.lastFrameTime += 1000/FRAMERATE;
  9.                 dtime = getTimer() - this.lastFrameTime;
  10.             }
  11.             this.lastFrameTime = getTimer();
  12.         }
  13.     }

onEnterRealFrame has the game logic, for example players movement and MAX_FRAME_SKIP prevent the player to hang too much.

We check if the time of a frame (1000/FRAMERATE) is lapsed, so we call onEnterRealFrame. We will call it how many times as the number of frames skipped from the last onEnterRealFrame call.
For example, if the fps is 10, and our game has a slow down for 300ms, it will call onEnterRealFrame for 3 times (300/(1000/10)) to recover the time lost.

However this solution has a problem: animated MovieClips will run out of sync. This can be solved either using tween engines like Zigo, or using a sound clip for synchronization.

Scroll browser window inside Flash

Tuesday, November 14th, 2006

Updated: fixed some typos

I've found that resizing a flash movie to fit his content has a little drawback: the mouse wheel doesn't scroll the browser window when the movie has focus, and in my case the movie has width: 100%.
Luckily I've found a nice javascript to scroll the page.

Add this javascript to the page:

JAVASCRIPT:
  1. function getScrollXY() {
  2.   var scrOfX = 0, scrOfY = 0;
  3.   if( typeof( window.pageYOffset ) == 'number' ) {
  4.     //Netscape compliant
  5.     scrOfY = window.pageYOffset;
  6.     scrOfX = window.pageXOffset;
  7.   } else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
  8.     //DOM compliant
  9.     scrOfY = document.body.scrollTop;
  10.     scrOfX = document.body.scrollLeft;
  11.   } else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
  12.     //IE6 standards compliant mode
  13.     scrOfY = document.documentElement.scrollTop;
  14.     scrOfX = document.documentElement.scrollLeft;
  15.   }
  16.   return [ scrOfX, scrOfY ];
  17. }

and in your movie:

Actionscript:
  1. var mouseListener:Object = new Object();
  2. mouseListener.onMouseWheel = function(delta:Number) {
  3.   getURL("javascript:window.scroll(getScrollXY()[0], getScrollXY()[1] + "+(0-delta*8)+");");
  4. };
  5. Mouse.addListener(mouseListener);

I multiply to 8 the delta to adjust the mouse sensitivity. Sadly there isn't a way to find the user's system sensitivity.
Maybe a better way can be to scroll directly to a specific point in the page:

Actionscript:
  1. mouseListener.onMouseWheel = function(delta:Number) {
  2.   if(delta> 0) {
  3.     getURL("javascript:window.scroll(getScrollXY()[0], "+this.bottom+");");
  4.   }
  5.   else {
  6.     getURL("javascript:window.scroll(getScrollXY()[0], "+this.top+");");
  7.   }
  8. };

Resize Flash at runtime

Saturday, November 11th, 2006

If your content is bigger than the average screen size, using a flash scrollbar for the entire document is really slow and not user-friendly, so its better to enlarge flash to fit the content and scroll the entire page with the browser's scroll bar.

Put the flash object in a div:

HTML:
  1. ...
  2. <SCRIPT LANGUAGE="JavaScript">
  3. <!--
  4. function newSize(width,height) {
  5.     if(document.all && !document.getElementById) {
  6.       document.all['myflash'].style.pixelWidth = width;
  7.       document.all['myflash'].style.pixelHeight = height;
  8.     }else{
  9.         document.getElementById('myflash').style.width = width;
  10.         document.getElementById('myflash').style.height = height;
  11.     }
  12. }
  13. //-->
  14. </script>
  15. </head>
  16. <div id="myflash" style="position:relative; width:100%; height:100%; z-index:1; min-width:1000px;">
  17.  ...
  18. </object>
  19. </div>

and in the movie do:

Actionscript:
  1. getURL("javascript:newSize('1000px', '100%')");

Other info here

Flash max connections

Saturday, November 11th, 2006

Recently I'm making a Flash photo gallery for my dad and I'm trying to optimize the loading of many pictures at once.
The question is: how many concurrent download can Flash make?
Google seems to have no answer, so I decided to make a small test to find it out by myself.

So I've made an swf that load 4 pictures simultaneously, and the result is in line with the HTTP specifications of max 2 connections per server.
More exactly, Flash use the browser configuration, in Firefox is Network.http.max-connections-per-server in about:config.
Can it be improved?
It is possible to use the old trick of loading images through multiples domain: for example static1.foo.com, static2.foo.com. This increase the maximum connection limit until network.http.max-connections

Default values in Firefox 1.5 are 8 for max-connections-per-server and 24 for max-connections.

You can try it by yourself:
Load from a single domain
Load from two domain

Sources:
Single domain
Two domain

Simple CakeAMFPhp How To

Wednesday, November 8th, 2006

It's been a while since I last wrote, sorry! I've been busy with work, thesis and some other suffs (which I'll be posting about in the next days).
One of those is AMFPhp: a method to connect Flash with Php.
Why AMF instead of JSON or XML? Basically because AMF is more mature than JSON, offer a ready-made and really complete set of classes, many utilities like the connection debugger component, a great Php implementation, and, above all, CakeAMFPhp. (AMF is also a binary protocol on top of HTTP, so performance should be better than XML)
CakeAMFPhp is the integration of AMFPhp and Cake, a Rails-inspired php framework. With Cake I've quickly build a prototype with the Bake command-line utility. Then I've started implementing the methods for the AMF calls. Thanks to the great database abstraction, every method is only few lines long.

Since CakeAMFPhp is a beta, I've found some problems, for which I've found a quick fix that I'll explain shortly.

To start a CakeAMFPhp project, simply download the required libraries as explained in this tutorial. (If you are new to Cake you should also see this)
Then in your controller, for example GalleriesController, put this:

PHP:
  1. vendor("cakeamfphp/amf-core/util/MethodTable");
  2. vendor('cakeamfphp/amf-core/adapters/lib/Arrayft');
  3. vendor('cakeamfphp/amf-core/adapters/lib/Arrayf');
  4.  
  5. class GalleriesController extends AppController
  6. {
  7. ...
  8. function GalleriesController()
  9. {
  10.   //AMF:
  11.   $this->methodTable = MethodTable::create(__FILE__);
  12.   parent::__construct();
  13. }

In the line 11 we call the automatic method table constructor of AMFPhp: it read the javadoc-like comments in the file and do all the magic:

PHP:
  1. /**
  2. * @desc Return the list of public galleries
  3. * @access remote
  4. * @pagesize 25
  5. */
  6. function getGalleries($offset = 0, $limit = 25) {
  7.   $data = $this->Gallery->findAll(null, null, 'created DESC', $limit, $offset, 0);
  8.   return $this->_arrayft($data, 'Gallery');
  9. }
  10.  
  11. function getGalleries_count() {
  12.   return $this->Gallery->findCount();
  13. }

The @access remote tag specify that the getGalleries method is callable from flash:

Actionscript:
  1. var ser = new Service("http://localhost/cake_gateway.php", null, 'GalleriesController', null , null);
  2. var pc:PendingCall = ser.getGalleries();
  3. pc.responder = new RelayResponder(this, "handleResult", "handleError");

The getGalleries_count() method is needed for the pageable recordset:

Actionscript:
  1. function handleResult (re:ResultEvent) {
  2.   var rs = RecordSet(re.result);
  3.   rs.addEventListener('modelChanged', this); //Listen for updateItems
  4.   this.totalItems = rs.getLength();
  5.  
  6.   for(var i:Number=startFrom; i <l; i++) {
  7.     item = rs.getItemAt(i);
  8.     if(i <rs.getNumberAvailable()) { //It is already fetched
  9.     ... //Process a row
  10.   }
  11. }

getGalleries return only the first 25 row from the database. When the data is loaded in flash, rs.getLength() method return the value from getGalleries_count(). getItemAt return an item or a future, we check if the item is loaded in the line 8. If the item isn't from the ones loaded, it is automatically requested from the server when we call getItemAt. When it arrives, the modelChanged method is called:

Actionscript:
  1. function modelChanged (info:Object) {
  2.   var rs = this.rs;
  3.   var item:Object;
  4.   if(info.eventName == "updateItems") {
  5.     for(var i:Number=info.firstItem; i <= info.lastItem; i++) {
  6.       item = rs.getItemAt(i);
  7.       target.addItem(item);
  8.     }
  9.   }
  10. }

in the info object there are the rows received, you can configure Flash to get only the item required or the page containing it.
That's all, simply add the @access remote tag, a *methodname*_count method and it works.
You can find more information on pageable recordsets here.

The _arrayft is required for the issue I've talk about before: CakeAMFPhp 0.6 does not support sending recorset to flash, so this method is required to transform the data returned by the Cake database abstraction layer into a AMF-compatible recordset:

PHP:
  1. function _arrayft($data, $table) {
  2.   $r = array();
  3.   if(!empty($data[$table])) {
  4.     //Multi table query:
  5.     if(is_array($data[$table][0])) {
  6.       //Nested table:
  7.       foreach($data[$table] as $t) {
  8.         $r[] = $t;
  9.       }
  10.     }
  11.     else {
  12.     //Sigle record:
  13.       foreach($data[$table] as $t) {
  14.         $r[] = $t;
  15.       }
  16.     }
  17.   }
  18.   else {
  19.     foreach($data as $t) {
  20.       array_push($r, $t[$table]);
  21.     }
  22.   }
  23.   return new Arrayf($r, array_keys($r[0])  );
  24. }

For performance reason, it is suggested to use a 0 'recursive' value in the find(..) call.