Intro to AS3 Workers (Part 3): NAPE Physics + Starling!

[UPDATE]: Adobe has removed support for ByteArray.shareable until Player 11.5. The source code has been updated to work around that restriction, but have left the example code intact since it will eventually work fine.

In part 1 of this series we looked at the basic message protocol for AS3 Workers, and a simple hello world.

In part 2, we looked at an example of performing imageProcessing in a seperate thread.

In this final installment, I’ll show how you can run your Physics entirely on a seperate thread, and we’ll also throw in a little Starling to the mix as some icing on the cake :)

First lets take a look at what we’re going to make.



Multi-Threaded Example

As a comparison, lets take a look at the single-threaded legacy implementation:


Single-Threaded Example

On most computers the single threaded test will struggle to reach >45fps. With the CPU completely maxed out. Even if you do manage to hit 60fps because you have a super fast CPU, you;re still totally maxed out, you would have no more room at all to do anything else in your game. Contrast that to the Worker implementation, where the main thread is doing virtually nothing on the CPU. It spends <1ms on de-serializing the data, and a couple more pushing a bunch of vertex's to Starling. It has so much free time it's taking a smoke break!

Overview

First a quick overview of how this will work:

  • The Nape simulation will live entirely inside a Worker thread
  • The Main Thread will make calls on the Worker Thread when it wants to add a new Physics Body
  • Each frame, the Worker Thread will copy the position data of all bodies into a shared ByteArray
  • The Main Thread will read the position data from the ByteArray, and use it to update the on-screen Sprites

We’ll start by looking at the document class, and the messages that it sends to the Worker. Then we’ll look at the Worker which contains the actual physics code.

Document Class

The first step is to setup our worker and some message channels so we can talk.

At this point you should be familiar with this boiler-plate code for a Worker-based application:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public function NapeWorkerExample()
{
registerClassAlias("SpritePosition", SpritePosition);
registerClassAlias("Rectangle", Rectangle);
 
if(Worker.current.isPrimordial){
 
	stage.frameRate = 60;
 
        //Create worker 
	worker = WorkerDomain.current.createWorker(loaderInfo.bytes);
 
	//Create shared message channels
	channelToMain = worker.createMessageChannel(Worker.current);
	channelToMain.addEventListener(flash.events.Event.CHANNEL_MESSAGE, onMessageFromWorker);
 
	channelToWorker  = Worker.current.createMessageChannel(worker);
 
	worker.setSharedProperty("channelToMain", channelToMain);
	worker.setSharedProperty("channelToWorker", channelToWorker);
 
	//Create shareable byteArray
	positionBytes = new ByteArray();
	positionBytes.shareable = true;
	worker.setSharedProperty("positionBytes", positionBytes);
 
	//Start worker
	worker.start();
 
	//Wait for Starling to start...
	_starling = new Starling(starling.display.Sprite, this.stage);
	_starling.addEventListener("rootCreated", function(){
 
		StarlingRoot = Starling.current.root as starling.display.Sprite;
 
		//Create UI for stats
		initUi();
 
		//Build physics world
		buildWalls();
		buildPyramid();
 
		//Add listeners
		stage.addEventListener(flash.events.Event.ENTER_FRAME, onEnterFrame);
		stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
		stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
 
	});
	_starling.start();
} 
else {
	stage.frameRate = 60;
	napeWorker = new NapeWorker();
}
}

The first portion of the document class is your standard worker setup, create the worker, create the message channels etc. We create some basic UI for monitoring stats, and also initialize Starling.

Also notice the calls to registerClassAlias() those are extremely important when we want to pass any non-native data-types. So remember, you NEED to call registerClassAlias() on both ends of the equation (worker and main), and include the class for any objects that you’ll be sending. If you don’t call this, the data will get received as generic Objects.

TIP: Notice how the worker and main thread can have different frameRates. Cool!

Once Starling has finished setting up, we build our physics scene using the buildWalls() and buildPyramid() functions’s. Let’s look at those now.

In buildWalls() we ask the worker thread to add some STATIC_BODIES and pass it an array of shapes. These will form the walls and floor or our scene.

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
protected function buildWalls():void {
	var thickness:int = 50;
	var width:int = stage.stageWidth;
	var height:int = stage.stageHeight;
 
        //Create vector of rectangles for the walls
	var shapes:Vector.<Rectangle> = new <Rectangle>[
		new Rectangle(0, 0, -thickness, height), //Left
		new Rectangle(width, 0, thickness, height), //Right
		new Rectangle(0, height - thickness, width, thickness) //Bottom
	];
 
	//Ask worker to add these to the physics simulation
	channelToWorker.send(MessageType.ADD_STATIC_BODY);
	channelToWorker.send(shapes);
}
...

You’ll notice I have declared a simple MessageType Class which defines the various message types I’ll be using:

0
1
2
3
4
5
6
7
8
package
{
public class MessageType
{
	...
        public static var ADD_BOX:String = "addBox";
	public static var ADD_STATIC_BODY:String = "addStaticBody";
}
}

In buildPyramid() we ask the worker thread to create about 800 dynamic bodies and add them to the world. We also create a graphical representation of that object and add it as a Starling Image:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//Builds a pyramid by callig addBox() a bunch of times...
protected function buildPyramid():void{
	var boxw:Number = 25;
	var boxh:Number = 15;
	var height:int = 40;
 
	for(var y:int = 1; y<height+1; y++) {
		for(var x:int = 0; x<y; x++) {
			var pos:SpritePosition = new SpritePosition();
			pos.x = stage.stageWidth/2 - boxw*(y-1)/2 + x*boxw;
			pos.y = stage.stageHeight - boxh/2 - boxh*(height-y)*0.98;
			pos.width = boxw;
			pos.height = boxh;
			addBox(pos);
		}
	}    
}
 
protected function addBox(data:SpritePosition):void {
	//Create sprite and add to starling root
	var graphicSprite:Crate = new Crate(data.width, data.height);
	StarlingRoot.addChildAt(graphicSprite as starling.display.DisplayObject, 0);
 
        //Store graphic in a hash by it's id
	data.id = graphicSprite.id;
	spritesById[data.id] = graphicSprite
 
        //Ask worker to create an object with this id, position and size
	channelToWorker.send(MessageType.ADD_BOX);
	channelToWorker.send(data);
}
//

The last portion of the main thread we’ll look at right now is the code to trigger drag and drop. To do this we need a couple simple things:

  • Inject the mouseX and mouseY of the main stage into the Worker. This is the only way the worker can know where the mouse is!
  • Ask the worker to START_DRAG and STOP_DRAG

To do this, we set up an ENTER_FRAME handler, and also MOUSE_UP and MOUSE_DOWN event handlers:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//
protected function onEnterFrame(event:flash.events.Event):void {
	//Pass mouseX and mouseY into worker so it can "grab" anything under the mouse
	worker.setSharedProperty("mouseX", mouseX);
	worker.setSharedProperty("mouseY", mouseY);
}
 
protected function onMouseDown(event:MouseEvent):void {
	channelToWorker.send(MessageType.START_DRAG);
}
 
protected function onMouseUp(event:MouseEvent):void {
	channelToWorker.send(MessageType.STOP_DRAG);
}
//

The last thing to do in this class, is to actually read the positions of the physics objects from our ByteArray, and apply the values back the Starling Images. Before we do that though, we need to take a look at the Nape Worker itself.

NapeWorker.as

In the constructor for the worker itself, we’re going to do a few things:

  • Get reference to shared bytes, and message channel’s
  • Initialize our Nape ‘Space’
  • Initialize a ‘hand’ object to be used for dragging
  • Add a listener so we can respond to messages from the Main Thread
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//
public function NapeWorker(){
	//Init Nape
	space = new Space(new Vec2(0, 600));
 
	//Create hand
	hand = new PivotJoint(space.world,space.world,new Vec2(), new Vec2());
	hand.active = false;
	hand.space = space;
	hand.stiff = false;
	hand.frequency = 4;
	hand.maxForce = 60000;
 
	prevTime = getTimer();
	addEventListener(Event.ENTER_FRAME, onEnterFrame);
 
	//Init Worker
	this.worker = Worker.current;
 
	registerClassAlias("SpritePosition", SpritePosition);
	registerClassAlias("Rectangle", Rectangle);
 
	positionBytes = worker.getSharedProperty("positionBytes");
 
	channelToMain = worker.getSharedProperty("channelToMain");
	channelToWorker = worker.getSharedProperty("channelToWorker");
	channelToWorker.addEventListener(Event.CHANNEL_MESSAGE, onMessageFromMain);
}
//

Again, notice that we had to make registerClassAlias() calls to support our custom classes (and even native ones like Rectangle!).

Next is to implement an event handler to respond to messages from the Main Thread:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/* Handle the various commands from the main thread */
protected function onMessageFromMain(event:Event):void {
	var msg:String = channelToWorker.receive();
 
	switch(msg){
 
		case MessageType.ADD_BOX:
			var position:SpritePosition = channelToWorker.receive(true);
			addBox(position.id, position.x, position.y, position.width, position.height);
			break;
 
		case MessageType.ADD_STATIC_BODY:
			var shapes:Vector.<Rectangle> = channelToWorker.receive();
			addStaticBody(shapes);
			break;
 
		case MessageType.START_DRAG:
			drag(true);
			break;
 
		case MessageType.STOP_DRAG:
			drag(false)
			break;
 
	}
}
 
public function drag(value:Boolean):void {
	if(value){
		var p:Vec2 = new Vec2(hand.anchor1.x, hand.anchor1.y);
		var bodies:BodyList = space.bodiesUnderPoint(p);
		if(bodies.length > 0){
			var b:Body = bodies.shift();
			hand.body2 = b;
			hand.anchor2 = b.worldToLocal(p);
			hand.active = true;
		}
	} else {
		hand.active = false;
	}
}

You can see that the handler is really just an event router, it gets a message, and based on the type, it call’s some internal function(s).

You can see the handlers for the drag related events, which are pretty self explanatory. You can also see the addBox() and addStaticBody() method we called previously.

First lets look at the addStaticBody() method, which involves a few simple Nape API’s:

0
1
2
3
4
5
6
7
8
9
10
/**
 * Add a static object (wall floor etc, can consist of multiple shapes
 **/
protected function addStaticBody(shapes:Vector.<Rectangle>):void {
	var border:Body = new Body(BodyType.STATIC);
	for(var i:int = 0; i < shapes.length; i++){
		var rect:Rectangle = shapes[i];
		border.shapes.add(new Polygon(Polygon.rect(rect.x, rect.y, rect.width, rect.height)));
	}
	border.space = space;
}

Next, the addBox() method, this one is slightly more complicated (comments inline):

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * Add a new 'box' object
 **/
protected function addBox(id:String, x:int, y:int, w:int, h:int):void {
        //Create the new dynamic body and add to Nape space
	var block:Polygon = new Polygon(Polygon.box(w, h));
	var box:Body = new Body(BodyType.DYNAMIC);
	box.shapes.add(block);
	box.position.setxy(x, y);
	box.space = space;
 
        //Inject a dummySprite into this body so we can easily track it's position
	var dummySprite:NapeSprite = new NapeSprite(id);
	sprites.push(dummySprite);
	box.graphic = dummySprite;
}

Next up is the real make-it-or-break-it part of this application. We’re going to serialize all the position data, and send it back to the Main Thread. And this needs to be fast. If it takes us 8ms to de-serialize 1000 objects, we’ve already blown half our rendering budget in the main thread!

We already know that a shareable ByteArray is the quickest way to share memory. But how best to use it?

The easiest and most elegant way is to simply call byteArray.writeObject(myArrayOfObjects). Unfortunately, this is slow. With this method, I can serialize 5000 items at about 6ms.

The fast way to do this is to manually pack your data into ByteArray. Rather than write in each object, we write in the Number and String values directly into the byteArray. With this method, I can do 5000 items in < 1ms!

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * Copy positions of NapeSprites into byteArray.
 **/
protected function onEnterFrame(event:Event):void {
	//Step the physics simulation using the elapsed time from last frame
        var et:int = Math.min(50, getTimer() - prevTime);
	prevTime = getTimer();
	space.step(et * .001, 10, 10);
 
	var ba:ByteArray = positionBytes;
	ba.position = 0;
	for(var i:int = 0, l:int = sprites.length; i < l; i++){
		ba.writeInt(sprites[i].id.length);
		ba.writeUTFBytes(sprites[i].id);
		ba.writeInt(sprites[i].x);
		ba.writeInt(sprites[i].y);
		ba.writeInt(sprites[i].rotation);
	}
 
        //Notify main thread of completion
	channelToMain.send(MessageType.PHYSICS_COMPLETE);
 
	//Update hand position for drag operations
	hand.anchor1.setxy(worker.getSharedProperty("mouseX"), worker.getSharedProperty("mouseY"));
 
}

Simple right!? We just pack all our values back to back in a ByteArray, and as long as we read them in the same order everything should work! Ya, its a little fragile, but fast as shit!

TIP: When storing a string value, we must first store the length of that string, so we can pass the length to byteArray.readUTFBytes() on the other side.

You can see that in action if we pop over to the Main Thread. In the message handler in the Main Thread, we’ll listen for the PHYSICS_COMPLETE message, and run basically an inversion of the function above:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected function onMessageFromWorker(event:flash.events.Event):void {
	var msg:String = channelToMain.receive();
 
	if(msg == MessageType.PHYSICS_COMPLETE){
 
		//Read byteArray getting the updated positions
		var s:Crate;
		var ba:ByteArray = positionBytes;
		positionBytes.position = 0;
		var id:String;
 
		while(positionBytes.bytesAvailable){
			//Read sprite data from byteArray into position object
			id = ba.readUTFBytes(ba.readInt());
 
			//Update the actual on-screen sprite
			s = spritesById[id];
			s.x = ba.readInt();
			s.y = ba.readInt();
			s.rotation = ba.readInt() * Math.PI / 180;
		}
	} 
 
}

That’s about it! You now have a complete physics system running wholly in another thread, running on top of Stage3D!

Of course this is just a demo, and there are tons of cool things you could add to make this more functional, like:

  • Ability to add more shapes / body types
  • Ability to remove / split items
  • Ability to add joints
  • etc…

Source Code

Download the source code for the project here:

Note: You will see some additional code which handles logging and error’s, and many try/catch blocks. In FlashBuilder 4.6 you can not Trace or view Runtime Errors from the worker thread, so it becomes necessary to try/catch everything, and send() the stackTrace back to the main thread so it can trace it out.

In FB 4.7 this should all be resolved and you will be able to debug like normal.

I’m really interested in any feedback you guys have on this article. It was a long one for me, and I wasn’t quite sure how to split everything up, did it work!?

Written by

30 Comments to “Intro to AS3 Workers (Part 3): NAPE Physics + Starling!”

  1. pete says:

    FYI, im getting the following error:
    (I’m running flash player 11.4.400.231 debug)
    Error: Error #3738: MessageChannel is closed.
    at flash.system::MessageChannel/send()
    at NapeWorkerExample/addBox()
    at NapeWorkerExample/buildPyramid()
    at MethodInfo-1()
    at starling.events::EventDispatcher/invoke()
    at starling.events::EventDispatcher/dispatchEvent()
    at starling.events::EventDispatcher/dispatchEventWith()
    at starling.core::Starling/initialize()
    at starling.core::Starling/onContextCreated()

    • Trey says:

      Hello Pete,

      I believe you’re be running 11.4 beta 1. Try downloading 11.4 beta 2. I too got that error, but once I snatched beta 2, the first example worked.

      • shawn says:

        Ya there’s is some general sketchiness going on in Chrome right now. Closing other browser tabs seem to help, Firefox seems rock solid.

        That error basically means that the Worker has crashed, but I can’t reproduce with the standalone player at all.

      • pete says:

        yep, installing 11.4 beta 2 fixed Error #3738
        However interestingly now all the demos online (not just isolated to your demo) seem to crash the flash player the first time they load, then work when the page is reloaded.. I guess this is why its in beta.
        but aside from that your demo runs at a cool 60fps, don’t think I’ve ever seen physics in flash run that smoothly :D

  2. stuit says:

    Awesome thing, really like it and definitely want to try it in my next games.
    Thanks for this tut.

  3. Vico says:

    on MBP : 24fps/60fps
    great démo of Workers

    • shawn says:

      Strange, I wonder if you’re running in Software rendering mode… Starling should be able to render 1000 items on a MBP! What are you seeing for the serialization costs??

  4. Hyzhak says:

    Create similar demo for box2d, but it’s significantly more slower

    http://hyzhak.github.com/bin/box2d.onworkers/0.0.1/

  5. Demo’s not functioning in IE with the very latest 11.4 beta :(

  6. Matt Bolt says:

    Is there a reason why you’re sending the message type first, then the position data? Why not just 1 object? ie: channelToWorker.send({ type: “addBox”, position: data });

    Using receive(true) seems unnecessary – probably should avoid blocking (explicitly) if at all possible.

    There may not be a difference either way, but I was curious as to any specifics as to why you wrote it this way.

    Thanks!

    • shawn says:

      The reason to do this is to create a more flexible message scheme, there may be some events that have no data, some that have lots of data, so by declaring it this way you make it more flexible.

      I suppose you could just always pass a generic {msg: msg, data: data}, and then cast the data on the other side, and would server moust use cases.

      For the receive(true), it seems to avoid the odd crash… thats the only reason it’s there, and the crashes may have just been Beta bugs.

  7. Alex says:

    On Intel i5 @ 2.4GHz both demos feel slow. Yes the first demo shows 60FPS, but that’s because there is little going on in the main SWF. In other words FPS counter doesn’t show average performance for both SWF files.

    Second SWF (worker) still doing all the number crunching for physics computation, hence it feels as slow as the second demo. I bet if I could benchmark worker SWF file I’d still get 12-13 FPS (that’s what I’m getting while running second demo).

    • shawn says:

      Basically the demo’s are tuned for my machine to something I thought would work for most. Obviously, if you run this on a slow PC it will not be able to process 1000 items at 60fps.

      But this is a stress test, you wouldn’t need 1000 physics objects in most games.

      To see the frameRate of the BG thread just look at the time elapsed for physics. If it’s taking 50ms to process physics, then that 20fps in the Worker Thread.

  8. [...] Workers can provide a huge performance boost. Take a look on this example using Nape & Starling. It’s definitely something I want to add in a future version. At the moment, Workers are not [...]

  9. Wilson Silva says:

    The demo does not work well on IE9 or FF on my machine. Have a look at this issue https://bugbase.adobe.com/index.cfm?event=bug&id=3309937

    Liping Zhao makes a comment about the way you’re initializing Starling, that may fix the problem.

    • Sean Monahan says:

      I’m unable to get the Workers version to run properly on Mac OS (10.7.4). I’ve tried Chrome, Safari and Firefox. I can see the stats counter in the top left corner and the info ticker along the bottom but I don’t see the boxes that are present in the legacy version.

  10. [...] AS3多线程快速入门(三):NAPE物理引擎+Starling 添加评论[作者:Dom Chen 分类:3D, ActionScript, Flash ] 原文链接:http://esdot.ca/site/2012/intro-to-as3-workers-part-3-nape-physics-starling [...]

    • shawn says:

      I think they are referring more to Starling and Away3D than me… no one approached me to write these, I just wanted to dive into them.

      And no worries at all, my blog is pretty new, so any discussion is good discussion :)

      RE: AIR, you should be able to just download my attached project, create a new AIR project with the same name, and point to the existing project dir, it’ll just take the document class and make it an AIR app.

      I actually always work in AIR, I don’t use Flash plugin anymore, period. The only reason I didn’t for this was simply so I could post the demo’s online.

  11. shawn says:

    All demo’s should be fixed and working in FP 11.4 Release Player :)

    • Terry Corbet says:

      First, I’d like to know when you were notified or otherwise became aware of the fact that Shared Byte Arrays were removed?

      Second, I’d like to know what your performance measurements showed for the degradation due to having to write the data back and forth across the Message Channels rather than through the shared bytearray object.

      Third, I’d like to know if you have tested the differences between the implementation as found in the released Flash Player 11.4 and the released AIR 3.4?

      Thanks for your demonstration/tutorials.

      • shawn says:

        Hi Terry.

        1. I was notified of the change via the Prerelease version, however it’s common knowledge now, anyone who tried the API’s will realize they’re a no-op.
        2. I don’t see any significant different between shared and non shared in my demo’s
        3. Haven’t tested AIR yet

        I’m definitely interested in the answers to 2 and 3, but really really don’t have time. Feel like writing some benchmarks!?

        • Terry Corbet says:

          There is very definitely a problem — our problem, probably, not yours. By “our” I mean anyone trying to work with Adobe’s beta programs, but not being admitted to the inner circle. We download and test beta code, we submit bug reports, we post to the beta forum, but we get no response. There was absolutely no notification that they were going to drop the shareable ByteArray. During that whole seven weeks the Beta LiveDocs were never updated with the correct facts concerning the new classes, methods or properties to support Concurrency.

          01. There had been a report of the degradation in ByteArray when shared across the virtual players. If they sub-class ShareableByteArray from ByteArray so that its normal use will not be disturbed, that will make better sense than thinking that no one will notice the memory locking overhead.

          02. There had been a report that the use of the File class in a background thread raised a Security Error not raised when we do all that File work in the foreground thread of our AIR apps. No response, its just hanging out there as an unknown restriction on what a Worker can do. Again, maybe in the communications they provide you, someone has addressed the concerns, but nothing for us ordinary folks.

          03. I just came back from watching Lee Brimlow’s webinar to see what he was going to say about the fact that his demo of Workers was broken by the last-minute retraction of the shareable attribute on ByteArray. He just waffled it saying, that now you could pass the data back and forth like any other object for which their is Serialization support.

          What is really, really terrible is that right now with released11.4 and released 3.4 there are two different implementations. It is still possible to run Lee’s Flash demo, but you cannot run the same implementation via AIR. Meanwhile Thibault goes running around the globe saying how great the new worker features are, and there are no published reports on the cost of establishing the plumbing and tearing it back down as part of the overhead of setting up a background task. If I just trivially watch Task Manager, I can easily see that the total system resource consumption is higher, as expected. What is needed is open, professional publication of the facts concerning the implementation so developers can make informed decisions about when to employ the features and when not to. That aspect of product management is completely absent. Maybe gamers don’t care, but businesses do.

          • shawn says:

            Ya, I agree that the docs and communications to developers are poorly organized and delivered in general. But in their defence this cropped up at the last minute right before release, so I think they scrambled a bit here, this is unusual…

            Also, they did call it out in the official release notes:
            Note: Shared memory support (ByteArray.shareable) has been moved to a forthcoming release of Flash Player.
            http://helpx.adobe.com/flash-player/release-note/fp_114_air_34_release_notes.html

          • Hi Terry,

            I am sorry to hear that you feel frustrated by these things.

            First, for the beta forums, it is not normal that you did not get answers to your questions. Can you point to questions you asked which were left unanswered, I would like to follow up on that. For the docs, I agree, we need to fix this.

            For the notification, Shawn is correct. We basically had a last minute meeting a few days before the release to remove this feature. It really got us by surprise and it took you guys too. I sent a heads up on the Prerelease before the release to inform developers and included it in the release notes. We should have sent a heads up on the Adobe forums too and on Twitter to propagate the info, agreed.

            I posted some details about the implementation of Workers here: http://www.bytearray.org/?p=4423

            But I am sure you refer to an official ADC article about Workers, which is something we are planning to do, I guess we should have posted it on the day of the release or maybe even before.

            Workers is a cool feature and we have worked hard on it to make it happen. I hope it will still be useful to you!

            Again, sorry for the issues you encountered and made the feature harder to leverage. You can reach me on my email timbert (at) adobe dot com if you want to chat more about this. I will be happy to include you on the Flash Player and AIR prerelease too so that you also get access to builds early on too.

            Thibault

  12. Terry Corbet says:

    Well, since Adobe does not directly respond to requests for information, and since the Docs pages now refer to you for examples, may I ask for some help.

    A. Is there or is there not a listWorkers method in the WorkerDomain class as seen by whatever globalplayer.swc file you are using? The airglobal.swc file created on August 15 does not believe that there is such a method, no matter what the Docs may say.

    B. Can you update your demos to show the proper method for shutting down a background worker, including the proper clearing of any MessageChannels, and any other shared resources, so that you are sure that GC will recover all the memory in the remaining, Primordial, code path.

    C. I appreciate the fact that you have not tried to use these facilities for an AIR application, but that would certainly be an appreciated service since there is not a single example of the use of these facilities in the environment in which they have the most potential — multi-windowed, mission-critical, long-running desktop applications.

    Thank you.

    • Terry Corbet says:

      During his dog-n-pony show, yesterday, Lee spoke on behalf of Thibault by describing the win-win that Adobe now has in its embrace of third-party projects. Having you guys write an extensive, thoughtful demo/tutorial of a Worker implementation must certainly be part of what Lee and Thibault mean. That said, I apologize for abusing your space to communicate helpful information back to Adobe. There being no easier way to reply to Thibault’s comments, above, I have posted back to his original example of how to convert wav to mp3 on his personal blog site and written a basic test suite for the Adobe QC team to use that I have attached to the bug [3317078] submitted to them.

  13. Vlad says:

    It doesn’t work in Chrome FP11.5

  14. Sammy Joe says:

    I can’t seem to get it to work in Chrome, FP 11.5 as well. I wonder if they just haven’t added byteArray.sharable back into the player yet?

    This is super cool for desktop stuff.
    am I right that this isn’t applicable to mobile?

  15. Rich Lovejoy says:

    Hi great demo!

    Being only vaguely aware of how this is working under the hood, I have a few questions…

    - Why does using a worker thread for physics improve performance at all? Is the worker somehow being offloaded to the gpu? Why is the swf not simply splitting CPU cycles between the Main and Nape threads?

    - Has anyone tested this on mobile? Does AIR for iOS support workers?

    Thanks!

Leave a Reply to Rich Lovejoy

Message