kelvinluck.com

a stroke of luck

Happy Christmas and Happy New Year!


This Christmas I am living in Canada whilst most of my friends and family are back in England or elsewhere. So I decided to make a virtual Christmas card that I could easily and quickly send anywhere. So here’s one for the reader(s?) of my blog:

You can click on the card to flip it over and read the message on the back but remember to flip back and see how the snow stacks up on the figures in the foreground… It’s not exactly realistic but I like it :)

I managed to put the whole thing together in about a day (which didn’t stop me being about a day late sending it out!) thanks to a bunch of open source projects. So massive thanks to the authors of and contributors to:
  • Papervision for the 3d (although thinking about it, I could have possibly tried to do something this simple using the new “postcards in space” 3d of the flash player 10).
  • Flint particle system for the snow (and I’m hoping to do more with this engine soon - it’s really nicely put together).
  • Pure MVC for holding it together.
  • Code Igniter for the backend (so I can send different cards to different people).
  • GTween for the tweening.
  • And also to Icon Drawer for the icons who are standing in the foreground of this card.
And now it’s time to go out and celebrate the approach of another year! I’m looking forward to lots of cool stuff for next year, both work and play. So Happy Christmas and Happy New Year everyone!! And all the best for 2009 :D

First steps with flash 10 audio programming


As I was reading my RSS feeds yesterday I came across a blog post by Andre Michelle where he released some sourcecode for using the new Sound APIs in Flash Player 10. I had a little spare time so I decided to finally set up FDT to allow me to author flash 10 swfs (which was easier than I expected) so I could do some playing.

The idea was to re-create my wave sequencer experiment using the APIs but to get started I did something simpler. I wrote a little class which allows you to load an MP3 file and play it back with the ability to change the playback speed dynamically. Here it is:

You can see the sourcecode for the relevant file below. The interesting stuff from an audio point of view is happening in the onSampleData callback. This is triggered by the Flash player whenever it needs a new buffer of audio samples to play. The code in that function is commented and hopefully pretty self explanatory. It is derived from code in my old wave sequencer experiment which was itself derived from some code in the popforge library.

package com.kelvinluck.audio
{
   import flash.events.Event;
   import flash.events.SampleDataEvent;
   import flash.media.Sound;
   import flash.net.URLRequest;
   import flash.utils.ByteArray;

   /**
    * @author Kelvin Luck
    */

   public class MP3Player
   {

      private var _playbackSpeed:Number = 1;

      public function set playbackSpeed(value:Number):void
      {
         _playbackSpeed = value;
      }

      private var _mp3:Sound;
      private var _loadedMP3Samples:ByteArray;
      private var _dynamicSound:Sound;

      private var _phase:Number;
      private var _numSamples:int;

      public function MP3Player()
      {
      }

      public function loadAndPlay(request:URLRequest):void
      {
         _mp3 = new Sound();
         _mp3.addEventListener(Event.COMPLETE, mp3Complete);
         _mp3.load(request);
      }

      public function playLoadedSound(s:Sound):void
      {
         var bytes:ByteArray = new ByteArray();
         s.extract(bytes, int(s.length * 44.1));
         play(bytes);
      }
     
      public function stop():void
      {
         if (_dynamicSound) {
            _dynamicSound.removeEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
            _dynamicSound = null;
         }
      }

      private function mp3Complete(event:Event):void
      {
         playLoadedSound(_mp3);
      }

      private function play(bytes:ByteArray):void
      {
         stop();
         _dynamicSound = new Sound();
         _dynamicSound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
         
         _loadedMP3Samples = bytes;
         _numSamples = bytes.length / 8;
         
         _phase = 0;
         _dynamicSound.play();
      }

      private function onSampleData( event:SampleDataEvent ):void
      {
         
         var l:Number;
         var r:Number;
         
         var outputLength:int = 0;
         while (outputLength < 2048) {
            // until we have filled up enough output buffer
           
            // move to the correct location in our loaded samples ByteArray
            _loadedMP3Samples.position = int(_phase) * 8; // 4 bytes per float and two channels so the actual position in the ByteArray is a factor of 8 bigger than the phase
           
            // read out the left and right channels at this position
            l = _loadedMP3Samples.readFloat();
            r = _loadedMP3Samples.readFloat();
           
            // write the samples to our output buffer
            event.data.writeFloat(l);
            event.data.writeFloat(r);
           
            outputLength++;
           
            // advance the phase by the speed...
            _phase += _playbackSpeed;
           
            // and deal with looping (including looping back past the beginning when playing in reverse)
            if (_phase < 0) {
               _phase += _numSamples;
            } else if (_phase >= _numSamples) {
               _phase -= _numSamples;
            }
         }
      }
   }
}

As you can see, there are three public methods in the above class. loadAndPlay will load an mp3 file into a sound object and start playing it at the desired playbackSpeed. stop will stop the currently playing mp3. And playLoadedSound will start playing an already loaded sound object at the desired playbackSpeed. This is useful if you have already preloaded your sound objects but it is also useful for another important reason as you can see in the demo.

Thanks to some great work from an old friend of mine, it is possible to dynamically create a Sound object based on an MP3 loaded through the new FileReference.load() functionality in Flash 10. This is why in the demo you can browse for an mp3 file on your local machine which can then be dynamically controlled by Flash immediately without sending it to a server first.

You can download the complete FDT project of my demo here if you want to look through all of the code. I’m excited by the possibilities that are opening up in flash now that Adobe made some noise - I’ve got a long way to go before I can do anything nearly as incredible as the Hobnox audio tool but I’ve got some ideas and I’m looking forward to playing around with them :)



Experiment with Papervision 3D particles and effects


A while back I was prototyping something for a client which involved lots of red dots moving around in 3D space, realised using Papervision 3D. I didn’t end up persuing this route with the client in the end but the effect was pretty cool so I thought I might as well share it here.

The idea is that there is a bunch of particles who are bouncing around randomly stuck within an invisible cube. The effect looked OK by itself but then I decided to try adding effects. I used a BlurFilter and a BitmapColorEffect to give the each of the particles trails. Then I changed the clipping point like in the original borg cube effects demo to give the impression of the particles falling. I like this version the best - if you move your mouse from side to side around the bottom of the demo swf then it starts to look like some kind of flocking is going on (like in my perlin noise experiment).

Click on the image below to see the demo. Click inside the demo swf to give it focus and then you can use the following keys:
  • 1 - Sets the render mode to normal clean particles (the default).
  • 2 - Sets the render mode to particles with trails.
  • 3 - Sets the render mode to falling particles with trails.
  • c - Toggles display of a cube showing the area the particles are contained within.

Particles and effects in Papervision 3D

The sourcecode for this example is pretty simple. You can see it below or you can download it from here.

package  
{
   import org.papervision3d.core.effects.BitmapColorEffect;
   import org.papervision3d.core.effects.BitmapLayerEffect;
   import org.papervision3d.core.geom.Particles;
   import org.papervision3d.materials.WireframeMaterial;
   import org.papervision3d.materials.utils.MaterialsList;
   import org.papervision3d.objects.DisplayObject3D;
   import org.papervision3d.objects.primitives.Cube;
   import org.papervision3d.view.AbstractView;
   import org.papervision3d.view.BasicView;
   import org.papervision3d.view.layer.BitmapEffectLayer;
   
   import flash.display.StageQuality;
   import flash.events.Event;
   import flash.events.KeyboardEvent;
   import flash.filters.BlurFilter;
   import flash.geom.Point;      

   /**
    * @author Kelvin Luck
    */

   [SWF(width='450', height='450', backgroundColor='#000000', frameRate='41')]

   public class ParticlesCube extends BasicView
   {
     
      public static const NUM_PARTICLES:int = 300;
      public static const CONTAINING_CUBE_SIZE:int = 500;
     
      public static const RENDER_MODE_CLEAN:int = 0;
      public static const RENDER_MODE_TRAILS:int = 1;
      public static const RENDER_MODE_FALLING:int = 2;
     
      private var particlesContainer:DisplayObject3D;
      private var particlesHolder:Particles;
      private var particles:Array;
      private var boundsCube:Cube;

      private var bfx:BitmapEffectLayer;
     
      private var _renderMode:int;
      public function set renderMode(value:int):void
      {
         if (value == _renderMode) return;
         
         clearBitmapEffects();
         
         var clippingPoint:Point = new Point();
         
         switch (value) {
            case RENDER_MODE_CLEAN:
               // nothing - effects already cleared above...
               break;
            case RENDER_MODE_FALLING:
               clippingPoint.y = -2;
               // fall through...
            case RENDER_MODE_TRAILS:
               bfx = new BitmapEffectLayer(viewport, stage.stageWidth, stage.stageHeight, true, 0xffffff);
               
               bfx.addEffect(new BitmapLayerEffect(new BlurFilter(2, 2, 2)));
               bfx.addEffect(new BitmapColorEffect(1, 1, 1, .9));
               
               bfx.clippingPoint = clippingPoint;
               
               bfx.addDisplayObject3D(particlesHolder);
               
               viewport.containerSprite.addLayer(bfx);
               break;
            default:
               throw new Error(value + ' is an invalid render mode');
         }
         _renderMode = value;
      }
     
      private var _displayCube:Boolean = true;
      public function set displayCube(value:Boolean):void
      {
         if (value != _displayCube) {
            _displayCube = value;
            boundsCube.visible = value;
         }
      }

      public function ParticlesCube()
      {
         super(550, 550);
         
         stage.quality = StageQuality.MEDIUM;
         
         particlesContainer = new DisplayObject3D();
         scene.addChild(particlesContainer);
         
         var cubeMaterial:WireframeMaterial = new WireframeMaterial(0x0000ff, 1, 2);
         var materialsList:MaterialsList = new MaterialsList();
         materialsList.addMaterial(cubeMaterial, 'all');
         
         boundsCube = new Cube(materialsList, CONTAINING_CUBE_SIZE, CONTAINING_CUBE_SIZE, CONTAINING_CUBE_SIZE);
         particlesContainer.addChild(boundsCube);
         displayCube = false;
         
         particlesHolder = new Particles();
         particlesContainer.addChild(particlesHolder);
         
         init(NUM_PARTICLES, CONTAINING_CUBE_SIZE);
         
         stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
         
         startRendering();
      }

      public function init(numParticles:int, containingCubeSize:int):void
      {
         var movingParticle:MovingParticle;
         
         if (particles) {
            particlesHolder.removeAllParticles();
         }
         
         particles = [];
         
         var i:int = numParticles;
         while (i--) {
            movingParticle = new MovingParticle(containingCubeSize);
            particlesHolder.addParticle(movingParticle);
            particles.push(movingParticle);
         }
         
      }

      override protected function onRenderTick(event:Event = null):void
      {
         // move each particle
         var movingParticle:MovingParticle;
         for each (movingParticle in particles) {
            movingParticle.position();
         }
         
         // twist the container based on mouse position
         particlesContainer.rotationY+=((stage.stageWidth/2)-mouseX)/200;
         particlesContainer.rotationX+=((stage.stageHeight/2)-mouseY)/200;
         
         // render
         super.onRenderTick(event);
      }
     
      private function clearBitmapEffects():void
      {
         if (bfx) {
            viewport.containerSprite.removeLayer(bfx);
            bfx = null;
         }
      }
     
      private function onKeyDown(event:KeyboardEvent):void
      {
         switch (String.fromCharCode(event.keyCode)) {
            case '1':
               renderMode = RENDER_MODE_CLEAN;
               break;
            case '2':
               renderMode = RENDER_MODE_TRAILS;
               break;
            case '3':
               renderMode = RENDER_MODE_FALLING;
               break;
            case 'c':
            case 'C':
               displayCube = !_displayCube;
               break;
         }
      }
   }
}

import org.papervision3d.core.geom.renderables.Particle;
import org.papervision3d.materials.special.ParticleMaterial;

internal class MovingParticle extends Particle
{
   
   public static const PARTICLE_SIZE:int = 10;
   public static const MAX_SPEED:int = 5;
   
   private var dX:Number;
   private var dY:Number;
   private var dZ:Number;
   private var halfSize:Number;

   public function MovingParticle(containingCubeSize:int)
   {
      var mat:ParticleMaterial = new ParticleMaterial(0xff0000, 1, ParticleMaterial.SHAPE_CIRCLE);
      super(mat, PARTICLE_SIZE);
     
      var size:int = containingCubeSize;
      halfSize = size / 2;
     
      x = (Math.random() * size) - halfSize;
      y = (Math.random() * size) - halfSize;
      z = (Math.random() * size) - halfSize;
     
      dX = Math.random() * MAX_SPEED;
      dY = Math.random() * MAX_SPEED;
      dZ = Math.random() * MAX_SPEED;
     
   }
   
   public function position():void
   {
      x += dX;
      if (x > halfSize || x < -halfSize) dX *= -1;
      y += dY;
      if (y > halfSize || y < -halfSize) dY *= -1;
      z += dZ;
      if (z > halfSize || z < -halfSize) dZ *= -1;
   }
}
// This line is just to stop the code formatter on my blog getting confused! >


New multiplayer papervision game


I’ve just released my entry into the Nonoba Multiplayer API Kick Off competition. It’s a multiplayer take on the old memory cards game where you have to turn over pairs of cards and try to remember what was under each one. The multiplayer aspect makes it much more frantic and fun as other players are looking at the same cards at the same time as you and you don’t want them to steal your pairs!

It will probably make more sense if you try it out yourself so go ahead and click the image below to play multiplayer memory mayhem!
My good friend Leigh Kayley did the designs (including illustrating all of the cool animals) and I built the game using Papervision, PureMVC, GTween and the Nonoba multiplayer API.

While I was building the game I did a little prototype for the score board transitions using papervision which you can see by clicking the image below. Click anywhere in the movie to give a random player some random points (and so maybe rearrange the scores) and press any keyboard key to toggle some mouse following behaviour.

Papervision 3D score panels test

Unfortunately in the game you can’t really see the 3d transitions on the scores so I thought I’d upload this for people to look at. And I’ve also uploaded the source code for anyone who is interested. It’s probably not the best because it was a prototype stuck together quickly but it may be useful to someone…

Update:

I’m pleased to say that Multiplayer Memory Mayhem won third prize in the multiplayer kickoff competion on Nonoba… Yay!


Wave Sequencer experiment


A couple of weeks ago I attended the FitC Amsterdam conference which was great fun. One of the most inspiring sessions I saw was Andre Michelle’s “Making REAL Music Within Flash” where he talked us through generating sound in flash using the infamous flash sound hack and then showed us how he is redefining what should be possible in flash by building the hobnox audio tool.

I travelled to Amsterdam by train and ferry which meant that I had some spare time on the way back to play and luckily Andre and Joa Ebert have released the complex code behind the flash sound hack as part of their popforge open source library.

So I built my Wave Sequencer. The idea is that it loads in a wav file and splits it into 16 equally sized chunks. You can then re-arrange these chunks to create new variations on the beat. Each 16 chunk section is a pattern and you can create up to 16 different patterns by choosing different patterns from the “pattern bank” at the bottom of the screen.

The loop I’m using is the famous Amen break and I’ve sped it up a bit (and given you a slider so you can control the speed yourself). If you play around with it you’ll see you can slice and dice your own old skool jungle riddims :)

Screenshot of Wave Sequencer Experiment

Note: If you are experiencing choppy audio then you are probably running the latest revision of the flash player (9.0.115.0) which breaks onSoundComplete. So join the petition and ask Adobe to make some noise. I’ve compiled a standalone version of the app against the older 9.0.28.0 player and you can download the PC standalone version which doesn’t have the audio issues.

Obviously this little experiment is very rough around the edges and there is a lot that can be done to improve it but I’ve been too busy with “real work” to look at it in the weeks since I got back from FitC and I thought it was better to publish it as is than to leave it to get lost on my hard drive…

My code here is really simple, all of the complex stuff is done by the popforge library. So big thanks to Andre for the inspiration and the sourcecode :) Hopefully I’ll find some time in the coming months to take this a lot further and to turn it into an AIR app which is actually useful!



Flash on the Beach and some Perlin Noise


Last week I went to the Flash on the Beach conference and as has been said by many people, it was amazing.

I decided to go for more of the inspirational rather than technical sessions and saw some absolutely amazing speakers including (in order of appearance): Hoss Gifford, Joshua Davis, Brendan Dawes, Craig Swann, Mario Klingemann, Robert Hodgin, Erik Natzke, Chris Allen, Dr Woohoo, Andre Michelle, Marcos Weskamp and Jared Tarbell. Wow!

And as well as all these amazing talks there was the opportunity to meet loads of friends - old and new - and to chat about geeky stuff. And then there was all of the booze and the parties… And a girl in a box!

Anyway, one particular example from Robert got me thinking and wanting to play… He mentioned the PerlinNoise function and talked about how it could be used to simulate flocking. And he showed a slide where a perlin noise image had been used to set the rotation of a set of arrows displayed on top of it. I wanted to play with this and had a little bit of time over the weekend so I managed to come up with this:

My perlin creatures

It’s really simple stuff - you can get the sourcecode and see the process that it evolved through here. The code isn’t beautiful or optimised as I was trying to concentrate on playing rather than doing it right (a concept which seemed to be a recurring theme of the conference).

And I wasn’t the only one who got interested by Robert’s mention of perlin noise. Seb Lee-Delisle posted on Sunday about 3D Perlin Noise in Flash - it looks like a really interesting way to take this further. I can’t wait to see what he comes up with and hopefully to find some more time to play with it myself :)



Actionscript 3: part 3!


Update 2:

This is a very old page imported from my previous blog. If there is missing content below or anything that doesn’t make sense then please check the page on my old blog.

Update:

These examples were created with the very first beta of actionscript 3 and run on the very first beta of the flash player 8.5. Unfortunately they don’t work on any release version of the player because of changes Macromedia/ Adobe made.

The evolution of my ActionScript 3 project has continued. Here is the current swf (remember you will need the Flash Player 8.5 to view it):


As you can see, it’s a whole heap more exciting now… It still creates the mosaic tiles from the original jpeg in the same way as the previous examples but now each tile also listens for an EventType.ENTER_FRAME event. This is basically the same as having a MovieClip.onEnterFrame event handler in older versions of Flash. Each tile is repulsed by the mouse using Barslund Repulsion (thanks to a script I grabbed from Solid Ether).

Here is the code for the example in it’s entirety:

Fairly simple really… And if anything it seems way more efficient and responsive than my attempt at bounce tweening in the last example…

Comments or suggestions for improvements appreciated :)



Second steps with ActionScript 3


Update 3:

This is a very old page imported from my previous blog. If there is missing content below or anything that doesn’t make sense then please check the page on my old blog.

Update 2:

These examples were created with the very first beta of actionscript 3 and run on the very first beta of the flash player 8.5. Unfortunately they don’t work on any release version of the player because of changes Macromedia/ Adobe made.

Update:

Check out part 3 of this series on my experiences with ActionScript 3.

I have taken my first attempt at ActionScript 3 and refined it a little… The first attempt was a very simple mosaic tool which created a mosaic from a jpeg. In this version I have improved it in a number of ways:

I now first blur each section of the image to get more of an average colour for each tile. This was a good excuse to use one of the flash.filters.* in AS and also gives a slightly better looking result. It still isn’t perfect but I spent quite a while searching the web and couldn’t find any good algorithms to find the average colour of a given bitmap (I’m sure they exist though - if you know one please leave some info in the comments).

I also decided to make the example a little bit more exciting by adding some movement to it. I initally did this by using the mx.effects classes but then I realised that these were adding 210KB to my file (unless I missed a “SimpleTween” class somewhere?). I presume that is because they depend on the whole Flex Framework but in this case (where my swf does pretty much what I want at 2KB) it seemed like some unnecessary overhead.

So I wrote a very simple little Tween class based on the new flash.util.Timer class and borrowed one of Robert Penner’s easing equations

So here is the resulting swf (note that you will need the flash player 8.5 to view it and that the movement happens when the swf loads so you may have to refresh the page to see it move):

And here is the ActionScript to make that swf:

If you compare it to my previous effort you will see that it is pretty similar… The additions are the BlurFilter and the new Tween class… They should be clear enough… The Tween class is very quickly knocked together and isn’t meant to be a proper generic replacement for the Macromedia ones but I think that such a beast may be necessary if the Macromedia ones are going to create such big files… Hopefully the next version of the zigo tween kit from Moses Supposes will include support for AS3…

Anyway - any comments on the code or suggestions for improvement appreciated :)



First actionscript 3 example


Update 3:

This is a very old page imported from my previous blog. If there is missing content below or anything that doesn’t make sense then please check the page on my old blog.

Update 2:

These examples were created with the very first beta of actionscript 3 and run on the very first beta of the flash player 8.5. Unfortunately they don’t work on any release version of the player because of changes Macromedia/ Adobe made.

Update:

Check out part 2 and part 3 of this series on my experiences with ActionScript 3.

Macromedia have just released the Flex 2 Product Line which includes the Flash Player 8.5 and ActionScript 3. It’s only an alpha but it’s a good chance to start playing around with the next generation of the Flash Platform.

Below is my first little experiment. It’s currently very simple and doesn’t do anything that you couldn’t do with Flash 8 but I think coming up with simple little projects like this and making them is a good way to learn the new syntax.

First up, here is the swf (note that you will need the flash player 8.5 to view it):

And here is the code that generated the swf:

As you can see, we load a jpeg in and then loop over it getting the colour every TILE_SIZE pixels. We then create a new Sprite which we draw a bunch of Shape’s (in this case squares) onto. The result is a mosaic like effect (I remember doing this in the early days of Flash 5 - a much more complicated process involving using PHP to analyse the image data).

Obviously a lot of room for improvement (getting the average pixel colour for a tile, having the image be dynamic rather than programmed into the AS etc etc) but not bad for the first couple of hours with a new language.

Any questions or suggestions for better ways I could have done things please use the comments :)