blog Frank Pepermans
Flash experiments outlet-
Flex Organization Chart Component
Posted on February 11th, 2010 7 commentsIt’s been one hell of a long time since my last update.
Ever since I’ve been working as a freelancer, time to spend experimenting with Flash has been very few.Nevertheless, I’d like to showcase this custom built Flex component :
This movie requires Flash Player 10As you may notice by the choice of image, it was developed for Telenet, as a way to represent their organizational structure.
The component is fed by a zipped XML file, containing up to 3000 profiles.Code has been optimized to display loads of profiles at once, and keeping performance on par.
The component also boasts drag and drop features and is fully skinnable.Top-right you’ll notice a small menu, use it to go either fullscreen, or to start looking for a specific person. Do keep in mind that all data has been replaced with dummy data, normally you can look for firstname, lastname and department in the input field.
Last but not least, the data generating this chart, is retrieved from Org Publisher. I’ve witten a Java parser to convert the OCB filetype to a ZIP which this Flash loads. So you could view this component as a glorified Org Publisher frontend.
The component has already been reused in a different project, where the profile data is replaced by Flex charts, displaying just how well a certain employee has performed over the past year. You’ll understand I can’t just put that online
More updates coming soon, there’s much in the pipeline, just need to find some time!
-
Astar pathfinder with Pixel Bender and Alchemy
Posted on April 6th, 2009 1 commentSome time ago I wrote a simple pathfinder astar implementation in AS3. It was just a simple grid, with walkable and non-walkable nodes which the alorythm used to define the optimal path.The biggest limitation was that everything is always grid-based. You would simple flag certain nodes in the grid as walkable and not walkable and then calculate the best path.
Why Pixel Bender for a path finder?
My initial goal was to have the astar pathfinder run on a pure black and white bitmap data object. This way a designer could simply place complex objects on a map and a developer could easily transform the map to a black and white collision map.
The next step of course would be to have Flash analyse this bitmap and create a grid for pathfinding accordingly.
Using getPixel in a loop would be very slow, especially in very large bitmaps, so Pixel Bender was obviously used here.
A cool bonus is that Pixel Bender also runs asynchronously in a seperate thread from Flash.How does Pixel Bender create the grid?
The Pixel Bender kernel script takes 2 parameters, one being the black and white bitmap obviously, the other being a node distance value. This node distance is the effective distance between 2 individual nodes in the grid. For example: a bitmap of 600 pixels width would output 30 columns in the node distance is 20 pixels.As you probably know, Pixel Bender loops over each individual pixel.
For each pixel, the node to the top-left of that pixel is found. Then the script will test if the current pixel happens to be in a straight line between 2 adjacent nodes.
If it is, another test will determine if you can walk from node A to B, this is not the case should the pixel be black.For each pixel, a result is kept. The output of the Pixel Bender kernel script is image3, so that gives 3 values for each pixel to use.
The first value is a binary value, this binary value is a collection of bit flags for the pixel, namely : is walkable or is not walkable, if the pixel is on the straight line to the node on the right/bottom-right/bottom/top-right.
The other 2 values are used to store the col and row of the top-left node.For quick updating I also divided the black and white bitmap into areas, each area is 200×200 pixels large and is processed by its own ShaderJob. This way, when the black and white map is updated, I can process these updates by area instead of having to re-process the image as a whole each time.
Now for Alchemy…
Thanks to Ralph Hauwert’s excellent post on how to optimize the use of Alchemy and Pixel Bender, I decided to try the same with this experiment.
Flash will write the Pixel Bender result straight into Alchemy memory, where it is then processed in C to a usable grid.
The actual astar algorythm was also ported to C since the algorythm potentially runs a very large loop when using low node distance values or large black and white collision maps.As a result
The path finder does run faster than in pure AS3, but not by a great amount. You can test it here.
The initial choice is to set the node distance property. The lower the value, the more nodes Pixel Bender will generate and thus the more data Alchemy has to crunch to display the astar path result.Please note that…
the initial choice can really result in a slow pathfinder if you select ‘intensive’ for example. In most practical implementations the less-intensive settings are more than enough.Credit to mr. Doob for the excellent Stats class
c code used in Alchemy
Around 90% of this app was built in C for use in Alchemy, below is the source.
It’s a bit cryptic sometimes, mostly due to some efforts in trying to optimize code execution with Alchemy.
Flash is only used to paint the maze and display the result from Alchemy & PB. -
XMas in summer
Posted on June 12th, 2010 No commentsHow do you render a 3D Christmas tree in Flash?
Papervision is an option, but don’t expect the 3D tree model to look realistic…
This project has a mini, custom-built 3D tree renderer.
It rotates particles around a 3D cone shape, replace those particles with random Bitmap objects of branches, rotate and colorize them randomly, and you get a decent 3D tree feeling.This build uses 1600 particles, some are dynamic, an they represent pictures which people can upload, sphered within xmas balls.
Click the image to view the 3D tree.
note that the webservice which loads the uploaded xmas balls is currently unavailable, so only the non-decorated tree is shown. -
Music@work
Posted on May 6th, 2010 No commentsJust for fun, and for something else than coding
My first ever attempt at a DJ set
Abfahrt Hinwil - Tech 8
Nicolas Masseyeff ft. jr. C - No more time (Gabriel Ananda mix)
Dirty Vegas - Pressure (Sultan & Ned Shepard remix)
Way Out West - Only Love
Kollektiv Turmstrasse - Freiflug
Elegant Universe feat. Adir Ohayon - Modern Time (Trafik remix)
Hybrid - City Siren (reprise)
BT - Never gonna come back down (Hybrid’s Breaktek remix)
Oko - Can’t You See
DJ Shadow - Broken Levee Blues (transition rap sample)
Ryan Davis - Clouds Passing By (Eelke Kleijn remix)
Jon Hopkins - Autumn Hill -
Eagerly awaiting mobile AIR 2.0/Flash 10.1
Posted on May 3rd, 2010 1 commentIt seems like an eternity, waiting for the official release.
Especially with all the commotion recently give Apple’s infamous section 331, and the following hatred towards the Flash platform.I could write a lengthly paper on my thoughts on the matter as a whole, yet those opinions can already be found all over the net in both the Flash and Apple camps.
As I haven’t personally had the honour of toying around with, say the Android beta of AIR 2.0, let alone mobile Flash 10.1, I’m just going to await the official release and see if Adobe will manage to silence the negativism surrounding their platform.Meanwhile, I’ve prepped up this demo on a rainy day. Very suitably, it is a simulation of running water in a maze. It’s an idea I have for a potential Flash game, but again, only time will tell if it will even manage to run well on a mobile device.
Benchmarking on my laptop so far, has given very different results.
In AIR 2.0 beta it runs very well, same with the standalone Flash 10 and Flash 10.1 players, but once loaded in a browser, it becomes painfully slow.The engine was written in C# with Alchemy, basically the only AS3 code that is used, is to update the main Bitmap object on each frame.
The engine will add water particles every frame, until the count reaches 50000 water particles.Feel free to have a go by following this link, benchmark posts are more than welcome!
-
Fun with flash.utils.Proxy and events
Posted on September 24th, 2009 No commentsUPDATE
Following the below post, some more experimenting gave a much cleaner result, as shown here :-
var manager:EventManager = EventManager.getInstance(mySprite);
-
// add some event listeners
-
with (manager.assign(myOnMouseEventHandler)) {
-
click++;
-
mouseOver++;
-
mouseOut++; // add listener
-
mouseOut- -; // remove listener
-
}
-
// delete a listener automatically after it has triggered once
-
with (manager.assign(myOnLoadHandler, true)) {
-
complete++;
-
}
-
// use a predefined function to just trace some events
-
with (manager.assign(EventManager.CAPTURE_TRACE)) {
-
complete++;
-
}
Using ++ or - - will add or remove the specified listener for an object.
See the original post below on what’s going on.
new source.ORIGINAL POST
Lately, many people have been complaining about the cumbersome usage of the AS3 events model, we can only dream of a simple implementation in the lines of ‘myObject.listeners += dispatcher’ instead of ‘myObject.addEventListener(eventType, dispatcher, false, 0, true)’.Now there’s really not much of an alternative in AS3, one thing that remotely comes to mind is the flash.utils.Proxy class.
A quick glance at the help page shows promise, you can override accessor function such as getProperty and setProperty. Looking at the typing of the function arguments would suggest that you can pass any data type to these functions, as name, value and return are all noted with an asterix sign.
However, in reality the name argument can be of only two types, String or QName.That’s a bummer because that means you can not get the same functionality which the Dictionary class providers, namely to use a variable of any type as name argument.
Imagine this line of code :
-
EventManager.target(mySprite)[[MouseEvent.CLICK, onClick]]++;
-
// add callback
-
EventManager.target(mySprite)[[MouseEvent.CLICK, onClick]]- -;
-
// remove callback
EventManager is a factory class, it checks if mySprite was previously added as target, if it was the EventManager instance for mySprite which already exists is returned, if it’s a first timer, a fresh new EventManager() with mySprite as locally stored ‘target’ is returned.
Since EventManager extends Proxy, the syntax [[MouseEvent.CLICK, onClick]] would send the Array [MouseEvent.CLICK, onClick] as name:* argument to the setProperty method.
Unfortunately, since name:* is automatically converted to String or QName, the Array gets passed as Array.toString(), tracing to something like “click,function Function() {}”.
Okay for click, but the function reference is completely lost now…Should this have worked without the String cast, I would be able to capture the ++ and - - instructions to actually add or remove listeners.
The setProperty would check if name:* is an Array, and if so store that Array somewhere, then have the setProperty function return a reference to the EventManager instance itself (return this);++ would be captured then, again by the setProperty method, and would be detectable since the value:* attribute would be 1, or -1 for - -.
Upon reaching to this code, I could address the locally stored event Array from above and call addEventListener or removeEventListener based on the 1 or -1 value.Being stubborn and all, I did want something useful to emerge out of this experiment. The big trouble is sending the event handler function to the EventManager.
I did end up with the following structure, first imagine the next few code lines :-
mySprite.addEventListener(MouseEvent.CLICK, onMouseEventA, false, EventPriority.BINDING, true);
-
mySprite.addEventListener(MouseEvent.MOUSE_OVER, onMouseEventA, false, EventPriority.BINDING, true);
-
mySprite.addEventListener(MouseEvent.MOUSE_OUT, onMouseEventA, false, EventPriority.BINDING, true);
-
mySprite.addEventListener(MouseEvent.CLICK, onMouseEventB, false, EventPriority.BINDING, true);
-
mySprite.addEventListener(MouseEvent.MOUSE_OVER, onMouseEventB, false, EventPriority.BINDING, true);
-
mySprite.addEventListener(MouseEvent.MOUSE_OUT, onMouseEventB, false, EventPriority.BINDING, true);
-
mySprite.addEventListener(Event.ENTER_FRAME, onEvent, false, 0, true);
-
mySprite.addEventListener(ToolTipEvent.TOOL_TIP_SHOW, onEvent, false, 0, true);
-
mySprite.addEventListener(ToolTipEvent.TOOL_TIP_HIDE, onEvent, false, 0, true);
That’s a long list of code, just to add a number of events to some EventDispatcher.
Now thanks to some fiddling with the return values of the setProperty method, the following line of code (seperated by line breaks and tabs for the sake of readability) does the exact same thing :-
EventManager.target(mySprite)
-
[MouseEvent.CLICK][MouseEvent.MOUSE_OVER][MouseEvent.MOUSE_OUT][true]
-
(onMouseEventA, EventPriority.BINDING)
-
[MouseEvent.CLICK][MouseEvent.MOUSE_OVER][MouseEvent.MOUSE_OUT][true]
-
(onMouseEventB, EventPriority.BINDING)
-
[Event.ENTER_FRAME][true]
-
(onEvent)
-
[ToolTipEvent.TOOL_TIP_SHOW][ToolTipEvent.TOOL_TIP_HIDE][true]
-
(onEvent);
Notice how you can keep chaining parameters.
The [true] parameter acts as a breakpoint, it tells the setProperty method to apply all event types to the event handler function as noted in the next segment ie (onMouseEventA, EventPriority.BINDING).
When all is applied, it returns yet again a reference to itself (return this), so that future event chaining may proceed.In the same fashion you can remove listeners :
-
EventManager.target(mySprite)
-
[MouseEvent.CLICK][MouseEvent.MOUSE_OVER][MouseEvent.MOUSE_OUT][false]
-
(onMouseEventA);
-
// removes specific event type and event handler combo.
-
EventManager.target(mySprite)
-
[MouseEvent.CLICK][MouseEvent.MOUSE_OVER][MouseEvent.MOUSE_OUT][false]
-
();
-
// removes ALL event handlers which handle mouseOver and mouseOut
-
EventManager.target(mySprite)[false]()
-
// remove any active event handler for any event type
Is all this worth the trouble? Probably not, but I did have some fun messing with the flash.utils.Proxy class and deviating from its traditional use
Below is a small example of the whole thing in action :
The black box listens to some mouse events (out, over, click)This movie requires Flash Player 10Should you be interested, the source can be found here.
-
-
Papervision with collision detection
Posted on April 8th, 2009 12 commentsThis movie requires Flash Player 10
This is my version of Papervision collision detection. The project actually started out as a 2D isometric engine, in the end I decided to map the 2D grid to a 3D environment.
The collision detection is also handled by the isometric engine, left-click on the upper-left framerate box to show or hide the 2D grid.Use the numpad arrows or W-S-A-D to move around and click-drag the mouse to look around.
It might take some time to load all the textures, so be patient, I didn’t implement a loader!The source can be downloaded here.
As mentioned above, this is NOT a full fledged fps engine. My initial idea was to have a pseudo 2D-3D world, where the camera would be positioned above the player (as in Diablo II for example).
This means that collision detection is only applied on an XY-axis and not the expected XYZ-axis. (eg a player can jump through a ceiling, but cannot traverse a solid wall).The world is actually tile-based with performance in mind. Every keypress that moves the player will calculate if the player is allowed to move in a certain direction, if the test fails, a mini path findinding script will return the best non-colliding position closest to the requested position.
The final version would ideally combine papervision 3D objects with static 2D objects and feature a diablo-like top down camera position. Unfortunately, I almost never finish projects I start in my spare time :-/
I do still plan to create a very basic world editor to render a demo which is a lil’ more interesting to explore.Below is an excerpt of the main setup script :
-
// The container used to render the 3D in
-
_appContainer = appContainer;
-
// The isometric display layer
-
_canvas2D = new UIComponent();
-
// The papervision display layer
-
_canvas3D = new Basic3DSetup(500, 400);
-
_canvas3D.addEventListener(Event.INIT, onEngine3DInit);
-
// Create a new world grid, the grid is infinite in size,
-
// the 2 constructor parameters define the width and height of a single grid tile
-
// the smaller the size, the better the collision detection, yet the slower the algorithm
-
_grid = new world.grid.Grid();
-
_grid.create(10, 10);
-
// Initialize the player pawn(s) container
-
_pawnList = new Vector.<Pawn>;
-
// Load and parse a compatible XML file to a papervision 3D world
-
_f3dParser = new F3DParser(_grid.tileWidth, _grid.tileHeight);
-
_f3dParser.addEventListener(F3DParserEvent.PARSER_COMPLETE, onParserComplete);
-
_f3dParser.loadAndParse("http://www.frankula.com/lab/swf/museum.xml");
-
// Initialize the player
-
// passing PawnType.TERRAIN_BLOCK tells the engine that this pawn is solid and
-
// thus collides with other solid objects.
-
_playerPawn = new Pawn(PawnType.TERRAIN_BLOCK);
-
_playerPawn.playerControlled = true;
-
// Set the display object on which to render on (2D)
-
_playerPawn.canvas = _canvas2D;
-
_playerPawn.grid = _grid;
-
// Define the collision area of this Pawn, in this case
-
// the player is represented as a 50×50 px circle on the grid.
-
// the actual player model may be smaller or larger, the cirlce is only
-
// used for collision detection
-
_playerPawn.shapeClass = Circle;
-
_playerPawn.setSize(50, 50);
-
_playerPawn.updateShape();
-
_grid.updateTilesForPawn(_playerPawn);
-
_playerPawn.draw();
-
_pawnList.push(_playerPawn);
-
_canvas2D.visible = false;
-
_canvas2D.x = 300;
-
_canvas2D.y = 100;
-
_canvas2D.scaleX = _canvas2D.scaleY = .5;
-
_fpsTicker = new UITextField();
-
_fpsTicker.background = true;
-
_fpsTicker.backgroundColor = 0xffffff;
-
_fpsTicker.autoSize = TextFieldAutoSize.LEFT;
-
_fpsTicker.text = "LOADING…";
-
_canvas3D.mouseEnabled = false;
-
_canvas2D.mouseEnabled = false;
-
//_fpsTicker.mouseEnabled = _fpsTicker.mouseWheelEnabled = false;
-
_appContainer.addChild(_canvas3D);
-
_appContainer.addChild(_canvas2D);
-
_appContainer.addChild(_fpsTicker);
-
_framesRendered = 0;
-
_fpsTimer = new Timer(1000);
-
_fpsTimer.addEventListener(TimerEvent.TIMER, showFPS);
-
_fpsTimer.start();
-
_fpsTicker.addEventListener(MouseEvent.CLICK, onToggle2D);
-
-
The Sims 1 graphics in Flash : IFF to AS3 Sprites
Posted on April 6th, 2009 No commentsAn old one I’ve had lying around ever since AS3 was released.
The IFF format was used for the Sims 1 way back, this parser can read almost any sims IFF file and convert it to Flash Sprites. (demo loads Sofas.iff, be patient for the file to download and then parsed).See also the ever excellent wikipedia entry on Interchange File Format.
Source here, but unfinished, and as mentioned above, very VERY old! But maybe still useful for someone… (used it to learn AS3 coming from AS2 back then)





