Object.registerClass( ) Class Method | Flash 6 |
assign a constructor for a movie clip symbol |
A string specifying the linkage identifier of an exported movie clip symbol, as set in the Library under Options Linkage.
The class constructor function to associate with symbolID. Must be a function object reference, not a string. Use null to unregister a class.
A Boolean; true if registerClass( ) was invoked with the correct number of arguments, false if not. Note that Flash 6 returns false only when registerClass( ) is invoked with the wrong number of arguments; it does not check whether the class was registered successfully.
The registerClass( ) method is part of the toolset used to create a movie clip subclass from a movie clip Library symbol. It connects an ActionScript class to an exported Library symbol. When instances of the symbol are placed on the timeline manually or programmatically via attachMovie( ) or duplicateMovieClip( ), Flash automatically invokes theClass as the new instance's constructor function and sets the instance's class to theClass. When the constructor function runs, its this keyword points to the instance being created. For example, the following code creates a constructor function, Vehicle( ), and then links it to the movie clip symbol exported as carSymbol in the Library:
// The constructor function function Vehicle () { // Set speed on the new clip this.pixelsPerFrame = this.pixelsPerSecond / 12; } // Link the constructor to carSymbol Object.registerClass("carSymbol", Vehicle);
When instances of the carSymbol movie clip are created, they are constructed by the Vehicle( ) function. Inside the function, the this keyword refers to the new instance. Notice, however, that Vehicle( ) takes no parameters. Parameters are expected to be provided as object properties by attachMovie( ) or duplicateMovieClip( ) (using an initObject). For example, the pixelsPerSecond property is passed by attachMovie( ) and is available when Vehicle( ) executes. The Vehicle( ) function uses pixelsPerSecond to calculate the speed of the instance in pixels per frame (assuming the movie's frame rate is 12 frames per second).
To ensure that instances of our Vehicle class inherit all the methods and properties of the MovieClip class, we must make Vehicle a subclass of MovieClip, as follows:
// Set Vehicle's superclass to MovieClip Vehicle.prototype = new MovieClip();
Registered classes should always inherit from MovieClip. Once we've registered our class and set MovieClip as its superclass, we can create the rest of the class as usual. Here's the completed class:
// The constructor takes no parameters. They are optionally passed by // attachMovie() and duplicateMovieClip() via the initObject parameter. function Vehicle () { this.pixelsPerFrame = this.pixelsPerSecond / 12; } // Associate the Vehicle class with a Library symbol. Object.registerClass("carSymbol", Vehicle); // Set Vehicle's superclass to MovieClip. Vehicle.prototype = new MovieClip(); // Add the goForward() method to the Vehicle class. Vehicle.prototype.goForward = function () { this.onEnterFrame = function () { this._x += this.pixelsPerFrame; } } // Add the brake() method to the Vehicle class. Vehicle.prototype.brake = function () { delete this.onEnterFrame; } // Make an instance. The Vehicle constructor is called automatically. // The properties of our initObject (attachMovie()'s last argument) // are set on the fastCar_mc instance before the constructor runs. this.attachMovie("carSymbol", "fastCar_mc", 1, { pixelsPerSecond: 100 }); // Call a method. this.fastCar_mc.goForward();
To remove a class registration, invoke registerClass( ) using the ID of the movie clip to be unregistered as the symbolID parameter, and null as theClass. For example:
// Revert carSymbol to a normal movie clip. This sets carSymbol's // class back to MovieClip instead of being a subclass of MovieClip. // fastCar_mc remains an instance of Vehicle, however. Object.registerClass("carSymbol", null);
|
Note that once a class is registered, instances of that class can immediately be created programmatically with attachMovie( ) or duplicateMovieClip( ), as in our Vehicle example. However, instances placed manually on the timeline at authoring time must be created at least one frame after the class registration. Instances placed manually on the same frame as the class registration will not be members of the registered class. Use of the #initclip pragma can solve this problem.
For information on making a movie clip class self-contained (i.e., placing the class code on the timeline of the movie clip itself), see the #initclip pragma's entry in this Language Reference. For much more information on creating classes from movie clip symbols, see Chapter 14.
Note that a single class constructor can be registered to multiple Library symbols, but a single Library symbol cannot be registered to more than one class.
Though normally used with movie clips, Object.registerClass( ) can also assign an arbitrary string identifier to a class constructor. Flash uses the identifier to reestablish the class of an object when it is imported into the Flash Player via SharedObject, LocalConnection, or Macromedia Flash Remoting MX (Flash Remoting). When Flash sends an instance of a registered class out of the Player, it includes the class identifier with the instance. When Flash later reads the instance back into the Player, it checks the instance's class identifier and reassociates the instance with its class (this is known as casting the object).
For example, suppose we create an instance, p1, of a custom class, GamePlayer, which defines a score property and an addPoints( ) method, as follows:
// The class constructor function GamePlayer () { // The score property this.score = 0; } // The addPoints() method GamePlayer.prototype.addPoints = function (points) { this.score += points; } // The p1 instance p1 = new GamePlayer(); p1.addPoints(100);
As the code is shown, p1 is saved to disk via SharedObject (shown later) if its association with the GamePlayer class is lost, because GamePlayer has no identifier that links it to the serialized p1 object. We can still retrieve the p1 object and find its score property (because score is defined directly on p1), but we cannot access its class's addPoints( ) method via the prototype chain. To maintain the relationship between p1 and GamePlayer, we must add the following class registration, which assigns an arbitrary identifier ("GamePlayerClass") to the GamePlayer class:
Object.registerClass("GamePlayerClass", GamePlayer);
Henceforth, all instances of GamePlayer will be marked transparently as belonging to the class with the identifier "GamePlayerClass" (this name is arbitrary, but by convention you should use the name of the class with the word "Class" appended). When Flash serializes p1 before sending it out of the Player, it includes the identifier "GamePlayerClass" in the data to be sent. (Serialization is the process of converting an object's properties into a different format for transmission.) When Flash reads p1 from an external source, it notices that a class identifier has been saved with the data. It then attempts to cast p1 to the class registered to that identifier (GamePlayer). Technically, there is no guarantee that the GamePlayer class in effect when the SharedObject was saved is the same GamePlayer class in effect when the SharedObject is retrieved. Flash simply attempts to cast the retrieved object to a class whose registered identifier matches the object's registered identifier (which is assumed to be the same class constructor that was used when the data was first stored).
However, in the process of reconnecting the object with its class, Flash also executes the class constructor on the deserialized object. Normally, the object need not (indeed, should not) be reconstructed, so we must add to our constructor a flag that prevents any unwanted reinitialization. Here, then, is the basic code required to create a registered class:
// The GamePlayer class function GamePlayer () { // Initialize the first time the constructor runs only if (this.inited) { return; } // Make a note that we've initialized this object this.inited = true; // Carry on with initialization this.score = 0; } // The addPoints() method GamePlayer.prototype.addPoints = function (points) { this.score += points; } // Associate GamePlayer with the identifier GamePlayerClass Object.registerClass("GamePlayerClass", GamePlayer);
And here is the code to create an object instance and save it as player1 using a SharedObject:
// Create a GamePlayer instance p1 = new GamePlayer(); p1.addPoints(100); // Create the SharedObject gameData_so = SharedObject.getLocal("gameData"); // Make a property to save our GamePlayer object gameData_so.data.player1 = p1; // Attempt to save the SharedObject gameData_so.flush();
Here is the code required to retrieve a registered object from a SharedObject. There is no way to store an object's constructor or methods, even by registering its class. So, the GamePlayer class constructor and addPoints( ) method must be defined in the receiving movie, and the class must be registered with registerClass( ). Note that, as mentioned earlier, the GamePlayer constructor and method(s) need not be identical to the ones used at the time the object was saved, but ordinarily they would be. So, our receiving code begins identically to the code shown earlier for the sending movie. This code can be in the same movie as the sender (in which case it need not be repeated), or it can be in a different movie (perhaps even on the same machine, communicating with the sending movie via a LocalConnection object).
// The GamePlayer class function GamePlayer () { // Initialize the first time the constructor runs only if (this.inited) { return; } // Make a note that we've initialized this object this.inited = true; // Carry on with initialization this.score = 0; } // The addPoints() method GamePlayer.prototype.addPoints = function (points) { this.score += points; } // Associate GamePlayer with the identifier GamePlayerClass Object.registerClass("GamePlayerClass", GamePlayer);
And here is the code to retrieve the SharedObject and recreate the object instance saved in player1. Note that the GamePlayer constructor is invoked when the SharedObject.getLocal( ) function is executed (and the data is deserialized), although we don't access the player1 instance object directly until it is assigned to the variable, p1.
// Retrieve the SharedObject. gameData_so = SharedObject.getLocal("gameData"); // Retrieve our GamePlayer object. p1 = gameData_so.data.player1; // Check p1's score: trace(p1.score); // Add 50 points to p1's score. This works // only because the GamePlayer class is registered. p1.addPoints(50);
A similar workflow applies to objects sent over a network via LocalConnection and Flash Remoting. For more information on Flash Remoting, see:
#initclip, LocalConnection, MovieClip.attachMovie( ), Object._ _proto_ _, the SharedObject object; Chapter 14