Creating a trail of moving object in Processing Hints Solutions
--D. Thiebaut 17:28, 25 June 2012 (EDT)
This page presents solutions and hints for the tutorial page on creating trails of moving objects in Processing]]
Exercise 1
Here's a possible way to do this, illustrated by the code below. The trickiest part of the code might be this line:
// amount of red in color, varies between 0 and 255 and changes every frame. red = 128 + (int) ( sin( frameCount * 0.05f ) * 127 );
The red integer is set to a value that oscillates between 1 and 255, as the variable frameCount keeps on going up in value. The 0.05f value is a float that makes the changing of red smoother. If we were to use sin( frameCount ) directly, the variation would be too brusk. The Excel table below shows how 127 * sin( frameCount ) compares to 127 * sin( frameCount * 0.05 ): notice how the variation of the second quantity varies in a smoother way.
package tutorial2;
import processing.core.*;
public class Exercise1 extends PApplet {
int red = 0; // amount of red in the circle's color
public void setup() {
// define the window size, make graphics softer, and make
// the background white
size(600, 600);
smooth();
background( 0xeeeeff );
}
public void draw() {
// compute radius of circle, growing and shrinking between 20 and 80 pixels
float radius = 50 + 30 * sin( frameCount * 0.05f );
// amount of red in color, varies between 0 and 255 and changes every frame.
red = 128 + (int) ( sin( frameCount * 0.05f ) * 127 );
// change color of circle paint depending on mouse button
if (mousePressed) {
stroke( red, 255-red, 0 );
fill(0);
}
else {
stroke( 0 );
fill( red, 255-red, 0 );
}
// draw a circle where the mouse is located
ellipse(mouseX, mouseY, radius, radius );
}
}
Exercise 8
This exercise is challenging. My approach is to create a class for the collection of 10 circles, and call it a TrailClass. The TrailClass contains the direction the trail moves in with two ints dirX and dirY. The CircleClass is simplified in the process.
Here's the code below. It maintains only 1 trail. It's easier to figure out what is going on with just one trail. Creating an applet with more than 1 trail is presented in the second listing.
package tutorial2;
import java.util.ArrayList; // needed to
import java.util.Iterator;
import processing.core.*;
/**
* CircleClass: a simple container to hold the location of
* the center of the circle, and the frameCount when it
* appears on the applet, as the frameCount is used to
* define the rate at which the circles "breathes".
*/
class CircleClass {
public int x;
public int y;
public int frameCount;
int dirX;
int dirY;
CircleClass( PApplet p, int xx, int yy, int fc ) {
x = xx;
y = yy;
frameCount = fc;
}
public void draw( PApplet p ) {
float radius1 = 50 + 30 * p.sin( frameCount * 0.05f );
float radius2 = 50 + 30 * p.sin( frameCount * 0.05f );
p.ellipse( x, y, radius1, radius2 );
}
}
/**
* TrailClass: this class is a collection of moving circles. In this example,
* the trail maintains 10 circles or whatever the number in noCircles is.
* The circles do not move. Instead new circles are constantly added at dirX, dirY
* away from the last circle drawn, and the oldest circle is removed, so that noCircles
* remain on the applet.
*
*/
class TrailClass {
ArrayList circles; // the collection of circles
int dirX; // direction of the trail in the X axis
int dirY; // direction of the trail in the Y axis
final int noCircles = 10;
// the number of circles in the trail
TrailClass( PApplet p, int x, int y ) {
// pick a random direction for the trail...
dirX = (int) (5 - p.random( 10 ));
dirY = (int) (3 - p.random( 6 ));
// create a list of circles
circles = new ArrayList();
// add the first circle at (x,y)
circles.add( new CircleClass( p, x, y, p.frameCount ) );
}
public void draw( PApplet p ) {
// get the last circle we added to the tail
CircleClass last = (CircleClass) circles.get( circles.size() - 1 );
// get its center coordinates
int x = last.x;
int y = last.y;
// find the center of the new circles
x += dirX;
y += dirY;
// if that is outside the applet, change the direciton
if ( x < 0 || x > p.width ) dirX = -dirX;
if ( y < 0 || y > p.height) dirY = -dirY;
// add a new circle at the new location
circles.add( new CircleClass( p, x, y, p.frameCount ) );
// if we have more than 10 circles remove oldest one
if ( circles.size() > noCircles )
circles.remove( 0 );
// draw all the circles (we assumed they'll have been erased by the main draw() function
for ( Iterator<CircleClass> it = circles.iterator(); it.hasNext(); ) {
CircleClass c = it.next();
c.draw( p );
}
}
}
/**
* Exercise8: the main Processing applet.
*
*/
public class Exercise8 extends PApplet {
TrailClass trail;
/**
* setup(). Sets the applet up.
*/
public void setup(){
size(800,600); // Size of Background/panel
background( 0xeeeeff ); //Color of Background, Black
frameRate(30); //Frame rate set at 30
// create a trail that starts in the center of the applet...
trail = new TrailClass( this, width/2, height/2 );
}
/**
* draw(): called to draw every frame.
* draws a circle where ever the mouse is.
*/
public void draw() {
// erase the applet
background( 0xeeeeff );
// display the trail
//stroke( 0 ); // black outline
fill( 255 ); // white interior
trail.draw( this );
}
}
Many Trails
package tutorial2;
import java.util.ArrayList; // needed to
import java.util.Iterator;
import processing.core.*;
/**
* CircleClass: a simple container to hold the location of
* the center of the circle, and the frameCount when it
* appears on the applet, as the frameCount is used to
* define the rate at which the circles "breathes".
*/
class CircleClass {
public int x;
public int y;
public int frameCount;
int dirX;
int dirY;
CircleClass( PApplet p, int xx, int yy, int fc ) {
x = xx;
y = yy;
frameCount = fc;
}
public void draw( PApplet p ) {
float radius1 = 50 + 30 * p.sin( frameCount * 0.05f );
float radius2 = 50 + 30 * p.sin( frameCount * 0.05f );
p.ellipse( x, y, radius1, radius2 );
}
}
/**
* TrailClass: this class is a collection of moving circles. In this example,
* the trail maintains 10 circles or whatever the number in noCircles is.
* The circles do not move. Instead new circles are constantly added at dirX, dirY
* away from the last circle drawn, and the oldest circle is removed, so that noCircles
* remain on the applet.
*
*/
class TrailClass {
ArrayList circles; // the collection of circles
int dirX; // direction of the trail in the X axis
int dirY; // direction of the trail in the Y axis
final int noCircles = 10;
// the number of circles in the trail
TrailClass( PApplet p, int x, int y ) {
// pick a random direction for the trail...
dirX = (int) (5 - p.random( 10 ));
dirY = (int) (5 - p.random( 10 ));
// create a list of circles
circles = new ArrayList();
// add the first circle at (x,y)
circles.add( new CircleClass( p, x, y, p.frameCount ) );
}
public void draw( PApplet p ) {
// get the last circle we added to the tail
CircleClass last = (CircleClass) circles.get( circles.size() - 1 );
// get its center coordinates
int x = last.x;
int y = last.y;
// find the center of the new circles
x += dirX;
y += dirY;
// if that is outside the applet, change the direciton
if ( x < 0 || x > p.width ) dirX = -dirX;
if ( y < 0 || y > p.height) dirY = -dirY;
// add a new circle at the new location
circles.add( new CircleClass( p, x, y, p.frameCount ) );
// if we have more than 10 circles remove oldest one
if ( circles.size() > noCircles )
circles.remove( 0 );
// draw all the circles (we assumed they'll have been erased by the main draw() function
for ( Iterator<CircleClass> it = circles.iterator(); it.hasNext(); ) {
CircleClass c = it.next();
c.draw( p );
}
}
}
/**
* Exercise8: the main Processing applet.
*
*/
public class Exercise8 extends PApplet {
ArrayList<TrailClass> trails;
/**
* setup(). Sets the applet up.
*/
public void setup(){
size(800,600); // Size of Background/panel
background( 0xeeeeff ); //Color of Background, Black
frameRate(30); //Frame rate set at 30
// create a trail that starts in the center of the applet...
trails = new ArrayList<TrailClass>();
for ( int i = 0; i < 20; i+= 1 )
trails.add( new TrailClass( this, width/2, height/2 ) );
}
/**
* draw(): called to draw every frame.
* draws a circle where ever the mouse is.
*/
public void draw() {
// erase the applet
background( 0xeeeeff );
// display the trail
//stroke( 0 ); // black outline
fill( 255 ); // white interior
// draw each trail
for ( Iterator<TrailClass> it = trails.iterator(); it.hasNext(); )
it.next().draw( this );
}
}