DekGenius.com
[ Team LiB ] Previous Section Next Section

23.3 Stage Three

In the third stage you want to add more circle instances to the movie. In and of itself, this is quite easy now that you have created a component. However, adding more circles adds another level of complexity. The circles should bounce off each other as well as the sides of the rectangle. To accomplish this, you need to devise a way in which each circle knows about all the other circles. This is not as difficult as it may sound. Here are the steps to complete the third stage of the application:

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

  2. Open the Circle symbol and modify the code as follows (changes are in bold):

    #initclip
    
    function CircleClass(  ) {}
    
    CircleClass.prototype = new MovieClip(  );
    
    CircleClass.prototype.init = function (minX, minY, maxX, maxY, vel, col, radius) {
      with (this) {
        lineStyle(0, 0x000000, 0);
        beginFill(0, 100);
        drawCircle(radius);
        endFill(  );
      }
      this.minX = minX;
      this.minY = minY;
      this.maxX = maxX;
      this.maxY = maxY;
      this._x = Math.random(  ) * this.maxX;
      this._y = Math.random(  ) * this.maxY;
      if (vel == "random") {
        this.vel = Math.random(  ) * 6 + 3;
      } else {
        this.vel = vel;
      }
      this.dir = Math.random(  ) * Math.PI * 2;
      this.colObj = new Color(this);
      if (col == "random") {
        col = Math.random(  ) * 255 * 255 * 255;
      }
      colObj.setRGB(col);
    };
    
    // The setCircleArray(  )  method allows you to define an array of references to
    // all the circle instances.
    CircleClass.prototype.setCircleArray = function (cirAr) { 
      this.circleArray = cirAr; 
    }; 
    
    CircleClass.prototype.onEnterFrame = function (  ) {
      this._x += Math.cos(this.dir) * this.vel;
      this._y += Math.sin(this.dir) * this.vel;
      if ((this._x + this._width/2) >= this.maxX) {
        this._x = this.maxX - this._width/2 - 1;
        this.dir += 2 * (Math.PI/2 - this.dir);
      }
      else if ((this._x - this._width/2)<= this.minX) {
        this._x = this.minX + this._width/2 + 1;
        this.dir += 2 * (Math.PI/2 - this.dir);
      }
      if ((this._y + this._height/2) >= this.maxY) {
        this._y = this.maxY - this._height/2 - 1;
        this.dir -= 2*this.dir;
      }
      else if ((this._y - this._height/2) <= this.minY) {
        this._y = this.minY + this._height/2 + 1;
        this.dir -= 2*this.dir;
      }
    
      // Loop through all the elements in the circle array and determine if the
      // circle has collided with any of them.
      for (var i = 0; i < this.circleArray.length; i++) { 
        cirB = this.circleArray[i]; 
    
        // Get the distance between the two circles using the Pythagorean theorem
        // (see Recipe 5.13).
        var dx = Math.abs(this._x - cirB._x); 
        var dy = Math.abs(this._y - cirB._y); 
        var dist = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); 
    
        // If the distance between the two circles is less than the sum of their 
        // radii, they have collided. Also, make sure the current circle is not this 
        // because you don't want to detect a circle's collision with itself!
        if(dist <= (this._width/2 + cirB._width/2) && cirB != this) { 
    
          // This code sets the new directions for the colliding circles.
          var circlesAngle = Math.atan2(this._y - cirB._y, this._x - cirB._x) + 
                                       Math.PI/2; 
          this.dir = (circlesAngle + this.dir)/2; 
          cirB.dir = (-circlesAngle + cirB.dir)/2; 
        } 
      } 
    };
    
    Object.registerClass("CircleSymbol", CircleClass);
    
    #endinitclip
  3. Modify the code on the first frame of the main timeline as follows (changes in bold):

    #include "DrawingMethods.as"
    
    // Place the code in a function to keep things organized as you add more
    // functionality in the subsequent stages.
    function initCircles(  ) { 
      
      // Create a movie clip to contain all the circle instances.
      _root.createEmptyMovieClip("circleHolder", _root.getNewDepth(  )); 
    
      // Create an array to hold the references to all the circles.
      circles = new Array(  ); 
    
      // Create 10 circle instances. For each circle, store a reference to the circle
      // array and then add the circle instance to the array. This enables each
      // circle to reference all the other circles.
      for (i = 0; i < 10; i++) { 
        cir = _root. CircleHolder.attachMovie("CircleSymbol", "circle" + i, i); 
        cir.init(0, 0, 200, 200, "random", "random", 10); 
        cir.setCircleArray(circles); 
        circles.push(cir); 
      } 
    
      // Draw the border within the circle holder movie clip instead of on _root .
      circleHolder.createEmptyMovieClip("border", i);
      with (circleHolder.border) {
        lineStyle(0, 0, 100);
        drawRectangle(200, 200, 0, 0, 100, 100);
      }
    }
    
    initCircles(  );

The additional code in this stage of the application is rather straightforward. By creating an array of references to all of the circle instances, and assigning that array as a property of each circle, each circle can know about all the other instances. Then, within the onEnterFrame( ) method, you check whether the circle has collided with the rectangle boundaries or with any of the other circles. The only thing that might be unclear in this new code is the mathematics involved. Refer to Chapter 4 and Chapter 5, and draw a diagram of two colliding circles, and that will help to clarify the math. Save and test your movie to see how it works.

    [ Team LiB ] Previous Section Next Section