/* built with Studio Sketchpad: * http://sketchpad.cc * * observe the evolution of this sketch: * http://studio.sketchpad.cc/sp/pad/view/ro.$$I5vrwRmQ1/rev.12 * * authors: * GoToLoop * license (unless otherwise specified): * creative commons attribution-share alike 3.0 license. * http://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(); } }