A Little Extra OOP (for particle systems)

April 16, 2009

A Little Extra OOP

Working with particle systems requires that you delve a little deeper into the wonderful world of OOP (Object-Oriented Programming). There are a few new concepts (and some you’ve already seen) that will take you a long way when working with particle systems: encapsulation, inheritance, access modifiers, polymorphism, getters and setters, static properties and methods, static constants, and throwing errors.

Encapsulation
Encapsulation involves exposing only what is necessary in order to use a class. You can think of it as the dials on your car radio. You don’t need to understand electronics to turn on your car radio. The circuitry is behind the scenes and the same is true about your code. You can have very complex code structures hidden using encapsulation and reveal only the bare minimum of what your user needs to interact with. This has been one of the cornerstones of PV3D and you’ll find many complex code structures beneath the sub-layer of PV3D’s commonly used classes.

Inheritance

Key to many applications in PV3D is the concept of inheritance. You can recognize when inheritance is in play by the “extends” keyword. The class you extend will therefore inherit all the properties and methods of the class it extends. So in the simple starter code below the new “ClassExtends” class will inherit from the Sprite class all of its methods and properties.

package {
import flash.display.Sprite;

public class ClassExtends extends Sprite
{
public function ClassExtends()
{
}
}
}

Inheritance saves you tons of space and labor by allowing you to write reusable code, and you can attach that code to other classes, thus extending their functionality very easily.

Polymorphism

It’s often joked that polymorphism is a word that will impress friends at parties, most likely it will get them going the other way. Polymorphism is the concept that an object that inherits from a class can be used in place of an instance from that class.
So to cut through all the formalism, it’s all about data types. If I’ve extended a class by the Movie class then that class can be treated as the Movie datatype. Think of it as the king’s son. If the king is allowed into the thrown room, so is his son, because in a sense he is an extended version of the king. There’s much more to polymorphism of course (or it wouldn’t have such a big name), but this is enough to get you through particles.

Access Modifiers

You’ve already dealt with access modifiers. They give you the ability to control your encapsulation, exposing and restricting various code elements in the sub-layers of your program, defining what properties and methods are exposed for use behind the scenes. As discussed in a previous chapter access modifiers use the keywords: public (everyone), private (within your class), protected (available to descended or sub-classes), internal (same package where defined).

Getters and Setters

If you open up the PV3D’s DisplayObject3D class you’ll find tons of getter and setter methods and if you’ve never seen this before it may seem a little strange, but it has its roots in the “best practice” of keeping all your class properties private. But you can still access those properties through pubic methods (so you protect the private property but expose it using public methods). And since this approach is used so much special methods “get” and “set” have been created just for the process of getting and setting data. Get allows you to get the private property, and set allows you to change that private property. If you only have a get method and not set method the property is read-only…you can’t change it.

In the code snippet below taken from the DisplayObject3D class you get and set the value of X rotation. The first step is to set your “_rotationX” property to private. Note: the underscore in front of the property “_rotationX” is just a convention, which indicates that the property is private.

So to illustrate this principle, in the statement below the “_rotationX” property is set to private.

private var _rotationX :Number;

By using the get and set methods you can access the “_rotationX” property as shown:

public function get rotationX():Number
{
if( this._rotationDirty ) updateRotation();

return Papervision3D.useDEGREES ? this._rotationX * toDEGREES :
this._rotationX;
}

public function set rotationX( rot:Number ):void
{
this._rotationX = Papervision3D.useDEGREES ? rot * toRADIANS : rot;
this._transformDirty = true;
}

Now, in your main program, all you need to do is reference rotationX to get or set your private property. For example, if want to get or set the x rotation of a cylinder use the code below:

get method: cylinder.rotationX
set method: cylinder.rotationX = 45;

You’ll use getter/setter methods as you add various physical properties to your particles.

Static Properties and Methods


Static properties and methods are attached to a class, as opposed to the instance of a class. A good example of this is aligning an object to the center of the stage. You do this all the time and it would be handy to have some reusable code that does this for you automatically. Using static properties and methods allows you to do this, and you won’t have to create an instance of this class every time you need it, but you will access it directly.

package utils
{
//Visual objects (top level objects) need to be imported.
import flash.display.DisplayObject;
public class Utils
{
public static var centerMyObject:String=”Center Object!”;
public function Utils()
{
}

//Because of polymorphism you can pass in any object that inherits from the Display Object class

public static functioncenterObject1(myObject:DisplayObject):void{

myObject.x=myObject.stage.stageWidth/2-myObject.width/2;
myObject.y=myObject.stage.stageHeight/2-myObject.height/2;
}
public static function centerObject2(myObject:DisplayObject):void{

myObject.x=myObject.stage.stageWidth/2
myObject.y=myObject.stage.stageHeight/2
}
public static function centerObject3(myObject1:DisplayObject,myObject2:DisplayObject):void{

myObject2.x=-myObject1.width/2;
myObject2.y=-myObject1.height/2;
}
}}

Another important category of static classes commonly used in PV3D is the Tweener class (such as TweenLite or Caurina). Typically, an object needs to be tweened in a certain way, which makes this approach ideal. Just toss your object into a static tween method and away you go. Tweeners are handled in more detail in a later chapter.
Static Constants


A static constant is like a static variable, but it never changes. Just open up the ObjectDisplay3D class and you’ll see tons of them. Static constants are typically used with events and have the following form.
* tells Mesh3D’s render() method to sort by measuring from the center of a triangle*/
public static const MESH_SORT_CENTER:uint = 1;
The convention is to use all caps when creating static constants and the separation of words with underscores. This is what Flash does with its static constants.
Throwing Errors (Try/Catch)

Why in the heck would you want to throw or create an error…aren’t there enough of them? When Flash has an error it doesn’t always know what to do with that error (or provides vague information). Throwing errors (and catching them) gives you the ability to take control of the process, directing Flash on what to do for certain types of errors or providing more details to the user about that error. The example below checks to see if a video is available; if it is not available an error is thrown

if(!video){
throw new Error(“No Video Available”)
}

It’s important to understand that when Flash encounters a throw statement that no more code can be run in the routine (its current script is terminated). It works somewhat like a return statement in a loop, but there’s more. When an error is thrown, Flash stops the current process and looks for some code that can catch what is being thrown.
To catch that thrown error you can use a try/catch block as shown below:

try
{
//statements
}
catch(myError:Error)
{
//statements
}

When an error is thrown, Flash looks to see if it was thrown within a try/catch block, if it was, it goes to the next position in the stack and executes its catch statement. The try/catch block gives you the ability to do something when your error occurs as opposed to stopping your code, which could potentially wreck your program.
Now that you have a little more OOP under your belt, you can now proceed to build advanced particle systems.


Follow

Get every new post delivered to your Inbox.