Inheritance and composition aren't in opposition; they can work together. In this next task, you'll build a more generic superclass, MovieClipContainer, which wraps much of the MovieClip class API. Then, you'll rewrite Rectangle to extend MovieClipContainer. Additionally, you'll write a DraggableRectangle class that subclasses Rectangle. 1. | Open a new ActionScript document and save it as MovieClipContainer.as in the same directory as Rectangle.as. Then add the following class declaration:
class MovieClipContainer { } You'll abstract some of the basic functionality from Rectangle and move it to MovieClipContainer. As with Rectangle, note that MovieClipContainer does not subclass MovieClip.
| 2. | Define a private MovieClip property called _target.
private var _target:MovieClip; The MovieClip property is the movie clip that the MovieClipContainer wraps.
| 3. | Define the constructor so that it constructs a new empty movie clip.
public function MovieClipContainer(parent:MovieClip) { var depth:Number = parent.getNextHighestDepth(); _target = parent.createEmptyMovieClip("clip" + depth, depth); } The MovieClipContainer constructor consists of some of the code that was defined in Rectangle. Specifically, when you construct a MovieClipContainer instance, it adds a new empty movie clip to the specified parent.
| 4. | Define getters and setters for some of the basic properties normally defined by the MovieClip class. For each, simply proxy the requests to the corresponding property of the _target property.
public function get _x():Number { return _target._x; } public function set _x(x:Number):Void { _target._x = x; } public function get _y():Number { return _target._y; } public function set _y(y:Number):Void { _target._y = y; } public function get _alpha():Number { return _target._alpha; } public function set _alpha(alpha:Number):Void { _target._alpha = alpha; } public function get _rotation():Number { return _target._rotation; } public function set _rotation(rotation:Number):Void { _target._rotation = rotation; } public function get _width():Number { return _target._width; } public function set width(width:Number):Void { _target._width = width; } public function get _height():Number { return _target._height; } public function set _height(height:Number):Void { _target._height = height; } Each of the getters and setters corresponds to basic properties from the MovieClip class. When you call a getter or setter for an instance of the MovieClipContainer class, it proxies the request to the corresponding property for the target movie clip. For example, when you set _x for a MovieClipContainer, it proxies that to the _x property of the target movie clip.
| 5. | Edit Rectangle.as, make it subclass MovieClipContainer, delete the _target property declaration, and replace the first two lines of code in the constructor with a call to the superclass constructor. The new Rectangle class looks like the following:
class Rectangle extends MovieClipContainer { public function Rectangle(parent:MovieClip, width:Number, height:Number, ¬ color:Number) { super(parent); _target.lineStyle(0, 0, 0); _target.beginFill(color, 100); _target.lineTo(width, 0); _target.lineTo(width, height); _target.lineTo(0, height); _target.lineTo(0, 0); _target.endFill(); } } Now that Rectangle subclasses MovieClipContainer, it no longer needs to have a _target property or add the new empty movie clip because the superclass takes care of those things.
| 6. | Open a new ActionScript file, and save it as DraggableRectangle.as in the same directory as Rectangle.as and MovieClipContainer.as. Add the following class declaration:
class DraggableRectangle extends Rectangle { } DraggableRectangle subclasses Rectangle so it inherits from both Rectangle and MovieClipContainer.
| 7. | Add the following import statement to the top of the class:
import mx.utils.Delegate; To correct scope issues you'll want to use Delegate.
| 8. | Define the constructor.
public function DraggableRectangle(parent:MovieClip, width:Number, ¬ height:Number, color:Number) { super(parent, width, height, color); } DraggableRectangle needs to call the superclass constructor to create the empty movie clip and draw the rectangle.
| 9. | Within the constructor, define the onPress(), onRelease(), and onReleaseOutside() event handler methods for _target so that they call methods of the DraggableRectangle class.
public function DraggableRectangle(parent:MovieClip, width:Number, ¬ height:Number, color:Number) { super(parent, width, height, color); _target.onPress = Delegate.create(this, onPress); _target.onRelease = Delegate.create(this, onRelease); _target.onReleaseOutside = _target.onRelease; } When the user clicks on the target movie clip, call the onPress() method of DraggableRectangle. When the user releases the mouse, call the onRelease() method of DraggableRectangle.
| 10. | Define onPress() and onRelease() methods so they call startDrag() and stopDrag() for _target.
private function onPress():Void { _target.startDrag(); } private function onRelease():Void { _target.stopDrag(); } When the user clicks on the target movie clip, make it draggable.
| 11. | Open rectangle1.fla and add the following code after the existing line of code:
var block:DraggableRectangle; for(var i:Number = 0; i < 10; i++) { block = new DraggableRectangle(this, 25, 25, 0xFFFF00); block._x = Math.random() * 550; block._y = Math.random() * 400; } Draw 10 draggable rectangles and place them at random coordinates on the stage.
| 12. | Test the movie.
When you test the movie, you'll see 10 yellow rectangles placed in random locations. You can click and drag any of the yellow rectangles.
| |