The Design and Implementation of Multimedia Software
An Example with Described Dynamic Visual Content

The Code for the Bus

/**
 * A BigBus is a Sprite that has Sprite objects for the tailpipe
 * exhaust.
 *
 * The Exhaust objects move themselves but the BigBus object
 * determines their position (so that they are positioned
 * relative to the tailpipe).
 *
 * @author  Prof. David Bernstein, James Madison University
 * @see     "The Design and Implementation of Multimedia Software (c) 2011"
 * @version 1.0
 * @augments RuleBasedSprite
 */
BigBus.prototype = new RuleBasedSprite();
BigBus.prototype.constructor = BigBus;

BigBus.EXHAUST_COUNT = 15;

/**
 * Explicit Value Constructor
 *
 * @param {Content} content   The Content to use for the BigBus
 * @param {float} width     The width of the Stage
 * @param {float} height    The height of the Stage
 * @param {Stage} stage     The Stage
 */
function BigBus(content, width, height, stage)
{
   this.initializeRuleBasedSprite();   
   this.initializeBigBus(content, width, height, stage);
}


BigBus.prototype.initializeBigBus = function(content, width, height, stage)
{
   this.setContent(content);   
   this.exhaust = new Array();
   for (var i=0; i<BigBus.EXHAUST_COUNT; i++)
   {
      this.exhaust[i] = new Exhaust();
      stage.add(this.exhaust[i]);          
   }
   
   this.x    =   0.0;
   this.y    = 300.0;       
   this.maxX = width;
   this.maxY = height;       
}

    

/**
 * Handle a Metronome tick
 * (required by Sprite [through MetronomeListener])
 *
 * @param {int} millis   The number of milliseconds since the Metronome started
 */
BigBus.prototype.handleTick = function(millis)
{
   // Move the bus
   this.x = this.x + 1;
   this.setLocation(this.x, this.y);
   if (this.x > this.maxX+50) this.x = 0;
   
   // Set the origin for the Exhaust objects
   for (var i=0; i<this.exhaust.length; i++)
       this.exhaust[i].setOrigin(this.x, this.y+63);
   
   // Inform the Exhaust objects that a tick has occurred
   for (var i=0; i<this.exhaust.length; i++)
       this.exhaust[i].handleTick(millis);
}
      

The Code for the Exhaust

/**
 * A "piece" of exhaust.  Several Exhaust objects together give the
 * appearance of exhaust from a tailpipe.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @see     "The Design and Implementation of Multimedia Software (c) 2011"
 * @version 1.0
 * @augments RuleBasedSprite
 */
Exhaust.prototype = new RuleBasedSprite();
Exhaust.prototype.constructor = Exhaust;

Exhaust.DIAMETER = 5;


/**
 * Default Constructor
 */
function Exhaust()
{
   this.initializeRuleBasedSprite();   
   this.initializeExhaust();
}
    
Exhaust.prototype.initializeExhaust = function()
{
   var shape   = new Ellipse2D(0,0,5,5);
   var content = new DescribedContent(shape,"black","gray",null);
   this.setContent(content);
    
   this.length = Math.random()*15;   
   this.count  = -1;       
   this.originX = 0.0;
   this.originY = 0.0;
   this.slope   = 0.0;
}


/**
 * Handle a Metronome tick
 * (required by Sprite [through MetronomeListener])
 *
 * @param {int} millis   The number of milliseconds since the Metronome started
 */
Exhaust.prototype.handleTick = function(millis)
{
   this.count++;
       
   if (this.count >= this.length)
   {
      this.count = 0;          
      this.setLocation(this.originX, this.originY);          
   }
   else
   {
      this.slope  = Math.random()*4 - 1;   
      this.setLocation(this.originX-this.count, 
                       this.originY-(this.count*this.slope));          
   }
}

/**
 * Set the origin.
 *
 * All movements of this Exhaust object will be relative to
 * the origin.
 *
 * @param {float} x    The horizontal coordinate of the origin
 * @param {float} y    The vertical coordinate of the origin
 */
Exhaust.prototype.setOrigin = function(x, y)
{
   this.originX = x - Exhaust.DIAMETER/2;
   this.originY = y - Exhaust.DIAMETER/2;       
}