Tutorial: Placing objects (movie clip symbol instances on ...



Tutorial: Placing objects (movie clip symbol instances on the stage) using ActionScript; Printing

Here is a stub of an application that demonstrates placing movie clip symbol instances—I call them walls—based on the player clicking twice on a portion of the Stage. The coding involves the Point object in the flash.geom package. The application also uses the PrintJob object to print part of the screen. This is a start of an application that would let the player design a maze. Note: at the end of these notes, I show how to print everything on the Stage.

The application allows the player to position walls on a board on the Stage. The player clicks once to set one end of the wall and a second time to set the other end. Positioning the wall requires a calculation to determine the rotation as well as the width (length) of the wall. These calculations use various built-in functions such as Point.distance and Math.atan2. The screen shot shows the results of player actions:

[pic]

The application involves the following features of Flash:

• creation and display of movie clip instances during runtime using ActionScript

• event handling for mouse clicks. More specifically, the coding must be such as to distinguish between a first and a second click.

• calculation of distance between two points to adjust the width of an object and degree of rotation based on the two points

• providing the player with the option of printing the board

• [for the eventual application: maintaining a list of the created instances]

Implementation

The first step is to create 2 movie clip symbols in the Library: one called board and the other called wall. The board symbol is just a big rectangle. Create the symbol and then bring an instance to the Stage and give it the instance name board.

The wall symbol is as shown:

[pic]

Notice that the origin and the transformation point are at one end. This is important because the positioning of the created instances is done based on one end being the origin and based on rotation at that point.

Because we want to create new instances of the wall symbol using code during runtime (as opposed to bringing instances over the Stage during development time), we need to right click on the wall symbol in the Library and select the Properties panel. Then select the Export for ActionScript box and also the Export to frame 1 box (this may go on by itself). Type as the class: Wall. The default Base class will be flash.display.MovieClip and you can keep that as is. Here is what the Properties should look like when you on done:

[pic]

If instead of this panel, you just have the top portion with the button Advanced, click on Advanced to get the whole thing.

We will use Flash components for the button to start printing. Click on Window/Components/User Interface Button and drag a button to the Stage. Give the button the name printbtn and use Window/Component Inspector to change the label to Print.

The last thing I to set the Stage (so to speak), was to use the T tool to place a static text field with the instructions: Click on board to place a wall: 2 clicks per wall.

The Stage (at a reduced magnification) is shown below:

[pic]

The rest of the application is in the coding. Click on Window/Actions. Make sure nothing else is selected.

The event handling for responding must, as indicated above, distinguish between a first and a second click. This is done by making two calls of the addEventListener method. I create a function draw1 to respond to first clicks and a function draw2 to respond to second clicks. Code in each of these two functions changes the event handling. The following outlines of the functions show how this is done.

CAUTION: don't copy and paste this code. It is shown again below. DO examine it to understand how the switch is made for responding to the mouse clicks.

board.addEventListener(MouseEvent.CLICK,draw1);

function draw1(ev:MouseEvent) {

board.removeEventListener(MouseEvent.CLICK,draw1);

board.addEventListener(MouseEvent.CLICK,draw2);



}

function draw2(ev:MouseEvent) {

….

board.removeEventListener(MouseEvent.CLICK,draw2);

board.addEventListener(MouseEvent.CLICK,draw1);

}

I will now explain what is done in the functions. The idea is to store the location information from the first click so it can be used for the second click. The information is used to locate one end of a wall, set the width to be equal to the distance between the two points, and rotate to wall so it goes roughly from the first point to the second point. This last calculation requires converting from a radian measure to a degree measure: the rotation property of movie clips takes degrees. The Math trig functions, namely atan2, produces radians. I use the const feature in Flash to set up a constant I call raddeg. It is equal to 180/PI. Calculating this once saves time. I use global variables (outside of any function) to hold the two points. Lastly, I have indicated an array, called walls. This is for the future for this application. It is where references are stored to all the walls.

The Point.distance method, a static (meaning it is not attached to any particular Point object) is part of the flash.geom package, so I use an import statement to make it accessible using just Point.distance.

import flash.geom.*;

board.addEventListener(MouseEvent.CLICK,draw1);

const raddeg=180.0/Math.PI;

var pt1:Point = new Point();

var pt2:Point = new Point();

var walls:Array=[];

The draw1 function simply stores the location clicked on by the mouse. This information is acquired using the ev parameter passed into the function. The localX and locally is in terms of the board object. This is exactly what we want since we will make the newly created wall a child of the board object.

function draw1(ev:MouseEvent) {

board.removeEventListener(MouseEvent.CLICK,draw1);

board.addEventListener(MouseEvent.CLICK,draw2);

pt1.x=ev.localX;

pt1.y=ev.localY;

}

The draw2 function does most of the work! The first step is to create a new Wall object. This works because the wall symbol in the Library has been set to be accessible by ActionScript during runtime. The code positions the new object, named w, at the first point, pt1. The code then sets pt2, in the same way, that is, using ev.localX and ev.localY. Next, the code sets the width of w to be the distance between the points. The next step is to determine the rotation. The atan2 function returns the angle (in radians) based on the change in y and the change in x. I use the raddeg constant value to change that to radians and then use it to set w.rotation. The board.addChild adds w to the display list as a child of the board. This also makes the coordinates work and also (see below) means that any created walls will be printed. Lastly, looking to the future, I used the code walls.push(w) to add this wall to a list of walls.

function draw2(ev:MouseEvent) {

var w:Wall = new Wall();

w.x=pt1.x;

w.y=pt1.y;

pt2.x=ev.localX;

pt2.y=ev.localY;

w.width=Point.distance(pt1,pt2);

var ro:Number;

ro=raddeg*Math.atan2(pt2.y-pt1.y,pt2.x-pt1.x);

w.rotation=ro;

board.addChild(w);

walls.push(w);

board.removeEventListener(MouseEvent.CLICK,draw2);

board.addEventListener(MouseEvent.CLICK,draw1);

}

Assuming you have written the import statement, the const and var statements, the first board.addEventListener (outside of any function) and the two function definitions, you can now test the program.

The next task of this sample application is printing the board. By the way, to save toner and time, I changed the fill for the board to be white, that is, no color.

Add the line of code setting up the event handling for clicking the button:

printbtn.addEventListener(MouseEvent.CLICK,printscreen);

Then define the printscreen function.

function printscreen(ev) {

var myPrintJob:PrintJob = new PrintJob();

myPrintJob.start();

myPrintJob.addPage(board);

myPrintJob.send();

}

Keep in mind that you can set up more complex print jobs then this one. The name of the object: PrintJob does convey this: you can set up a multi-page operation and query its status. For this application, the code creates the PrintJob object, starts the job, THEN adds the page for printing out the board object plus all its child objects. This is exactly what we want: the board plus the Wall objects that have been added. The first argument is any MovieClip (actually any Sprite, a more general object than MovieClip).

There are two optional parameters for addPage. A second parameter can be a Rectangle object that specifies the area of the printed page to receive the printing. It is possible using this parameter or NOT using this parameter for clipping to occur: that is, just the upper left portion of the object is printed. The third parameter can specify bitmap printing as opposed to the default of vector-based. The third parameter is constructed as an associative array of a special type.

var options:PrintJobOptions = new PrintJobOptions();

myPrintJob.addPage(board,new Rectangle(0,0,300,500),options);

If you need to set the third parameter, but not the second:

myPrintJob.addPage(board,null, options);

This application only needed the first parameter. Lastly, we send the job to the printer. The player will be presented with a typical printer window for choosing a printer.

[pic]

Here is the complete ActionScript code. It is all in frame 1.

import flash.geom.*;

board.addEventListener(MouseEvent.CLICK,draw1);

printbtn.addEventListener(MouseEvent.CLICK, printscreen);

const raddeg=180.0/Math.PI;

var pt1:Point = new Point();

var pt2:Point = new Point();

var walls:Array=[];

function draw1(ev:MouseEvent) {

board.removeEventListener(MouseEvent.CLICK,draw1);

board.addEventListener(MouseEvent.CLICK,draw2);

pt1.x=ev.localX;

pt1.y=ev.localY;

}

function draw2(ev:MouseEvent) {

var w:Wall = new Wall();

w.x=pt1.x;

w.y=pt1.y;

pt2.x=ev.localX;

pt2.y=ev.localY;

w.width=Point.distance(pt1,pt2);

var ro:Number;

ro=raddeg*Math.atan2(pt2.y-pt1.y,pt2.x-pt1.x);

w.rotation=ro;

board.addChild(w);

walls.push(w);

board.removeEventListener(MouseEvent.CLICK,draw2);

board.addEventListener(MouseEvent.CLICK,draw1);

}

function printscreen(ev) {

var myPrintJob:PrintJob = new PrintJob();

myPrintJob.start();

myPrintJob.addPage(board);

myPrintJob.send();

}

What if you want to print everything on the screen, NOT just the board and its dynamically created children? The following approach works. The addPage method needs to refer to an object that contains everything. I use the parent of the board. It must be coerced (converted) to be a Sprite. My example still puts this in a function. You can use the code anywhere and substitute for board the instance name of anything on the Stage.

function printscreen(ev) {

var myPrintJob:PrintJob = new PrintJob();

myPrintJob.start();

var all:Sprite = Sprite(board.parent);

myPrintJob.addPage(all);

myPrintJob.send();

}

This does not address any issues of error handling, for example, a non-functioning printer. Also note that if the player cancels the print job, an error is thrown, which you can see if you test this from the Flash environment.

................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download