Uploaded to www.rart.com/j2me-presentation/html_Source/ March 19, 2002
This is an example of a Rart universe ported to the J2ME environment.
The FlakesME universe requires the rP60ME class which provides math support.
This version has been tested with j2mewtk 1.0.2 and 1.0.3
/*
* @FlakesME 1.0 010905
*
* © A-Square, Inc.
* 1648 Waters Edge Lane, Reston Virginia, 20190, USA
*/
package rartme.univ;
import javax.microedition.lcdui.*;
import java.util.Stack;
import java.lang.Math;
import rartme.*;
/**
* Flakes universe
*
* Source: FlakesME.java
* Description: In the Flakes universe branches grow from the center in an
* approximation of the growth of a hexagonal crystals, as formed by for
* example a snow flake.
*
* The actual drawing of the branches is performed by the class rP60ME,
* which emulates the geometry including the shaded drawing of branches up
* to 5 pixels wide.
*
* author Jan Aminoff/ © A-Square 1998-2001
*
* This version is adapted to J2ME and the second real universe to be
* programmed in the ME environment. Compared to the regular Flakes universe,
* FlakesME shows the growth of a single flake centered on the small screen.
* Released with RartME as the FlakesME sample universe, September 2001
*
* Proud Author: Jan Aminoff
*/
public final class FlakesME extends UniverseME {
// Section 1 Identifying the Universe
// -----------------------------------------------------------------------
public String getName(){return("FlakesME");} // Name of the universe.
public String getDescription(){return(sd);} // Describing the universe.
private String sd=
" In the FLAKES Universe branches grow and "+
"branch always at 30 or 60 degree angle and in circular "+
"symmetry, approximating the growth of a snow flake.";
public String getRartist(){ // Name of Rartist.
return(" Jan Aminoff 2001");}
// end of Section 1
// Section 2 What the universe does
// -----------------------------------------------------------------------
// This universe is more complicated than others and so the documentation
// for Section 2 has been subdivided in subsections as follows
// Subsection 2a Initiation
// With methods init, reset, and newFlake
// Subsection 2b Operation
// With methods cycle, drawFlake, and eraseFlake (Erases a flake)
// Subsection 2c Changing
// with method manageChange
// Subsection 2a Initiation
// With methods getBackground, init, reset, and newFlake and with
// declarations of static variables as well as variables associated with the flake.
// Static Variables
// The arms of a flake can branch with 5, 2 or one branch. The selection
// is made from the following table indexed with a random index.
private static int branches[]={5,5,2,2,2,2,1,1,1,1};
// The thickness of a branch is selected from the following table where
// the first index is proportional to distance from center and second
// index is random. The effect is that branches near the center are more
// likely to be thicker.
private static int thickness [][]= {
{5,5,5,5,5,5,5,3,3,1},
{5,5,5,3,3,3,3,3,1,1},
{5,3,3,3,3,3,1,1,1,1},
{3,3,3,3,1,1,1,1,1,1},
{3,3,1,1,1,1,1,1,1,1}
};
// The sixe of the enclosing circle is selected as a percentage of
// 120 percent of the minimum screen dimension using this table.
// See newFlake.
private static int size[] = {
10,20,30,40,45,50,55,60,60,65,
65,70,70,70,75,75,80,80,85,90};
// Fundamental private variables
private int R; // radius of enclosing circle
private int X = xm/2; // x-coordinate of center
private int Y = ym/2; // y-coordinate of center
private int lvl; // level of brancing
private int lmax; // maximum level of branching
private int rMin1; // current minimum distance from points to circle
private boolean done;
private Stack stackA;
private Stack stackB;
private int r,rMin, d, dr, w;
private rP60ME p0,p1,p2;
private DebugME dB; // In case needed. See init
private boolean resetScreen = false;
// Prescribed by UniverseME
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,"FlakesME.init, dblevel "+dblevel);
setParams(); // See Section 3 about uParameters
reset();
newFlake(); // Initiate first flake
} // end init
// reset, used in init only in this universe
private void reset(){
resetScreen = true;
} // end reset
/**
* Initiates a flake based on the size of the available screen
* with width xm and height ym. Most flakes should be big, but
* some small for variety.
* Selection is done in two steps for a maximum of 100. First
* select with equal probability any entry in the array size and
* add randomly 0-9.
*/
private void newFlake(){
int rmax = Math.min(xm,ym)/2;
int percent = (size[RND(20)]+RND(11))*120/100;
int r = percent*rmax/100; //radius
R=r;
X=xm/2;
Y=ym/2;
lvl=0; // the number of stacklevels
stackA=new Stack(); // one stack per flake
stackB=new Stack();
com=complexity.getCur();
// lmax gives number of branches or levels, function of the
// uParameter complexity.
lmax=1 + RND(com-1); //At least one branching
dB.dbg(3, "FlakesME.newFlake, line 156 com, lmax "+com+", "+lmax);
//rMin1 is distance to circles edge at previous level
rMin1=r;
Point P = new Point(X,Y);
p0=new rP60ME(P);
// establishes center of flake in the rPoint system
p0.dir = RND(2); //0 or 30 degree angle initially
//Work from branching points from previous level in StackA
stackA.push(p0); //Start at center with one point in StackA
done =false;
//Now ready to go into branc drawing mode
} // end newFlake
// Subsection 2b Operation
// With methods cycle, drawNextLevel, drawBranch, eraseFlake
// and static methods for SQUARE and rMin
// cycle, prescribed by UniverseME
public void cycle(Graphics g){
if (resetScreen){
clearScreen(g);
resetScreen=false;
}
// In this universe we deal with only one flake
if (!done) drawNextLevel(g) ;
lvl++;
if (lvl > lmax){
clearScreen(g); //eliminates the flake and
newFlake(); //initiates a new one
}
} // end cycle
private void clearScreen(Graphics g){
g.setColor(0); // Black background
g.fillRect(0, 0, xm, ym);
}
//Draws next level of the flake
void drawNextLevel(Graphics gc){
int r=R;
rMin=r; // rMin measures distance to circles edge during calculation
int level=lvl;
// Cycle until level reaches lmax or distance to edge 2 or less
if(!done){
level++;
// number of branches, 1, 2, or 5, see branches
int nb=(level==1)?1:branches[RND(10)];
// thickness of branch, see thickness
w=(level < 5)?thickness[level][RND(10)]:1;
dB.dbg(3, "FlakesME.drawNextLevel r, lmax "+r+", "+lmax);
int ddr = 2*r/lmax;
dr=1+RND(ddr); // length of branch, see ddr
dr=Math.min(dr,rMin1); //not further than circles edge
// Store next level of branching points in StackB
// work from A until empty
while (!stackA.empty()){
p1=(rP60ME)stackA.pop(); //next branch point
switch (nb) { //nb number of branches
//Each branch point comes with an inherent direction dir.
case 1: //one branch
drawBranch(r,0,gc); //straight ahead
break;
case 2: // two branches
drawBranch(r,-1,gc); //+ and - 30 degreas
drawBranch(r,1,gc);
break;
case 3: //only in error at this time
break;
case 4: //only in error at this time
break;
case 5: //five branches //60 degrees all around
drawBranch(r,-4,gc);
drawBranch(r,-2,gc);
drawBranch(r,0,gc);
drawBranch(r,2,gc);
drawBranch(r,4,gc);
break;
} //switch nb
} //stack A empty, done with present level
if((level > lmax)||(rMin<3)){ // finished?
done = true;
lmax = 4*level;
stackB = null;
stackA = null;
} else { //move points from B to A until B is empty
while (!stackB.empty()) stackA.push(stackB.pop());
rMin1=rMin; //saves the value of rMin
}
// go to next level
} // end while
} // drawNextLevel
/**
* extends a branch distance r in the direction di
* the method also draws the line as well as the lines rotated around
* the circle. In the process a new endpoint is created and pushed onto
* stackB for use in the drawing of next again level.
*/
private void drawBranch(int r, int di, Graphics gc){
int di1=(p1.dir+di)%12; //dir must be >=0 and <12 around the circle
// Calculate new endpoint at p2 and draw the line from p1 to p2
p2=p0.extendBranch60(p1,di1, dr,gc,w);
// Draw the new line rotated in 60 degree increments around the circle
p0.rotateLine60(p1,p2,gc,w);
//Save the new endpoint in stackB
stackB.push(p2);
rMin=rMin(rMin,r,p2); // keep ruuning track of remaining distance
} // end drawBranch
/**
* checks distance to the edge of the sector bounded by x=0, a 60 degree
* radius and radius r from the center p with relative coordinates x,y.
* is used to determine minimum distance from any new branch end point to
* the edge of circle.
* Uses SQRT as defined in rP60ME
*/
private static int rMin(int rMIN, int r, rP60ME p){
int rd=(r-rP60ME.SQRT(SQUARE(p.x)+SQUARE(p.y)));
return Math.min( rMIN,rd);
} // end rMin
static int SQUARE(int x){
return x*x;
}
// Subsection 2c Changing
// with method manageChange
// manageChange prescribed by UniverseME
public void manageChange(uParameter uP){
int idx=uP.getIndex();
dB.dbg( 3, "FlakesME.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 CYCLETIME:
ct=uP;
break;
case PARA4:
complexity=uP;
break;
}
} // end manageChange
// end of Section 2
// Section 3 uParameters as used in the universe
// -----------------------------------------------------------------------
private uParameter number; //Number of Flakes requested - PARAMETER
private uParameter complexity; //A measure of complexity - PARAMETER
private int com=4,com_max=10,com_min=2;
private String cdescr=
"The parameter determines the maximum number of brancings. "+
"The actual number is less and random.";
private uParameter ct;
private void setParams(){
complexity=new uParameter
(PARA4,"Complexity",1,com, com_max, cdescr);
adduParameter(complexity);
// Universe provides the description for uParameter with index CYCLETIME
ct= new uParameter
(CYCLETIME,"Cycle Time", 40,100,1000, CycleTimeDescr);
adduParameter(ct);
} // end setParam
// Security related constructor
public FlakesME() throws InstantiationException {}
} // End of FlakesME universe