1. Code
  2. Interface Design

Create a Stylish 3D Interface with Papervision3D: Structure


In this Tut, you will learn how to create a complete 3D Interface framework that you can easily modify and re-use. I promise, by the time you finish, you'll have a better understanding of Papervision3D, learn a handful of effects and apply them to PV3D.

You'll also have a good understanding of OOP and how classes work together in a medium scale project like this one. We'll start with the simplest class and progress to more complex ones. The project has a total of 17 classes working together. Also, the interface is set up so that you can easily plug-in any game that you've developed.

Also available in this series:

  1. Create a Stylish 3D Interface with Papervision3D: Structure
  2. Create a Stylish 3D Interface with Papervision3D: Effects and Submenus

Step 1: Create a New Project

Open FlashDevelop and click Project > New Project

Step 2: Set Up

Choose Actionscript 3 > AS3 Project.

For the name of the Project put in

For the location, click and navigate to the folder you would like to save it into.
Leave the Create Directory For Project checkbox selected and click OK.

If you want to use Flash CS3+, create a new Flash file and set the width and height to 1000x700, set the background color to black, and set the frame rate to 40. Name it interface3D.fla and save it anywhere you like.

Step 3: Preparing Assets for Use

For FlashDevelop, open the project directory and copy or drag soundAssets from the source download (linked at the top of the page) into the \bin\ folder. Inside the source download folder is another folder named actionscript. This folder contains all the Actionscript classes for the project. Except for the and the, the rest of the classes in this folder are the completed versions of what you will be writing.You can compare your work with them every time you finish a class you made from scratch following the tutorial. Drag the and the files into the \src\ folder where the class resides. Those 2 classes come as freebie. I'll discuss more about them later.

For Flash, copy or drag soundAssets folder from the source download into the same folder where you have interface3D.fla. Then drag the 2 classes mentioned above into the same folder.

Let's review the contents of the soundAssets folder. We have 10 sound files in MP3 format which will be used for sound effects.

Step 4: Install TweenLite & Papervision3D

We're going to use TweenLite for the tweening and Papervision for 3D. Both packages are included with the source download. For more info, you can visit their websites at Papervision and TweenLite.

For FlashDevelop, go ahead and copy or drag greensock.swc and the Papervision3D_2.1.932.swc from the Source download into the \lib\ folder for this project.

From FlashDevelop, click View > Project Manager

Step 5: External Libraries

Still in FlashDevelop, click the '+' sign to the left of the lib folder to expand it.

Select both swc files and right-click, choose Add to Library.

For Flash, copy or drag the \com\, \org\, and \nochump\ folders from the Source download into the same folder as your interface3D.fla file.

Step 6: Setting Up the Document Class

If you're using Flash CS3+, just follow along. Instructions for Flash CS3+ continue in step 8.

Now, in FlashDevelop, click view and choose Project Manager as you did in step 4. Once the Project Manager, go into the \src\ folder and double-click to open the class. This class is the document class for this project and is automatically generated for every new project. Below is the list of responsibilities it needs to accommodate for our application.

  1. load sound assets to use for effects using the CustomLoader class
  2. once all the sound assets are loaded, create and add the 3D menu into the stage
  3. listen for FullScreen events and inform UserInterface3D about it
  4. add some random sound effects to enhance the atmosphere
  5. listen for UserInterface3D.START_GAME to know when to load a sprite or a movieclip representing a game
  6. load the UserInterface3D back into the stage again when the game sprite has been removed

Note that for the 2nd responsibility of this class, we will first use a Tester class and then later on replace it with the UserInterface3D class. Tester will be used for creating and testing the 3D classes as you create them and UserInterface3D will put the them all together as one complete application.

Go inside the package declaration and replace all the imports with the list below:

These imports will all be used by the time you complete this project. As for instance variables, let's start with 2, _timer which will be a Timer instance assigned with a random delay which is for playing sound effects to add atmosphere to our project, and _customLoader to hold the single instance of the CustomLoader class which will be used to load all the sound assets.

Add the following lines of code inside the Class declaration above the constructor method:

Step 7: Document Class Initialization

Still in FlashDevelop, right below where it says 'entry point' inside the init () method, add the following lines of code:

For those of you not familiar with the CustomLoader class, It is mainly used to load visual and sound assets. It is based on the Singleton Pattern to make sure there is only 1 instance that will hold all the external assets for the project. My other tutorial for Creating Intros with PV3D linked here, has detailed information for building this class.

Its list of responsibilities are:

  1. load external assets (display and sound assets).
  2. give out a list of names of all the assets that were loaded.
  3. dispatch a 'CustomLoader.ALL_LOADS_COMPLETE' event when all the assets have loaded successfully.
  4. provide the asset when requested.
  5. if something goes wrong during loading, send out the error.

To start using the CustomLoader class, we assign _customLoader an instance returned by calling the CustomLoader.getInstance () static method. As soon as the _customLoader instance has been created, it's important to add a 'CustomLoader.ALL_LOADS_COMPLETE' listener to it. This will inform us when all the assets have loaded successfully. To add a visual asset like an image to the queue for loading, just call the addItem () method and pass in the url as parameter. For sound assets, call addSound () and also pass in the url as parameter.

Once all the assets you want to load have been added to the queue, call the startLoading () method. The names for each sound/image asset are automatically generated by getting its short name. For example: if you load 'soundAssets/menuCollapse.mp3', the name to access this sound asset will be 'menuCollapse'. To get the list of all the names of all the assets (images and sounds), just call _customLoader.names like trace (_customLoader.names) and all the names will print as an array of names. To access images, call the _customLoader.getItem () method and just pass in the short name in string format. For sounds, call _customLoader.getSound () and pass in the short name also in string format. We will only need to load sound assets for this project since all the graphics will be generated by Papervision3D.

Step 8: Testing the CustomLoader Instance

For a simple test, let's play a random sound asset by accessing all the names of the assets currently stored by the CustomLoader instance. Add the following lines of code below the init () method:

Now when you run the project, you should hear a random sound played. Run it a few more times and you're likely to hear a different sound each time.

For Flash, Create a new Class named 'Main' where you saved your interface3D.fla and use it as the Document class. The imports are usually generated by FlashDevelop automatically but since you're using Flash to create your classes, just add them all now and you'll see what they're used for later on. Copy the code below and replace all the code inside the new class:

Now run the application by hitting CTRL + ENTER.

Great! Now we know the CustomLoader works! Let's move on.

Step 9: Generating Sound Effects to Add Atmosphere

Replace the contents of the onLoad () Method with the code below:

Here, we assign a local variable 'sound' an instance of the background2.mp3 and play it 100 times. Then the createRandomNoise () method is called. Add the following code below the onLoad () method:

Add the onTimerComplete() Method below the createRandomNoise () Method.

To complete the class add the getRandomInRange () static method. This useful method is declared static to maximize its accessibility. It simply generates a random number between $min and $max, and returns it:

  • rounded if the 3rd parameter is left as default,
  • as a float if the 3rd parameter is set to false.

Add the following lines of code below the onTimerComplete () method:

All the createRandomNoise () method does is assign a new Timer instance to _timer with a random interval between 5 and 20 seconds. An onTimerComplete listener is then triggered each time the Timer completes and this is where the 'randomEcho' sound is played and as you can see, the sound generated has variable volume between 0 and .7. It then calls the createRandomNoise () method again to start a new Timer. This creates some sort of a random sound loop with varying interval. Go ahead and run a test if things are working. If everything went well, you should hear the sound effects play in the background when you run the program.

Save your work and let's move on to creating 3D objects.

Step 10: Creating the Tester Class

If you're using Flash CS3+, again, just follow along. Instructions for Flash CS3+ will continue in Step 13.

As mentioned earlier, this class will be used for testing 3D objects. This class will inherit from BasicView which makes of a quick 3D template ready for use. In FlashDevelop, click View > Project Manager, right-click the \src\ folder and choose Add > New Class.

The New Actionscript Class window will pop-up. For the Name enter 'Tester', for the Base Class, click browse and enter 'org.papervision3d.view.BasicView'. Click "OK" to finish.

This is a simple class. Its responsibilities are to:

  1. Add simple 3D perspective.
  2. Create simple 3D object as prototype as starting point for creating custom DisplayObject3D classes.
  3. Test each custom DisplayObject3D created as we create them.

Add the following imports inside the package brackets before the class declaration:

Step 11: Tester Instance Variables

Now add the following private instance variables inside the Class declaration:

These 5 variables will be used to move the camera around in an orbiting manner. The objects added to the scene will not move but will look so since the camera will be the one moving around them. We'll add other variables as we develop their corresponding DisplayObject3D classes. When we get to the UserInterface3D, we'll have the objects rotate and hold the camera at a stationary position instead.

Step 12: Tester's Constructor

The constructor will call 2 methods to start things, first, the init () method which will handle general initialization and second, startRendering () which will start Papervision's 3D rendering engine. Add the following lines of code inside the Constructor Method:

Step 13: Adding 3D Display Objects

This method will take care of initializing the 3D objects we're about to create . For now let's add a simple DisplayObject3D into to the scene as a warm up. Add the following lines of code below the Tester Constructor method:

The addSimpleDO3D () Method will add a 3D vector graphic along with 3D text into the scene. This will serve as the prototype for the custom classes we will make soon. Add the code below the init () method:

First, we create a VectorShape3D, this Class is Papervision's 3D version of Flash's Vector graphic. To make this 3D graphic asset, we need an instance of the VectorShapeMaterial to use as its material. Once a VectorShape3D has been instantiated, we can then access its Graphics3D property for drawing.

Using Graphics3D is very similar to using Flash's native Graphics class. Here we assign a local variable named 'material' of type VectorShapeMaterial a new instance. Another local variable named 'vs3D' of type VectorShape3D is then instantiated assigning 'material' as its parameter. To start drawing, a local variable named 'g' is assigned the VectorShape3D's Graphics3D property. The color is set by calling Graphics3D's method beginFill () and passing in the color 0xFF0000 (red). Additionally, you can pass in a value between 0 and 1 as the second parameter to set the alpha property. We set the Graphics3D line property by calling its lineStyle () method and passing in 2 parameters to set its thickness and color properties respectively. Here we set the thickness to 1 and the color to 0x0000FF (blue). Drawing is then started by calling Graphics3D's moveTo method and passing in the starting x and y positions. Here we start at the left-top corner -199 units to the left of 'x' axis center and 106 units up the center y axis. A call to Graphics3D's lineTo () method is then repeated 4 times to draw a square VectorShape3D. The shape is drawn by creating a line from the starting point (-199,106) going down (-199,-106), then to the right (199, -106), and then up (199,106) and finally completing the square, back to (-199,106).

To apply alpha transparency of .6 to the VectorShape3D object, we assign a local property named vLayer of type ViewportLayer, the ViewportLayer of the VectorShape3D instance. We do this by calling Viewport.getChildLayer () method and passing in the instance of VectorShape3D assigned to vs3D, this parameter takes in DisplayObject3D objects. Once assigned, you can then apply effects for the 3D asset just like you would on a regular display object.

The next thing we do is add 3D text. This is where we will first use the imported class. This class is a 3D font created using Mathuie Badimon's 'Make a typography file' version 2.0 software. You can get more information about it here. To create 3D vector text, we'll need to instantiate 4 properties and pass them as parameters when the 3D text is instantiated:

  1. The 1st is the text it will write, this is in String fomat. Here we pass it the nameString variable.
  2. Next, letterMaterial of type LetterMaterial. When instantiating this class, here we pass in the color of 0x00FF00 (green). If left alone, the default parameters are pink for the color and 1 for the alpha (full opacity).
  3. The 3rd variable font3D of type Font3D is assigned an instance of the class.
  4. The 4th and optional parameter is the name parameter, used as the name for the Text3D instance. This too is in String format.

Here, we create a new Text3D and pass it nameString to use for its text, font3D for the its font, letterMaterial for its material, and nameString again for its last and optional parameter, its name property. All we need to do now is position it, set its align property, and add it into the scene. Since we are using font for this project, we will set Text3D's align property to 'left', its 'x' position is set to 650 to center it in the 'x' axis, the 'y' position is assigned 10 to center its 'y' axis, finally the 'z' position is set to -25 to make it appear in front of the VectorShape3D.

To apply alpha transparency, we will use the same method as we did for the VectorShape3D we created earlier. A local variable named tLayer of type ViewportLayer is assigned text3D's ViewportLayer. Again, this is done by calling Viewport's instance method 'getChildLayer' and passing in text3D as parameter. The alpha value of .6 is then set for tLayer. This is only way to apply filters and effects to anything that inherits from DisplayObject3D. As you will see later when we cover effects more extensively.

Here, we create a new Text3D and pass it nameString to use for its text, font3D for the its font, letterMaterial for its material, and nameString again for its last and optional parameter, its name property. All we need to do now is position it, set its align property, and add it into the scene. Since we are using font for this project, we will set Text3D's align property to 'left', its 'x' position is set to 650 to center it in the 'x' axis, the 'y' position is assigned 10 to center its 'y' axis, finally the 'z' position is set to -25 to make it appear in front of the VectorShape3D. To apply alpha transparency, we will use the same method as we did for the VectorShape3D we created earlier. A local variable named tLayer of type ViewportLayer is assigned text3D's ViewportLayer. Again, this is done by calling Viewport's instance method 'getChildLayer' and passing in text3D as parameter. The alpha value of .6 is then set for tLayer. This is only way to apply filters and effects to anything that inherits from DisplayObject3D. As you will see later when we cover effects more extensively.

To keep things organized, we'll use an empty DisplayObject3D to house both VectorShape3D and Text3D and then add that into the scene. A local variable named do3D of type DisplayObject3D is created, adds vs3D and text3D into it and then adds it to the scene.

Go back to your class and add the code below inside the onLoad () method after the createRandomNoise () method call:

Now run it to view the product. It should look like the cut-out below with the sound effects playing in the background. If you're using Flash, just add the code above inside and follow along to the end of this step.

Let's add 1 last method before moving on to creating our first custom DisplayObject3D class. This will take care of moving the camera around and give us that 3D perspective. Add the following lines of code below the addSimpleDO3D () method:

This method is from BasicView's superclass AbstractView. It's triggered on every enterFrame event once the startRendering () method is called as we did inside the init () method.

Now, when you run a test, you'll see that the camera is now orbiting your DisplayObject3D. It might look like the object is moving but its actually the camera that's rotating around the center of the scene. In this method, the main function is the Camera.orbit () method. To use this method, xDist & yDist are assigned the distances of the mouseX & mouseY from the center of the scene basing it from the width and height of the stage. The instance variable _camPitch of type Number is used as the value to orbit the camera on the 'y' axis (moving left or right). This is calculated by first multiplying yDist with _rotX and then subtracting the current value of _camPitch plus 90. Adding 90 adjusts the camera so that when the mouse is on center, the camera is also looking straight at the center of the stage. _easOut is then multiplied to the overall value to apply easing to the camera's movement. The same concept applies with _camYaw which has the effect applied to the camera's 'x' axis (moving up or down). We add 270 to center the camera when the mouse is centered on the stage. The two variables are then passed into the Camera.orbit () method to move the camera. Lastly, super.onRenderTick () is called at the end of the method so that the super classes can render the 3D scene.

OK, run another test and see some 3D movement going on!

Whoa! Did you see that?! I'm not talking about the 3D perspective. When you move your mouse to the left of the stage, do you notice how the Text3D went to the back of the VectorShape3D? You've got a 'Z' sorting issue. Don't worry, we have a simple solution which we'll add to the UIComponent3D class we're creating next. Save your work before going to the next step.

If you're using Flash, apply the changes mentioned earlier for the Main document class and continue here. Create a new class named, save it in the same folder where you have interface3D.fla file. Copy the code below into it, save it again and then run it.

If you run into problems, just compare your code with the completed classes included with the source download.

Step 14: Creating a Custom DisplayObject3D Base Class - UIComponent3D

What this class needs to do is simplify adding custom drawn VectorShape3D with optionally visible text3d into the scene. It will also be in charge of 'z' sorting. This will be part of the solution we will discuss later. It will add, remove, and dispatch InteractiveScen3DEvents, draw the 3D vectors and calculate their dimensions. This class will serve as the Super class for all the different visual assets (including buttons) used in this project. Here is the list of its responsibilities:

  1. provide width and height properties translated into PV3D's unit measurement system.
  2. draw custom vectorshape3d and access its ViewportLayer to apply effects.
  3. add text3D, also access its ViewportLayer to apply effects.
  4. organize z sorting.
  5. add listeners, remove listeners, and dispatch InteractiveScene3DEvents.

For FlashDevelop, create a new class, name it UIComponent3D and have it extend DisplayObject3D. See Step 10 for a refresher.

For Flash, create the class inside the folder you've been using for interface3D.fla.

Select all of the code inside the class and replace it with the lines below:

After the package declaration comes all the required class imports. Then comes the class declaration. Below that, you see all the protected variables needed for its functionality. Comments are listed to the right of each variable for usage description. Then comes the constructor. The first 3 parameters are required followed by an optional 4th parameter. Its important to have a name for each DisplayObject3D for reference. The $viewport parameter is needed to access the ViewportLayer of the Text3D and VectorShape3D which will have effects applied to. The coordinates parameter is an array of Number2D used for drawing. The 4th parameter allows to show or hide the 3D text.

The constructor calls super () to assign the name for the DisplayObject3D and the rest are custom properties are stored for each UIComponent3D instance.

Step 15: UIComponent3D Visual Customization

Once an instance of UIComponent3D has been created, we can then customize the VectorShape3D's properties before drawing. Add the following lines of code after the constructor:

These are all implicit setter methods. You can read more about these methods, including their counterparts here. You'll see them in action later.

Step 16: UIComponent3D Initialization

Once we've set up the visual properties, we can then initialize the UIComponent3D instance externally. An example will show why we have this set as public methods. Here, setDimensions () is called to set its width and height. Afterwards the createInterface () method is called to draw the VectorShape3D and finally, createText () is called to create the Text3D. Add the following method above the getter methods:

Step 17: Calculating UIComponent3D's Width and Height Properties

We need to get these properties to create an interactive plane later when we extend this for our Button3D class.As you know, Papervision DisplayObjects don't have width and height properties so we're adding them as custom instance properties inherited by all of the subclasses. For the width, we use simple math and add the farthest 'x' position to the left of center with the farthest 'x' position to the right. The same applies for the height. Add the code after the init () method:

To have these protected properties accessible externally, let's add implicit getters for them as well. Add the methods below above the other implicit getters at the bottom of the class:

Step 18: Drawing the VectorShape3D

This method is called next inside the init () method. It takes care of adding the 3D graphics into UIComponent3D and assigns its ViewportLayer to _interfaceLayer for applying effects later. Remember the addSimpleDO3D () method in the Tester class. Plus now it takes in an array of Number2D coordinates to use for drawing. Add the following lines of code below setDimensions ():

Inside the method is a call to setLayerIndex () method, its part of fixing our 'z' sorting issue. What it does is assign the passed in ViewportLayer parameter the layerIndex of the passed in index parameter. Add it below the end of createInterface () method.

Step 19: Adding Text3D

This was also part of the addSimpleDO3D () method, we just it separated for more control and to keeps things simple. Add the code above the setLayerIndex () method:

The setLayerIndex () method is called again, this time passing in the Text3D's ViewportLayer and is assigned the value of _layerIndex + 1. With this the Text3D will always be drawn in front of the VectorShape3D. Also, notice how we check _showText is set to true, this is set to false by default as the last parameter for the Constructor method.

Step 20: Adding and Removing InteractiveScene3DEvent Listeners and Dispatching

For Papervision, this is the event you want to listen to for interactivity. Add the following codes below the setLayerIndex () method:

The first 2 simplifies adding and removing MouseOver, MouseOut, and MouseClick events. The last 3 takes care of dispatching them. These all help the extending subclass - Button3D. I've decided to put these methods inside UIComponent3D to keep Button3D focused on its other responsibilities.

Step 21: External Access to ViewportLayers for Effects and Filters

Add the methods below to allow other classes to apply effects for each UIComponent3D. This will be used by the DistortionEffect3D you will create later.

Step 22: External Access to Text3D for Positioning

We'll have to manually adjust the position for each Text3D when we get to creating a couple of descendant classes extending Button3D. Add the code below after the get textLayer () method:

This completes our UIComponent3D class! Save it before going for the next step.

Step 23: Milestone Testing out UIComponent3D

Go back to the Tester class and comment out the addSimpleDO3D () method call. Next, add addCustomDO3D () method call below it. Then add the method listed below after the addSimpleDO3D () method:

Remember how we set up UIComponent3D's constructor? We have 3 required parameters and 1 optional which defaults to false. The first parameter is used as both the name and text. The second is the Viewport3D property of BasicView to access ViewportLayers for UIComponent3D. The third is an array of Number2D's which is used to draw the VectorShape3D. And last, the optional parameter $showText, which here we set to true. The next thing we need to after instantiating UIComponent3D is call its init () method. Then we position its Text3D and add it into the scene. The visual properties are what we set as default. To change color and transparency for both fill and line style, just assign them before calling the init () method. We'll apply them later as we build more complex DisplayObject3D's like MainMenu3D. The Text3D doesn't have any way of changing colors since we don't need it here but you can always add another optional parameter for UIComponent3D's constructor for this. Declare _uic as an instance property of type UIComponent3D and then run the program.

Your result should be similar to the image below.

Ok. It works. But we still have that 'z' sorting issue even when we're already managing the layerIndex for our VectorShape3D and Text3D. For the layerIndex 'z' sorting to take effect, we need to change the viewport's containerSprite's sort mode to index sort. Go into Tester's init () method and add the code below before anything else.

Make sure the following import is included inside Tester's package before running the app again.

Alright! That takes care of the 'z' sorting issue. Again, if you're having bugs, check your code against the completed classes included with the source download. If all went well, let's start building the Button3D class.

Step 24: Creating Button3D

For Button3D, instead of having it simply dispatch mouse events then extending it to add effects, we'll do it all in one go. Also, this is part of the reason we added the listeners to Button3D's super class - UIComponent3D. It inherits from UIComponent3D then adds its own functionality. Here are the list of its responsibilities:

  1. play sound effects for mouse over and mouse click.
  2. add an interactive plane that will trigger the mouse events.
  3. apply effects for mouse over, mouse out, and mouse click.
  4. provide external control for adding and removing mouse event listeners.
  5. provide external control to remove mouse click listeners utilized when we create buttons that only listen for mouse over and mouse out to scroll Text3D as you saw in the About menu.

Create a new class and name it Button3D. Have it extend UIComponent3D and copy the code below into it to start things. I expect that you already know how to create new classes regardless which editor you are using.

As usual, the required imports are at the top of the page as part of the package. Inside the class declaration, the first 2 properties are declared as public static constants since both will be used by external and descendant classes. They're for 'z' positioning for for the button. The other 5 are instance variables accessible for subclasses. See the comments for their use. The constructor method takes in the same parameters as the superclass, this time setting the 3rd parameter also optional. The 4th parameter is also modified to show the text by default.

Step 25: Button3D Constructor

Add the code below inside the constructor method:

The first thing it does is check if $coordinates value is null, if it is, it assigns its own set. So whenever an instance of this class is created with the 3rd parameter set to null, it will have a default set of coordinates to draw. (I've included a simple drawing tool with the tutorial which you can use to generate these coordinates.)

A call to super () method is then made passing in the assigned values which is handled by UIComponent3D. The CustomLoader instance is then accessed for the sound effects used for mouse events. The volume of the sounds we're using is a little loud so we compensated with the SoundTransform class.

Step 26: Adding Functionality to the createInterface () Method

Aside from drawing the VectorShape3D, we also want to add a plane that will listen to mouse events here in Button3D. We can do that by overriding the createInterface () method inherited from UIComponent3D and apply new functionality to it. Add the code below after the constructor:

This is the best example to show the effectiveness of OOP. By overriding the inherited method and then just adding to it, we avoid duplicate code. All we did here is call super.createInterface (), passing in the parameter to have UIComponent3D do its thing and then calling addInteractivePlane () to have Button3D add a plane to use for interactivity. Add the code below after the createInterface () method:

The method is simple. It assigns a new plane with the color of 0 (black) and an alpha of 0 to make it completely transparent. This is where we get to use the _width and _height properties inherited from UIComponent3D. To create a plane, we simply instantiate an instance by passing in 3 parameters, the color material, which we set to black with full transparency, then _width and _height. Once created, it's then placed in the same 'x' position as the inherited _interfaceGraphic VectorShape3D. Button3D then adds it as a child and calls the activate () method. The activate () method is called here so that once a Button3D is instantiated, it is automatically interactive. I'll explain more about the activate () and deActivate () methods when we get to them.

Step 27: Applying Effects to Reflect Interactivity

My favorite part, creating effects! Ok, so let's go over the effect we want to achieve. For mouse over, we want the button to move closer to the camera, play a sound, have it glow for a second then fade back to normal again. For mouse out, we just want the button to move back to its original position. For mouse click, we want the button to also move back to its original position, blink 3 times and then dispatch the button click event so that the menu containing them doesn't start close before the 3 blinks finish. Let's start with the mouse over effect. Add the following code below the addInteractivePlane () method:

Firstly, we play the sound we assigned for mouse over. Then we move the button's 'z' position 50 units closer to the camera. Remember assigning the ViewportLayer properties of the VectorShape3D and Text3D into them when we were building UIComponent3D? We use TweenMax because it has the extra capability of applying blur and glow effects, not to mention others that TweenLite doesn't have. Here, we instantly assign an array of filters to both _interfaceLayer and _textLayer. It's as simple as assigning filters to a regular Sprite class since in essence, the ViewportLayer is a Sprite. TweenMax is used to fade the effects out. A call to UIComponent3D's onObjectOver () method is then made passing in the same InteractiveScene3DEvent that triggered this one.

Next, for mouse out, Add the code below after the onObjectOver () method:

All this does is trigger the UIComponent3D's onObjectOut () method and position the button back to its original location.

Now for the mouse click effect. Add the following method below the onObjectOut () method:

When an instance of the Button3D is clicked, first thing it does is play a sound. It's then returned back to its original 'z' position. Two methods are then called - flashText () and deActivate (). We use InteractiveScene3D.OBJECT_RELEASE to inform the MainMenu3D holding this Button3D so that it can disable all the other buttons after a choice has already been made. Add the 2 helper methods below the onObjectClick () method:

Ok, so there's another helper method helping the flashText () helper method. Hey, whatever it takes to achieve the effect, right?! =)
When flashText () is called, it creates a timer with a delay of 15 milliseconds which repeats 9 times. The blink () method is then assigned as the callback for every TIMER event, dispatchClick () is assigned as callback for the TIMER_COMPLETE event. every time the blink () method is called, _text3D's visibility toggles. This happens 9 times which makes it look like the text blinked really fast 3 times. Once the timer completes, blink () is called one more time to make _text3D visible again and the onObjectClick event is dispatched.

Step 28: External Controls for Adding and Removing MouseEvent Listeners

Add the following lines of code:

These methods will allow the MainMenu3D to control when the Button3D should listen to mouse over, mouse out, and mouse click events.

Step 29: Extra Functionality

Visit the demo app again and play with the About menu for a second. Notice how the scrollers don't need to listen for mouse clicks. For this, we'll have to add functionality to remove the mouse click listener automatically added by default. Add the 2 methods at the bottom of the class:

The set noClick () setter method simply assigns the Boolean parameter passed in to it. To remove the click listener, just call this method and pass in a value of true before calling the button's init () method. Button3D overrides the addMouseListeners () method and checks if the _noClick property is true, if it is, it stops listening for click events.

Step 30: Milestone Testing Button3D

Go back to and comment out the addCustomDO3D () method call inside the init () method. Next, add a call to addButton () method below it. Then add the 2 methods listed below after the init () method:

First, it assigns a local variable named 'b' as an instance of Button3D, and passes in a name and text of 'button 0' and the viewport. Remember, the last 2 parameters are optional. Now run it. You should see something like the cut-out below:

Oops! No mouse interaction?! To listen for mouse events, first, we need to make the viewport interactive. Go back inside Tester's init () method and add the code below the sortMode assignment:

That's it! Run it again and see how it reacts to the mouse. The onButtonClick () method informs us that the button is clicked via trace and then we call Button3D.activate () on the button to have it listen for mouse events again. Remember, we have this set to disable itself as soon as the button is clicked. Also, you can change the speed of the blinks if you think its a little fast - see step 27. But once effects are added, you might need to re-adjust it again.

Let's do another button, this time, let's customize it a bit since the last one had all default properties. Change the code inside addButton to what we have below:

Just so we know the mouse over and mouse out event listeners are working, add the code below after the onButtonClick () method before running another test:

Here's a snapshot of our new Button3D with the custom properties we assigned.

And that completes our Button3D class. Now relax, take a break and come back when you're ready for more.

Step 31: Creating the Main Menu - MainMenu3D

This DisplayObject3D instance will be what you see as the main page that opens up when the application first starts. It holds 4 buttons - start game, settings, about, and exit. It manages its own animation and processes events before sending them up the display hierarchy. Here is its list of responsibilities:

  1. create 2 borders to act as casing for the contents
  2. create and add the 4 buttons and add listeners for them
  3. prepare for intro animation
  4. add effects and animations
  5. provide external control for playing intro and exit animations
  6. manage activating and deactivating the buttons
  7. dispatch custom events triggered by the 4 buttons so that UserInterface3D can load the appropriate submenu, have the Main document load the game sprite, or close the entire application

Create a new class and name it MainMenu3D. Have it extend DisplayObject3D. Once the class file is open, just copy and paste the code below replacing the content of the class.

First, the required imports inside the package declaration then come the instance variables and class constants.

Step 32: MainMenu3D Constructor

The constructor takes in 2 required parameters, $name and $viewport. super () is called to assign the $name for the DisplayObject3D instance. And $viewport is saved for reference later. Add the code below inside the constructor method:

Step 33: Instance Initialization

The init () method triggers 3 other methods that abstract the creation for the borders, the buttons, and the distortion effect. Add the code below after the constructor:

The 1st method, createFrame () simply adds the 2 borders as children. We use UIComponent3D since all they need to be are visual components. Add the following code below the init () method:

The addButtons () method takes care of adding the 4 buttons. Add the code below next:

Here, _buttonArray is assigned a new Array to hold references for the 4 buttons. As _buttonTitles is iterated through, listeners for OBJECT_CLICK and OBJECT_RELEASE are then added for each button created. they are then positioned on their 'y' axis based on _buttonPosY for the current iteration. Remember how we setup the onObjectClick () method for Button3D, the 1st takes care of the extra animation effects for the button while the other propagates up to MainMenu3D. You'll see its use when we get to the event handlers later.

Lastly, the setMenuEffect () method. Add the code below:

This is where we will add the distortion effect. For now, just leave it until we create the custom DistortionEffect3D class. We'll do that next as soon as we finish MainMenu3D.

Step 34: Handling the Intro Animation

If you study how the main menu from the preview link at the top of the page, you'll see the sequence of operation. The menu borders fade in and move to open. Once open, the buttons start to show from the bottom to the top. All flashing and playing sound. To start, the intro animation will need to be prepared before playing it. Add the code below after the setMenuEffect () method:

This is where we will add control for activating the distortion effect you'll be creating later. The code above positions the 2 borders close to the center so they can animate outwards in an opening manner. Their alphas are set to 0 so they can slowly appear when the intro starts. All the buttons are then made invisible so they can appear 1 by 1 in sequence once the borders have finished opening.

Add the code below next. This will take care of playing the intro and provide external access for it:

This method calls prepareIntro () to get everything in proper place before starting the animation. A local variable sound of type Sound is assigned a reference to the sound effect named 'menuExpand' saved in the CustomLoader instance. Next, TweenMax is used to slowly fade the 2 borders' alpha property in. This tween has a duration of 0.4 seconds and has a delay factor of 0.5 seconds. The sound is called to play when it starts, and the tween is set not to get overwritten. Another call to TweenMax is assigned for the actual movement of the 2 borders, this time with a delay of .75 seconds. .25 seconds after the fade in starts, the 2 borders are animated to open. The 2 borders move to open in 0.5 seconds and when finished, calls the initializeButtons () method.

Add the code below:

This is how the 4 buttons are activated and then added to the menu in sequence. It counts backwards from the number of buttons delayed by .07 seconds. At each iteration a call to showButtons () is made passing in _buttonArray's value for the the current iteration. Below is the last method which completes the intro animation:

Once this is called, the button passed in as parameter is worked on to. It first shows the button then then trigger its onObjectOver () method to simulate a mouse over event. Immediately after, it puts the button in its default mouse out position.

Step 35: Handling Mouse Events

From within MainMenu3D, the buttons will be handled by their name to identify which button was clicked and dispatch the appropriate event it needs to trigger. The onButtonClick () method will send the event to MainMenu3D's containing parent, either UserInterface3D or the Tester class we're currently using. Add the code below:

The rest of the animation for the button is done so by the button itself. Remember, we set this method to get triggered by each button's onObjectClick () method. That method takes care of all the button animation effects before dispatching this event upward. After dispatching the appropriate event, the menu is informed to exit. Next, add the code below for the onButtonRelease () method:

This is the simplest method for MainMenu3D, its sole purpose is to make sure that when a button is clicked, the user, no matter how fast he tries, won't be able to click another button and possibly trigger something undesirable. Go back to Button3D's onObjectClick () method to see how this is triggered.

Step 36: Handling the Exit Animation

Once the user has decided what to do, either edit the settings, play the game, whatever, Mainmenu3D will start exiting and inform Tester or UserInterface3D when its finished. Note that this method is declared public, matching its counterpart startIntro (). UserInterface3D will have no need to call this method since it is handled internally. Add the code below:

This is where we will add control to deactivate the distortion effect mentioned earlier. Here, the buttons are hidden from view one by one in sequence. The opposite of how they appeared in the initializeButtons () method. Add the hideButtons () method next:

This method is what makes the buttons flash one by one and then hide in sequence before the 2 borders animate to close. It first simulates a mouse over effect. Another delayedCall () is applied so that the button stays long enough to finish the button over effect before being removed from visibility. After that, it checks if the button being worked on is the last button from the list of buttons and if it is, calls the closeNav () method. Add the 2 methods next:

Once all the buttons have been set invisible, the 2 borders begin to close. The first 2 calls to TweenMax take care of fading out the top and bottom borders. The fade out takes 0.2 seconds with a delay of 0.4 seconds. The end of the fade dispatches the EXIT_COMPLETE event. For the second set of TweenMax calls, the borders are animated inwards in a closing manner. It takes 0.5 seconds to complete, uses the Expo.easeInOut for the ease and doesn't have any delay. This call also plays the sound 'menuCollapse' for the closing sound effect. And we're done with MainMenu3D! Alright, save and get ready for testing.

Step 37: Milestone Testing MainMenu3D

Go back to the Tester class' init () method. Comment out the call to addButton () and add a call to addMainMenu () below it. Copy the method below after the init () method:

Here, MainMenu3D is instantiated passing in the name 'menu' for the name and viewport for its _viewport property. Listeners are then assigned for all the events the MainMenu3D instance will dispatch. After adding it to the scene, we need to call the MainMenu3D's public method startIntro () to have it load. Let's add the corresponding methods for the listeners before testing. Add the code below after the addMainMenu () method:

Now run the application. Click here to see the result:

Once any of the 4 buttons is clicked, the MainMenu3D instance dispatches the event then exits. You should see print outs of what the button triggered. Here, we just load the menu again when the MainMenu3D.EXIT_COMPLETE event is received. Again, the buttons might be blinking a little fast for anyone to notice but it should slow down once we start adding effects. Play with it a little to get more familiar with it. We're going to extend this class for both the AboutMenu3D and SettingsMenu3D submenus later. Now, let's work on the DistortionEffect3D before we move on to higher grounds.


Thanks for reading up to this point! Join me again for the second and concluding part where we'll finish our interface.

Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.