23.5 Stage Five
The final stage in this application is to use an XML file to load
initialization data. Up to this point, we have hardcoded the number
of circles as well as their properties (color, radius, and velocity)
into the Flash document. However, you can create an XML document from
which you can load all that data at runtime so that you can make
changes to the movie without having to reexport the
.swf file. Here are the steps you should
complete to finish the fifth stage of the application:
Open a new text document and save it as
circles.xml in the same directory as where you
are saving your Flash documents. Add the following content to your XML document and save it: <collisionMovieData>
<!-- Define the dimensions of the rectangle within which circles can move. -->
<bounceArea width="200" height="200" />
<!-- Define the circles that should be created. In this example you create four
circles with random velocities and colors and with various radii. -->
<circles>
<circle radius="30" vel="random" col="random" />
<circle radius="5" vel="random" col="random" />
<circle radius="24" vel="random" col="random" />
<circle radius="10" vel="random" col="random" />
</circles>
</collisionMovieData> Open stage4.fla and save it as
stage5.fla. Modify the code on the main timeline, as shown here (changes are in
bold): #include "DrawingMethods.as"
#include "MovieClip.as"
#include "TextField.as"
#include "Table.as"
function loadData ( ) {
var myXML = new XML( );
myXML.ignoreWhite = true;
// Load the XML data from the XML document.
myXML.load("circles.xml");
myXML.onLoad = function ( ) {
// Get the width and height attribute values from the <bounceArea> element.
var bounceAreaWidth = this.firstChild.firstChild.attributes.width;
var bounceAreaHeight = this.firstChild.firstChild.attributes.height;
// Create an array to hold the values for each of the circles.
var circlesInfo = new Array( );
// Get the array of the <circle> elements.
var circlesNodes = this.firstChild.lastChild.childNodes;
var atr;
// Loop through all the <circle> elements, and add the
// attributes object for each to the circlesInfo array.
// The properties of the attributes object are vel , col , and dir .
for (var i = 0; i < circlesNodes.length; i++) {
circlesInfo.push(circlesNodes[i].attributes);
}
// Call the initCircles( ) , initButtons( ) , and createTable( ) functions only
// once the data has loaded. Pass initCircles( ) the width and height for the
// bounce area, and also pass it the circlesInfo array.
_root.initCircles(bounceAreaWidth, bounceAreaHeight, circlesInfo);
_root.initButtons( );
_root.createTable( );
};
}
// Modify initCircles( ) to accept parameters that define the width and height
// of the rectangle as well as an array of circle information objects.
function initCircles(baW, baH, circlesInfo) {
circles = new Array( );
_root.createEmptyMovieClip("circleHolder", _root.getNewDepth( ));
var cInfo;
// Loop through all the circle information objects, and use those
// values to create the circle component instances.
for (var i = 0; i < circlesInfo.length; i++) {
cInfo = circlesInfo[i];
cir = circleHolder.attachMovie("CircleSymbol", "circle" + i,
circleHolder.getNewDepth( ));
cir.init(0, 0, baW, baH, cInfo.vel, cInfo.col, cInfo.radius);
cir.setCircleArray(circles);
circles.push(cir);
}
circleHolder.createEmptyMovieClip("border", circleHolder.getNewDepth( ));
with (circleHolder.border) {
lineStyle(0, 0x000000, 100);
drawRectangle(baW, baH, 0, 0, baW/2, baH/2);
}
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 ( ) {
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;
}
}
function pressBtn ( ) {
_root.circleHolder.action = this.action;
}
function releaseBtn ( ) {
_root.circleHolder.action = null;
}
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);
}
// Call loadData( ) instead of the other three functions. The other
// functions are now called once the data has loaded.
loadData( );
Save the file and test it. There are really only two changes that we
have made in this stage of the application. First of all, rather than
hardcode the data into the Flash document, we use an XML object to
load the data into the movie at runtime. You don't
want to initialize the movie until after the data has loaded, so you
should invoke the initCircles( ),
initButtons( ), and createTable(
) functions from within the XML
object's onLoad( ) method.
Additionally, you want to extract values from the XML data and pass
those values along to the initCircles( )
function. The bounceAreaWidth and
bounceAreaHeight values are rather self-evident.
The circlesInfo array, on the other hand, might
not be immediately clear. You want to construct an array in which
each element represents the properties (color, velocity, and radius)
of the circles that are defined in the XML document. This is rather
convenient because each of the <circle>
elements contains an associative array with those three properties
(the attributes of the XML element). So you can use the
push( ) method to append the value of each
<circle> element's
attributes property to the circlesInfo array.
myXML.onLoad = function ( ) {
var bounceAreaWidth = this.firstChild.firstChild.attributes.width;
var bounceAreaHeight = this.firstChild.firstChild.attributes.height;
var circlesInfo = new Array( );
var circlesNodes = this.firstChild.lastChild.childNodes;
var atr;
for (var i = 0; i < circlesNodes.length; i++) {
circlesInfo.push(circlesNodes[i].attributes);
}
_root.initCircles(bounceAreaWidth, bounceAreaHeight, circlesInfo);
_root.initButtons( );
_root.createTable( );
};
Then you need to make a small modification to the
initCircles( ) function so that it accepts and
uses the parameters loaded from the XML data. Not much needs to
change. The hardcoded values for each circle's
color, velocity, and radius should be replaced by the values from the
circlesInfo array, and the hardcoded values that
previously defined the width and height of the bounce area rectangle
should be replaced by the parameters baW and
baH:
for (var i = 0; i < circlesInfo.length; i++) {
cInfo = circlesInfo[i];
cir = circleHolder.attachMovie("CircleSymbol", "circle" + i,
circleHolder.getNewDepth( ));
cir.init(0, 0, baW, baH, cInfo.vel, cInfo.col, cInfo.radius);
cir.setCircleArray(circles);
circles.push(cir);
}
circleHolder.createEmptyMovieClip("border", circleHolder.getNewDepth( ));
with (circleHolder.border) {
lineStyle(0, 0x000000, 100);
drawRectangle(baW, baH, 0, 0, baW/2, baH/2);
}
|