23.4 Stage Four
In the fourth stage of the
application
we want to add some buttons that allow the user to move the circles,
as a group, as they bounce around. Also, we'll let
the user scale and rotate the circles as a group. Here are the steps
to follow to complete stage four:
Open stage3.fla and save it as
stage4.fla. Create a new movie clip symbol named
RectangleButton. Open the linkage properties for RectangleButton. Check the Export for ActionScript and Export in First Frame options
and add a linkage identifier of
RectangleButtonSymbol. Click OK to close the linkage properties. Edit RectangleButtonSymbol. Add the following code to the first frame of the default layer: #initclip
function RectangleButtonClass ( ) {}
RectangleButtonClass.prototype = new MovieClip( );
RectangleButtonClass.prototype.init = function (label, col, w, h) {
// If w (width) is undefined, default to 100; if h (height) is undefined,
// default to 30; if col (for color) is undefined, default to 0xDFDFDF (light
// gray); and if label is undefined default to "submit".
w = (w == undefined) ? 100 : w;
h = (h == undefined) ? 30 : h;
col = (col == undefined) ? 0xDFDFDF : col;
label = (label == undefined) ? "submit" : label;
// Create a movie clip into which to draw the rectangle button.
this.createEmptyMovieClip("btn", 1);
// Create a label text field. Use createAutoTextField( ) to make the text field
// autosize. (You will include TextField.as from Chapter 8 on the main
// timeline.)
this.createAutoTextField("label", 2);
// Make the text field nonselectable so it doesn't interfere with the button.
this.label.selectable = false;
this.label.text = label;
// If the label text field's width is greater than w, reassign a value to w to
// accommodate the text field.
w = (this.label._width > w) ? this.label._width + 6 : w;
// Draw a rectangle in the btn movie clip. (You will include MovieClip.as from
// Chapter 7 on the main timeline.)
with (this.btn) {
lineStyle(0, 0x000000, 0);
beginFill(col);
drawRectangle(w, h);
endFill( );
_x += w/2;
_y += h/2;
}
// Center the label within the button.
this.label._x = this._width/2 - this.label._width/2;
this.label._y = this._height/2 - this.label._height/2;
// When the btn clip is pressed and released, scale it to create an effect.
this.btn.onPress = function ( ) {
this._xscale = 96;
this._yscale = 96;
}
this.btn.onRelease = function ( ) {
this._xscale = 100;
this._yscale = 100;
}
};
Object.registerClass("RectangleButtonSymbol", RectangleButtonClass);
#endinitclip Edit the code on the first frame of the main timeline and make the
modifications shown here (changes are in bold): // Include DrawingMethods.as from Chapter 4 and MovieClip.as from Chapter 7.
#include "DrawingMethods.as"
#include "MovieClip.as"
// Include the libraries for the table and text field custom methods.
// TextField.as is from Chapter 8, and Table.as is from Chapter 11.
#include "TextField.as"
#include "Table.as"
function initCircles ( ) {
circles = new Array( );
_root.createEmptyMovieClip("circleHolder", _root.getNewDepth( ));
for (var i = 0; i < 10; i++) {
cir = circleHolder.attachMovie("CircleSymbol", "circle" + i,
circleHolder.getNewDepth( ));
cir.init(0, 0, 200, 200, Math.random( ) * 3 + 3, "random", 10);
cir.setCircleArray(circles);
circles.push(cir);
}
circleHolder.createEmptyMovieClip("border", circleHolder.getNewDepth( ));
with (circleHolder.border) {
lineStyle(0, 0x000000, 100);
drawRectangle(200, 200, 0, 0, 100, 100);
}
// Add an onEnterFrame( ) method to circleHolder that makes changes to the
// movie clip's properties depending on what button has been pressed.
circleHolder.onEnterFrame = function ( ) {
var vel = 5;
switch (this.action) {
case "up":
this._y -= vel;
break;
case "down":
this._y += vel;
break;
case "left":
this._x -= vel;
break;
case "right":
this._x += vel;
break;
case "rotateCW":
this._rotation += vel;
break;
case "rotateCCW":
this._rotation -= vel;
break;
case "scaleUp":
this._xscale += vel;
this._yscale += vel;
break;
case "scaleDown":
this._xscale -= vel;
this._yscale -= vel;
}
};
}
function initButtons ( ) {
// Create an array of names for the buttons.
btnNamesAr = new Array("left", "right", "up", "down",
"scaleUp", "scaleDown", "rotateCW", "rotateCCW");
// For each button in the array, create instances of the button component.
for (var i = 0; i < btnNamesAr.length; i++) {
btn = _root.attachMovie("RectangleButtonSymbol", btnNamesAr[i] + "Btn",
_root.getNewDepth( ));
btn.init(btnNamesAr[i]);
// Assign the button name to the action property for that button. This value
// corresponds to the possible action values for the circleHolder within the
// switch statement in its onEnterFrame( ) method.
btn.action = btnNamesAr[i];
// Assign onPress( ) and onRelease( ) functions for each button.
btn.onPress = pressBtn;
btn.onRelease = releaseBtn;
}
}
// This function is assigned to the onPress( ) event handler method for all the
// buttons; it sets the action property of the circleHolder to the action
// property value for the button being pressed. This causes the corresponding
// action to take place for circleHolder .
function pressBtn ( ) {
_root.circleHolder.action = this.action;
}
// When a button is released, set the circleHolder 's action property to null to
// stop the current action.
function releaseBtn ( ) {
_root.circleHolder.action = null;
}
// Create a table to position all the elements on the stage.
function createTable ( ) {
tr0 = new TableRow(5, new TableColumn(5, circleHolder));
tr1 = new TableRow(5, new TableColumn(5, leftBtn, rightBtn, upBtn, downBtn),
new TableColumn(5, scaleUpBtn, scaleDownBtn),
new TableColumn(5, rotateCWBtn, rotateCCWBtn));
t = new Table(5, 0, 0, tr0, tr1);
}
initCircles( );
initButtons( );
createTable( );
There is a lot of new code added in stage four. Save the file, and
let's take a look at some of the snippets that could
use a little more explanation.
Within the initCircles( ) function, we
added an onEnterFrame(
) method for the circleHolder movie
clip. This is a technique you can use to create continuous changes to
the movie clip's properties when a button is
pressed. When you assign actions to an onPress(
) method for a button (or button movie clip in this case),
that action occurs only once each time the button is pressed. For
example, if you place code to increment a movie
clip's _x property within the
onPress( ) method, you have to click the button
repeatedly to move the movie clip. If you want to use the button to
continuously change some object's properties, then
you need to come up with a different solution. In this case, you can
use an onEnterFrame( ) method on
circleHolder (the movie clip whose properties you
want to change). Each button assigns a different value to the
circleHolder's
action property; using a
switch statement, you can determine which
property or properties to update for the movie clip.
circleHolder.onEnterFrame = function ( ) {
var vel = 5;
switch (this.action) {
case "up":
this._y -= vel;
break;
case "down":
this._y += vel;
break;
case "left":
this._x -= vel;
break;
case "right":
this._x += vel;
break;
case "rotateCW":
this._rotation += vel;
break;
case "rotateCCW":
this._rotation -= vel;
break;
case "scaleUp":
this._xscale += vel;
this._yscale += vel;
break;
case "scaleDown":
this._xscale -= vel;
this._yscale -= vel;
}
};
Next, you should create all the buttons. You can create the rectangle
button component instances one at a time, or, more conveniently, you
can use a for statement to take care of this for
you. In this example, we use an array to store all the button names
and then loop through that array and create a component instance for
each element. We pass the init( ) method the
button name as a parameter so that its value shows up in the
button's label. You also should assign the name to
the action parameter of the component instance.
You use this property value in the onPress( )
method to determine which value to assign to the
action property of the
circleHolder movie clip:
function initButtons( ) {
btnNamesAr = new Array("left", "right", "up", "down",
"scaleUp", "scaleDown", "rotateCW", "rotateCCW");
for (var i = 0; i < btnNamesAr.length; i++) {
btn = _root.attachMovie("RectangleButtonSymbol", btnNamesAr[i] + "Btn",
_root.getNewDepth( ));
btn.init(btnNamesAr[i]);
btn.action = btnNamesAr[i];
btn.onPress = pressBtn;
btn.onRelease = releaseBtn;
}
}
When a button is pressed, assign that button's
action property value to the
circleHolder movie clip's
action property. This sets into motion the
corresponding actions. On the other hand, when the button is
released, set the
circleHolder movie clip's
action property to null to stop
the actions.
function pressBtn ( ) {
_root.circleHolder.action = this.action;
}
function releaseBtn ( ) {
_root.circleHolder.action = null;
}
|