/* built with Studio Sketchpad:
* https://sketchpad.cc
*
* observe the evolution of this sketch:
* https://studio.sketchpad.cc/sp/pad/view/ro.$$I5vrwRmQ1/rev.12
*
* authors:
* GoToLoop
* license (unless otherwise specified):
* creative commons attribution-share alike 3.0 license.
* https://creativecommons.org/licenses/by-sa/3.0/
*/
/**
* Clickable Spawning Balls (v3.05)
* by drov.fr (2013/Jun)
* mod GoToLoop (2013/Dec)
*
* forum.processing.org/one/topic/nullpointerexeption-with-an-arraylist.html
* forum.processing.org/two/discussion/2171/effect-in-processing
*
* studio.processingtogether.com/sp/pad/export/ro.9oyKfI9kOIa77/latest
*/
import java.util.List; // actually, it is already imported, but not "activated"!
// Constant field variables of the top class, the sketch itself!
// An ArrayList which only stores instances of class Balle, and initial size = 128:
//final static List<Balle> balles = new ArrayList(0200); // Java
final static List<Balle> balles = new ArrayList(); // JS
final static color BG = 0;
final static String ENGINE = JAVA2D; // JAVA2D, P2D, P3D, OPENGL
void setup() {
size(600, 400, ENGINE); // old P2D & P3D don't exist in Processing 2.x.x!
frameRate(60);
ellipseMode(CENTER);
fill(Balle.COLOUR); // directly access a static field w/o instantiate it 1st!
}
void draw() {
background(BG);
// This is called enhanced or for-each or even for-in loop.
// It iterates over all of the elements stored in the ArrayList
// which is referenced by variable balles.
// Since that contains only instances of class Balle
// iterator b is declared as of type Balle to receive an element from it:
for (Balle b: balles) b.script();
// Changes app window top-bar title:
//frame.setTitle( "# Balls: " + balles.size() ); // Java only
}
void mousePressed() {
// If it's NOT a middle-click, add a new instance of Balle:
if (mouseButton != CENTER) balles.add( new Balle() );
// Otherwise, also checks whether it has at least 1 instance stored
// before removing oldest one to avoid an exception:
//else if (balles.size() != 0) balles.remove(0);
// A faster alternative -> removes latest added Balle instead:
else {
final int len = balles.size();
if (len != 0) balles.remove(len - 1);
}
}
final class Balle {
// Fields of inner class Balle (instantiable):
short x, y;
byte spX, spY;
// Static constant fields of inner class Balle (non-instantiable):
final static byte DIM = 20, HALF_DIM = DIM >> 1; // >> 1 is / 2
final static byte MAX_SPD = 5;
final static color COLOUR = #FFFF00; // yellow
Balle() { // constructor of inner class Balle
x = (short) mouseX;
y = (short) mouseY;
// Pick a random speed and pick a direction for it:
spX = (byte) random(1, MAX_SPD + 1);
if (random(1) < .5) spX *= -1;
// Ternary operator ?: which demands 3 operands.
// If random(1) < .5, multiplies by -1, otherwise by 1:
spY = (byte) ( random(1, MAX_SPD + 1) * (random(1) < .5 ? -1:1) );
}
void bump() {
// Adds spX/spY to x/y, then multiplies
// spX/spY by -1 in case x/y is off canvas:
if ( (x += spX) < HALF_DIM | x > width - HALF_DIM ) spX *= -1;
// Alternative way w/ ?: ternary operator:
y += spY *= y < HALF_DIM | y > height - HALF_DIM ? -1:1;
}
void show() {
ellipse(x, y, DIM, DIM);
}
void script() {
bump();
show();
}
}