Uploaded to www.rart.com/j2me-presentation/html_Source/ March 19, 2002

The Class LinesME

This is an example of a Rart universe ported to the J2ME environment. See the use of the ColorME class.

Lines also uses the small EndPoint class, the source for which we also have provided here.

This version has been tested with j2mewtk 1.0.2 and 1.0.3

/*
 * @LinesME    1.0  010915 
 * 
 * © A-Square, Inc.   
 * 1648 Waters Edge Lane, Reston Virginia, 20190, USA  
 */
 package rartme.univ;
 import javax.microedition.lcdui.*;
 import rartme.*;


/**
 * Lines universe
 *	 
 * Source: LinesME.java
 * Description: Displays a window with lines that wander across the screen.
 * When the endpoints rech the border, they bounce off in random directions.
 * There are a number of lines on the screen at the time and they change 
 * color as they progress. The original Rart Lines universe was programmed
 * in QuickBasic for the Macintosh around 1985. 
 *		
 *	This version is adapted to J2ME and the first real universe to be
 * programmed in the ME environment. With a color display there are 
 * options to select background from the standard Java colors using the
 * ColorME class.
 * Released as a sample universe for RartME, September 2001
 * Proud Author: Jan Aminoff
 */


public final class LinesME extends UniverseME {
	
	// Section 1     Identifying the Universe
	// ------------------------------------------------------------------------
	
	public String getName(){	// Name
    	return("LinesME");}       // Name of the universe.
    public String getDescription(){
    	return(sd);}            
    private String sd=			// Description
    		"  In the Lines Universe two end points are "+
            "stepped streight until they bounce randomly "+
            "against the edge of the display. Lines join the two end "+
            "points for each step.";                                 
    public String getRartist(){
    	return("Jan Aminoff 2001");}  // Name of Rartist.
    	
    // end of Section 1
    
	// Section 2    What the universe does
	// -----------------------------------------------------------------------
	
	private static int nn_max=xm/2; // Max half of screen covred with lines
		
	// The endpoints of the lines are saved in the following two arrays
	private Point p1s[] = new Point[nn_max];
	private Point p2s[] = new Point[nn_max];
	// The EndPoints are the ones moving generating new lines as they move
	private EndPoint p1;  // first EndPoint
	private EndPoint p2;  // second EndPoint
  
	private int m;		// current index to point array
	private boolean color;
	private boolean resetScreen=false;  // Flag to reset the screen as needed.
	
	private DebugME dB;   // Here if needed. See init.
	
	public void init(){
	     
	   // Following establishes a pattern for setting and use of Debug.

	   /*
		 * Set debuglevel to 2 or higher for tracing output.
		 * You can set it here for this class only or for all rartme
		 * classes in the JAD file (Usually RartME.jad) from where it
		 * is available in Universe as protected int dblevel;
		 */
		int dblvl = 0;		// Set dblevel here for this universe
		dblevel = Math.max(dblvl,dblevel);
		dB= new DebugME(true);
		dB.setLevel(dblevel);
		dB.dbg(1,"LinesME.init, dblevel "+dblevel);
		dB.dbg(3, "LinesME.init, nn_max "+nn_max); 
		color = (numColor>0);
		setParams();
		reset();
	}
	
	/**
	 * reset is used in init and also in manageChange when uParameters speed
	 * (with index VIEWSIZE) and number (with index NUMBER) have changed.
	 */
	private void reset(){
		vv = speed.getCur();	// current maximum speed
		nn = number.getCur();	// current number of lines
		// xm and ym are available from universe
		p1 = new EndPoint(xm,ym,vv); // first EndPoint 
		p2 = new EndPoint(xm,ym,vv); // second EndPoint
		m=0;		// index to current pair of endpoints
		// reset the arrays of points
		for (int i = 0; i<nn; i++){
			p1s[i]=new Point(0,0);
			p2s[i]=new Point(0,0);
		}
		// The following deals with the ability to select color 
		cc=colorcomb.getCur();
		dB.dbg(3,"LinesME.reset, line 106, cc, color " +
				cc+", "+((cc>1)? ColorME.colornames[cc-2]:((cc>0)? 
				"wh on bl":"bl on Wh")));
		if (cc==0) {
		    colorlines = false;
		    lineColor = ColorME.BLACK;
		    background = ColorME.WHITE;
		}else if (cc==1){
		    colorlines = false;
		    lineColor = ColorME.WHITE;
		    background = ColorME.BLACK;
		}else{
		    colorlines = true;
		    background = ColorME.colorvalues[cc-2];
		}
		resetScreen=true;
	}	//end of reset
	
	public void cycle (Graphics g){
	    if (resetScreen){
		     //g.setPaintMode();
		    g.setColor(background);		     
			 g.fillRect(0,0,xm,ym);
			 resetScreen = false;
		}
		// Save p1 and p2 as points in point arrays
		p1s[m]=new Point(p1);
		p2s[m]=new Point(p2);
		//Update position of the two end points
		p1.move();
		p2.move();
		// Step index to point arrays
		m= (m+1) % nn;
		// If we have been there, disappear the former line
		if ((p1s[m].x!=0)&& (p1s[m].y!=0)){
			g.setColor(background);
			g.drawLine(p1s[m].x, p1s[m].y, p2s[m].x, p2s[m].y);
		}
		if (colorlines) {
		    // Step line color
		    hue++;
		    lineColor = ColorME.mkColorfromHue(hue);
		    hue = hue % 359;	// keep going around the color wheel.
		}
		// Draw Line in color p1 to p
		g.setColor(lineColor);
		g.drawLine(p1.x, p1.y, p2.x, p2.y);
	}	// end of cycle		
	
	// Color stuff
	/* In the enhancement introduced as Ex5b there are three variations of
	 * the Lines universe: Black lines on white, white lines on black, and 
	 * lineColor stepped through 360 colors on a selectable background.
	 * The third version is distingushed by the boolean colorlines being true.
	 * The first two versions are distinguised by colorlines being false and 
	 * the boolean blackonwhite being either true or false.
	 *
	 * Default is colorlines being true.
	 */
	private int cc=2;   //Default choice of linecolor varying on white
	private boolean colorlines=true;
	private boolean blackonwhite;
	private int background = ColorME.BLACK; //Reset in reset
	private int lineColor = ColorME.WHITE;    //
	private int hue = 270;
	
	public void manageChange(uParameter uP){
		int idx=uP.getIndex();
		//dB.dbg( 2,"Lines.mC, Change in : "+uP.getName());
		if (uPs[idx]!=null) uPs[idx]=uP; //ensures that uPs, the list of current parameters is up to date			
		switch (idx){
			case NUMBER:
				number=uP;
				reset();
				break;
			case PARA4:	 //used for speed or actually density
				// do not need to reset here but need to reset max speed in 
				// the two EndPoints
				speed=uP;
				vv=speed.getCur();
				p1.setMaxSpeed(vv);
				p2.setMaxSpeed(vv);
				break;
			case PARA5: // for new colorcombinations
			    colorcomb=uP;
			    reset();
			    break;
			}
			
		}   // end manageChange
	// end of Section 2		   
      
	// Section 3   uParameters as used in the universe
    // -----------------------------------------------------------------------
    
   private uParameter number;	//Number of lines requested - PARAMETER
	private int nn_min=1,nn_cur=nn_max/2;	// nn_max is a static variable	
	private int nn=nn_cur;						//actual number of lines
	private String ndescr=	
			"Number of 'Lines' on the "+
			"screen at any one time.";
			
	// max speed of any EndPoint in x or y direction - PARAMETER
	private uParameter speed; 
	private int vv=4,vv_max=8,vv_min=1;	  
	private String sdescr= 
			"The 'Speed' is the maximum speed in pixels.";
	
	// colorcombinations of linecolor on background color - PARAMETER
	// The following is new for Ex5b:
	private uParameter colorcomb;
	private String ccdescr1 =
       "Select black lines on white background or white lines on black";
	private String ccdescr2 = 
       " or lines whose color is stepped through 360 shades of color against"+
       " a background selected from thirteen primary Java colors.";   
   static String colornames1[]={ " Black on White", " White on Black"};
	static String colornames2[]= { " Black on White", " White on Black",
       " Black", " Blue", " Cyan",
       " Dark grey", " Grey",
       " Green", " Light grey", " Magenta",
       " Orange", " Pink", " Red",
       " White", " Yellow"};
	
	// cycletime is set here but otherwise handled in the rartrunners
	public uParameter cycletime;

    private void setParams(){
        number= new uParameter 
        		(NUMBER,"Number of Lines",nn_min,nn_cur,nn_max,ndescr);
        // The adduParameter() method is defined in Universe
        adduParameter(number);     
        speed=new uParameter(PARA4,"Speed",vv_min,vv, vv_max, sdescr);
        adduParameter(speed);
        String ccd = ccdescr1;
		  ccd +=(color)? ccdescr2:".";
        colorcomb = new uParameter
                (PARA5,"Color Combination",cc,
					 (color)? colornames2:colornames1, ccd);
        adduParameter(colorcomb);
        // Since "Cycle Time" is a compulsory parameter, Universe actually
        // provides the  description 
        cycletime= new uParameter(CYCLETIME,"Cycle Time", 10,25,100, CycleTimeDescr);   
        adduParameter(cycletime); 
   } // end of params

	// Security related constructor
   public LinesME() throws InstantiationException {}
}	// End of class Lines

EndPoint Class

/*
 * 
 * EndPoint    1.0  010915 
 * 
 * © A-Square, Inc.   
 * 1648 Waters Edge Lane, Reston Virginia, 20190, USA  
 */

package rartme.univ;
import rartme.*;
/**	 
 * Class: EndPoint, the EndPoint moves in steps of fixed increments (or  
 * speed)across the screen until it hits a border when it is redirected in 
 * a new direction with a new speed.
 *
 * Released as a component of the LinesME sample universe, September 2001
 */
public class EndPoint extends Point {
    public static int BORDERWIDTH=2; // EndPoints bounce when coming within 
				// BORDERWIDTH pixels of any edge of the screen
	private int bw=BORDERWIDTH;		// just to save typing
	private int dx;		    // current velocity in x dir
	private int dy;		    // current velocity in y dir
	private int xm; 		// width of window set in constructor
	private int ym;			// height of window set in constructor
	private int vv;			// maximum speed of point set in constructor
	
	
	/**
	 * Constructor
	 * The initial poition of an endpoint is within the rectangle described by
	 * (bw, bw, x_max-2*bw, y_max-2*bw) where bw is the BORDERWIDTH.
	 *
	 * @x_max	the width of the window in pixels
	 * @y_max	the height of the window in pixels
	 * @v_max	the maximum stepping speed of the EndPoint
	 */
	EndPoint(int x_max, int y_max, int v_max) {
		xm=x_max;
		ym=y_max;
		vv=v_max;
		setMaxSpeed(vv);
		x = bw+RND(x_max-2*bw);
		y = bw+RND(y_max-2*bw);
		dx = setSpeed(vv);
		dy = setSpeed(vv);
	}   // end EndPoint constructor
	
	/**
	 * sets the maximum speed in x and y direction
	 * 
	 * @v	speed, greater than 0 and smaller than 50
	 */
	public void setMaxSpeed(int v){
		v= (v<1)? 1: (v>50)? 50: v;
		vv=v;
	}   // end setMaxSpeed
	
	/**
	 * The move method encapsulates the behaviour where a point is stepped in
	 * discrete increments (dx and dy) until it hits an edge when its 
	 * direction is reversed and the speed paralell to the edge given a new
	 * random value, effectively bouncing the point at random.
	 *
	 */
	public void move(){
		x += dx;							//Step x
		y += dy;							//Step y
		// Check to see if the point hit the edge in x-direction
		if (x < bw || x > (xm - bw)){		 
			dx = (x<bw)? ABS(dx):-ABS(dx);  // always moving toward center
			x += 2*dx;						// double back
			dy = setSpeed(vv);				// change speed in y-direction
		}
		// Check to see if the point hit the edge in y-direction
		if (y < bw || y > (ym - bw)){		
			dy = (y<bw)? ABS(dy):-ABS(dy);  // always moving toward center
			y += 2*dy;						// double back
			dx = setSpeed(vv);				// change speed in x-direction
		}
	}	// end move
	
	// Following two methods taken from Universe
	private static int RND(int x){
		 return(UniverseME.RND(x));
	}
	private static int ABS(int x){
		 return(UniverseME.ABS(x));
	}
	
	private int setSpeed(int v){
		int v1;
		do{					
			// The following ensures speed distributed randomly in the
			// interval [-v , v] endpoints included and 0 excluded.
			v1=(RND(3)-1)*(1+RND(v));
		}while (v1==0);   // speed never 0!
		return v1;
	} // end of setSpeed
	
}	// End of class EndPoint