DekGenius.com
[ Team LiB ] Previous Section Next Section

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:

  1. Open stage3.fla and save it as stage4.fla.

  2. Create a new movie clip symbol named RectangleButton.

  3. Open the linkage properties for RectangleButton.

  4. Check the Export for ActionScript and Export in First Frame options and add a linkage identifier of RectangleButtonSymbol.

  5. Click OK to close the linkage properties.

  6. Edit RectangleButtonSymbol.

  7. 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
  8. 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;
}
    [ Team LiB ] Previous Section Next Section