If we knew you were comin', we'd've baked a cake

Tag: Actionscript/AS3 Page 6 of 7

Flash AS3: A quick test of Five3D

Five3D is a compact Actionscript library that allows you to create 3D views quickly and easily. Much like Papervision3D, Away3D or Sandy, it allows you to create basic 3D graphics with Actionscript. Why would you use Five3D instead of one of these other libraries? Here’s a quick rundown of the advantages and shortcomings of Five3D  that I have found:

  • Five3D has a stripped-down feature set. If you need to do something simple like move a large number of planes in 3D space, Five3D will be easier to set up than the other 3D packages. The drawback is that it doesn’t do many of the things that the other engines do, like providing built-in primitives or Collada imports.
  • Five3D handles vector objects without first turning them into bitmaps. You can actually use Flash’s native drawing API to create vector shapes and move them in 3D while still retaining the vectors. This creates smoother renders than the other 3D engines, especially when scaling and rotating objects. The other 3D engines create bitmaps of textures and then map them onto the surfaces of objects.
  • Five3D handles 3D text really well. You can convert fonts into vectors and then use them as 3D objects. This makes 3D text effects really simple.
  • The default handling of bitmap textures is cleaner than Papervision. With Five3D, bitmap textures on planes map much more smoothly than with Papervision’s defaults. You can map textures just as well in Papervision, but it’s a little bit of a hassle to set up.
  • The Five3D library is written to extend the native flash classes in a way that is really intuitive. For example, a MovieClip3D is just like a MovieClip, but it has additional features like a z-coordinate. Half the time, you can guess what properties each object will have without even looking them up in the docs.
  • Five3D doesn’t use a camera object. Depending on your needs, this could be an advantage or a disadvantage. You can handle this by simply creating a Sprite3D container to hold all of your objects. Then, move the container to simulate camera movement. I often do this in Papervision projects anyway because of various issues I have had with the camera.

I have built a simple “Hello World” test of Five3D, which you can see below. It’s not very exciting, but it isn’t supposed to be. When I started playing with Five3D, I had a hard time finding a simple, stripped-down example that could get me started, so that is what I’ve built here. You can download the source files here. I have also added links to some more advanced tutorials and samples at the bottom of this post.

I did run into some weird Five3D quirks when I built this. First, when I created a MovieClip3D object and added it to the scene, it wasn't appearing on stage. I traced all of the properties and everything indicated that it was on the stage, but it was not displaying. I Googled around a bit and found this website with the answer: you have to call the activate() function for MovieClip3D objects to get them to render on the stage. I don't understand why you need to do this, but it fixed my problem.

The other quirk that you need to know about is that you have to turn on z-sorting. By default, it z-sorts according to your addChild() calls, just like regular MovieClips. If you don't need z-sorting, just add the 3D items in the correct sequence. I'm guessing that this helps to optimize the code. If you need your objects to spin in 3D space, you can turn on z-sorting with the childrenSorted property (check out the example source code for usage).

Thanks to Mathieu Badimon for this amazing Actionscript package.

Links:

Download the source files for the example above

A 3D text sample with source code

A simple example of Five3D with source code

A fun Five3D experiment

A tutorial on building a 3D photo album with Five3D

Info on integrating Five3D with Jiglib physics

Essential AS3 classes: getURL and PixelPerfectCollision Detection

As I have made the transition to AS3 class-based programming, I have built a package of useful classes that handle functionality I need all the time. For example, I have a class that handles the basic rollover functionality for a button. Rather than write this code over and over, I made a class that takes care of it. That’s the main benefit of working in classes – things become more modular and you (theoretically) spend less time building repetitive code. I am always looking for good code to add to my core package of classes and the following two classes definitely fit the bill. I use them all the time and I thought I’d help more people locate them:

getURL:
One of the biggest hassles in AS3 is writing 10 lines of code to accomplish the same thing that you can do with one line in AS2. The getURL() function was killed in AS3. Now you need to set up a URLRequest… it’s a hassle. Well, Actionscript guru Senocular has created a getURL() class that mimics the behavior of the AS2 function. simply add the class to your import statements and then use it just like you did in AS2. Grab it here.

Pixel Perfect Collision:
One of the more annoying problems with Flash is that collision-detection has never lived up to its promise. In AS2, the hitTest() function only allowed you to check if the bounding boxes of 2 objects were touching. This worked great if all of your graphics were rectangular, but it often registered a collision between objects that, visually, looked like they were still pretty far apart. Grant Skinner was the first person to solve this problem with his AS2 collision-detection code. His original code was then ported to as3 by Boulevart. I had been using that code for projects, but it had a few shortcomings – it didn’t work for rotated or scaled objects and both objects had to share the same parent. I was just recently contemplating an update to the AS3 Collision class to fix some of these issues when I found an updated version by Troy Gilbert. It not only handles rotated and scaled objects, but he has optimized the code and removed the constructor (which was really unnecessary anyway). You will definitely want to get his PixelPerfectCollision class.

That’s all for now. If you’ve found any other classes that you use all the time, leave a comment and let me know.

Flash AS3: Why can’t I extend my AS3 class?

As I have made the move from AS2 to AS3, I have run into several situations where Flash refused to let me extend an AS3 class. I have spent many hours pounding my head on the desk, screaming “Why doesn’t this work?!” Well, that may be an exaggeration, but I have definitely spent many hours on this issue.

The problem is related to using direct references to MovieClip instance names in an AS3 class. If you associate an AS3 class with a MovieClip using the linkage property of the MovieClip …AND… you have direct references to any of the MovieClip’s children instance names, you can NOT extend the class. I have created a packet of examples (click here to download the packet) to help demonstrate what I’m talking about:

Example 1 (marked basic_linkage_example in the packet): This is simply an example of the base scenario. The buttons on the stage are each instances of the MovieClip bounceButton, which has a base class linkage of BounceButtonTweenLite. This class handles the rollover functionality of the button (with the help of the amazing TweenLite library) and also provides some other basic functionality, like the ability to enable and disable a button. If you open up this class file, notice that only the child Movieclip with the instance name graphic_mc actually bounces. There is another child MovieClip that provides a hit area larger than the graphic to prevent any rollover “flickering” when the button bounces. This is a great example of needing to target a child MovieClip and doing it directly with the child clip’s instance name.

Example 2 (marked linkage_extension_example in the packet): This shows what happens when I try to extend the BounceButtonTweenLite class with a class called NavButton. notice that the NavButton class does not override any of the base class functionality – it simply adds an init() function and establishes a MouseEvent.CLICK listener. If you try to publish this file, you will see that it throws a couple of compiler errors and it doesn’t work. Again, this is because the BounceButtonTweenLite class contains a direct reference to graphic_mc, which is the instance name of one of its child MovieClips. I can’t extand this class as long as I am using the linkage property to associate the NavButton class with my bounceButton MovieClip.

Example 3 (marked composition_example in the packet): This shows how you can make it work by using a composition method of associating classes with MovieClips. When using composition, the linkage property of the MovieClip isn’t used. Instead, you send references to the MovieClip (and any needed children) into the class. Since the references are no longer tied to timeline instance names, you can extend it without any problems. In this example, I instantiated new instances of the NavButton class and sent references to each MovieClip and it’s child graphic. The code that handles this composition method of associating the MovieClips and their classes is on the main timeline. If this were a real project, I would place the code in another class, but I wanted to keep this simple.

Variations on this same issue keep popping up in my projects. I recently had a project which had several different bounceButton-style MovieClips that each contained different graphics. They all shared the same BounceButtonTweenLite base class. That was no problem. The problem came when I wrapped each of those in another set of MovieClips, each with a base class called SelectorButton. The SelectorButton class had a reference to the inner button’s instance name. It didn’t work. Why? Well, I had 8 DIFFERENT inner button MovieClips that shared a base class. So when the wrapper class tried to reference it, the flash compiler freaked out. It was basically saying: “Hey! You told me that these MovieClips were all the same, but they aren’t!” Even though they had the same basic structure, the MovieClips weren’t EXACTLY the same, so the compiler didn’t like it. Again, a composition method fixed the problem.

Using a MovieClip’s linkage is a great way to associate classes with MovieClips – it’s fast and easy. Frankly, I do it all the time and I’m not likely to quit anytime soon. Unfortunately, as you get better at class-based programming, you will find that the linkage property creates problems like these and that a composition-based structure is a lot cleaner. From an object-oriented programming perspective, composition also helps to separate actionscript code from graphics, making the entire project a whole lot more modular. Big Spaceship uses composition so that their projects can be passed from Flash to Flex and vice versa. They talk about it here (in fact, this post is where I got the idea to use composition to fix my problems with class extension).

I hope that this explanation makes some sense and saves you a little time. As usual, you can download the sample files here.

Flash AS3 PrintJob: Problems printing from Flash

Flash has a feature called PrintJob that allows you to print MovieClips – either by creating PDFs or simply sending them directly to a printer. Unfortunately, PrintJob has a poorly documented bug that can cause a lot of headaches. Sometimes, it will print blank pages. Other times, it will scale the pages incorrectly. The behavior is seemingly random and it is different on different computers. I had a lot of trouble printing from Flash with a recent project at work, but there is a remarkably simple solution. Read on…

In my project, I allowed a user to save PDFs to a print queue for printing at a later time. This was done by simply pushing the MovieClips onto an array. When a user hit the print button, I created a PrintJob and then looped through the array of MovieClips, scaling each one as needed to fill the page and then sending them to the printer. The actionscript code looked like this:

//-prints all saved pdfs:
public function printAllPages():void {
	if (savedPdfsArray.length > 0) { //if there are pdfs to print...
		var pj:PrintJob = new PrintJob(); //create printjob
		if(pj.start()) {
			for (var i:int=0; i < savedPdfsArray.length; i++) {            
				//scale it to fill the page (portrait orientation):
				var myScale:Number;
				myScale = Math.min(pj.pageWidth/savedPdfsArray[i].width, pj.pageHeight/savedPdfsArray[i].height);
				savedPdfsArray[i].scaleX = savedPdfsArray[i].scaleY = myScale;
				var printArea:Rectangle = new Rectangle(0, 0, pj.pageWidth/myScale, pj.pageHeight/myScale);

				pj.addPage(savedPdfsArray[i], printArea); //add page to print job
			}
			pj.send(); //send to printer
		}
		pj = null;
	}
	else { //if there are no pdfs in the queue...
		errorPopup.openMe("You do not have any pdfs saved in your queue.");
	}
}

This code worked perfectly on my PC, but occasionally gave me problems on an old iMac in the office. I had someone else test it on a newer Mac and it seemed fine, so I wrote it off as an outdated printer driver.

Then, when we sent it to the client, there were all sorts of problems. On some computers, it printed blank pages. On others, it scaled the pages incorrectly, so that the MovieClips didn't fill the page. It happened on both Macs and PCs. After a lot of Googling around without much success, I found this thread on Kirupa forum. One of the responders suggested that the MovieClips must be added to the stage or they won't print. I gave this a try and IT WORKED! It fixed all of the weird, unpredictable PrintJob behavior in my application. I quickly updated my code and the client was happy:

//-prints all saved pdfs:
public function printAllPages():void {
	if (savedPdfsArray.length > 0) { //if there are pdfs to print...
		var pj:PrintJob = new PrintJob(); //create printjob
		if(pj.start()) {
			for (var i:int=0; i < savedPdfsArray.length; i++) {
            
            			//========== printjob bug fix - prevent blank pages: ==========
                		savedPdfsArray[i].x = 2000; //keep it hidden to the side of the stage
                		stage.addChild(savedPdfsArray[i]); //add to stage - prevents blank pages
                		//=============================================================
                
				//scale it to fill the page (portrait orientation):
				var myScale:Number;
				myScale = Math.min(pj.pageWidth/savedPdfsArray[i].width, pj.pageHeight/savedPdfsArray[i].height);
				savedPdfsArray[i].scaleX = savedPdfsArray[i].scaleY = myScale;
				var printArea:Rectangle = new Rectangle(0, 0, pj.pageWidth/myScale, pj.pageHeight/myScale);

				pj.addPage(savedPdfsArray[i], printArea); //add page to print job
			}
			pj.send(); //send to printer
		}
        
        	//========== printjob bug fix - prevent blank pages: ==========
        	for (var j:int=0; j < savedPdfsArray.length; j++) {
        	    stage.removeChild(savedPdfsArray[j]); //don't forget to remove them from the stage
        	}
        	//=============================================================
        
		pj = null;
	}
	else { //if there are no pdfs in the queue...
		errorPopup.openMe("You do not have any pdfs saved in your queue.");
	}
}

I hope this post saves someone else a lot of hair-pulling. Thank you "orangehaze" and Kirupa forum!

Page 6 of 7

Powered by WordPress & Theme by Anders Norén