🔍

Hey, see all those fireflies? ehm stars?

simple starfield simulation combined with spritesheet animation

This sketch refers to a custom creates spritesheet animation system for Processing – check more details here: https://turboflip.de/advanced-animation-with-spritesheets-in-processing/
It combines a simple starfield simulation with a 2D mouse click behaviour and spritesheet animation. all wrapped with object and class logic 🙂


// NOTE!!! this script needs to have a explosion.png spritesheet in the data folder!!!

int how_many_stars = 800;

float displace_amount = 0;

float targetSpeed = 0;
float main_speed = 0;

aSTAR[] allSTARS;

void setup() {

  size(640, 480);
  init_spritesheet();
  imageMode(CENTER);
  noSmooth();

  // create a new list/array of explosion objects
  allSTARS = new aSTAR[how_many_stars];

  // run through the empty list an create a new star object at a random position and random phase
  for (int i=0; i<allSTARS.length; i++) {

    allSTARS[i] = new aSTAR(
      random(-width/2, width/2), 
      random(-height/2, height/2)
      );
  }
}

void draw() {

  displace_amount  = map(mouseY, 0, height, 0, 4);

  targetSpeed = map(mouseX, 0, width, 0, 2);
  // update Speed
  main_speed = lerp(targetSpeed, main_speed, 0.1);

  noStroke();
  fill(0, 44);
  rect(0, 0, width, height);

  translate(width/2, height/2);

  // run through the star list and update each star object 
  for (int i=0; i<allSTARS.length; i++) {

     if(allSTARS[i].do_explode){
       allSTARS[i].explodeMe();
    }else{
      allSTARS[i].updateMe();
    }  
}
}


void mousePressed() {

  // by pressing any mouse button, a random star needs to explode!

  int nid = return_ID_of_the_nearest_star_2D();

   allSTARS[nid].do_explode = true;
}


int return_ID_of_the_nearest_star_2D() {
  float def_dist = 100000;
  int rid = -1;
  float cdist = 0;

  for (int i=0; i<allSTARS.length; i++) {

    cdist = dist( mouseX-width/2, mouseY-height/2,  allSTARS[i].sx, allSTARS[i].sy);

    if (cdist < def_dist) {
      rid = i;
      def_dist = cdist;
    }
  }

  
  return rid;
}


// ---------------------------------------------
// ---------------------------------------------
// ----- SPRITESHEET OPERATIONS ---------------- 
// ---------------------------------------------
// ---------------------------------------------
 
// this spritesheet has only one row of 12 x 96x96px graphics
 
int[] explo_anim = {0,1,2,3,4,5,6,7,8,9,10,11 };
int DIM_X = 12; // horizontal dimension of spritesheet
int DIM_Y = 1; // vertical dimension of spritesheet
  
PImage main_sheet;
PImage[] sprites = new PImage[DIM_X*DIM_Y];
int animtick = 0;


 // ---------------------------------------------
void init_spritesheet() {
 imageMode(CENTER);
  main_sheet = loadImage("explosion.png");
  int W = main_sheet.width/DIM_X;
  int H = main_sheet.height/DIM_Y;
   
  for (int i=0; i<sprites.length; i++) {
    
    int x = i%DIM_X*W;
    int y = 0; // this is a hakc here! needs to be improved!!!
    sprites[i] = main_sheet.get(x, y, W, H);

}
  println("extracted " + sprites.length + "frames with each" + W + "x" + H  + "px from spritesheet");
}

// ---------------------------------------------
  
int animate(float _x, float _y, int _w, int _h, int[] _arr, int _anim_tick, int _anim_speed, boolean _hor_flipped, boolean looped) {
    
  pushMatrix();
    translate(_x, _y);
    if(_hor_flipped){
      scale(1,1);
    }else{
      scale(-1,1);
    }
    image(sprites[_arr[_anim_tick]],0,0 , _w, _h);
   popMatrix();
   
  if (frameCount % _anim_speed == 0) {
    if (_anim_tick<_arr.length-1) {
     _anim_tick++;
    } else {
      
      if( looped ){
       _anim_tick = 0;
      }
    }
  }
  return _anim_tick;
}


class aSTAR {

  // basic var we need for each star object
  float x = 0;
  float y = 0;
  float z = 0;
  float sx=0;
  float sy=0;
  int my_anim_tick = 0;
  float myspeed = .1;
  boolean do_explode = false;

  aSTAR(float _x, float _y) {
    // set an inital position
    x =  _x;
    y=   _y;
    z = random(width/2);
  }


  void resetMe() {

    x = random(-width/2, width/2);
    y = random(-height/2, height/2);
    z = random(width/2);
    do_explode = false;
  }

  void updateMe() {

    z -= myspeed + main_speed;

    x += ( noise(z*.01, y*.01, millis()*.0001  )-.5 ) * displace_amount;
    y += ( noise(x*.01, z*.01, millis()*.0001  )-.5 ) * displace_amount;


    sx = map(x / z, 0, 1, 0, width/2);
    sy = map(y / z, 0, 1, 0, height/2);

    // I use the z value to increase the star size between a range from 0 to 16.
    float r =   map(z, 0, width/2, 10, 0);


    fill(255, 255-1*z);

    noStroke();
    ellipse(sx, sy, r, r);

    if (z<4) {

      resetMe();
    }
  }

  void explodeMe() {


    // update routine for each explosion object
    my_anim_tick = animate(
      sx, 
      sy, 

      int(z*1.2), int(z*1.2), 
      explo_anim, 
      my_anim_tick, 
      5, 
      false, 
      true
      );

    if (my_anim_tick>explo_anim.length-2) {
      resetMe();
    }
  }
}


is this fireflies or stars?

This sketch is a simple redesign of Daniel Shiffmans starfield simulation. It adds up with a displacement that can be contolled by the mouse



int how_many_stars = 800;

float displace_amount = 0;

float targetSpeed = 0;
float main_speed = 0;

aSTAR[] allSTARS;

void setup(){

  size(640,480);
  init_spritesheet();
  imageMode(CENTER);
  noSmooth();
  
  // create a new list/array of explosion objects
  allSTARS = new aSTAR[how_many_stars];
  
  // run through the empty list an create a new star object at a random position and random phase
  for(int i=0;i<allSTARS.length;i++){
  
    allSTARS[i] = new aSTAR(
     random(-width/2, width/2),
     random(-height/2, height/2)
    );
    
  
  }
 
}

void draw(){

  displace_amount  = map(mouseY, 0, height, 0, 4);
  
  targetSpeed = map(mouseX, 0, width, 0, 2);
   // update Speed
  main_speed = lerp(targetSpeed, main_speed, 0.1);
  
  noStroke();
  fill(0,44);
  rect(0,0,width,height);
  
  translate(width/2, height/2);
 
  // run through the star list and update each star object 
     for(int i=0;i<allSTARS.length;i++){
  
       allSTARS[i].updateMe();
  }
   
}
 
class aSTAR{

   // basic var we need for each star object
   float x = 0;
   float y = 0;
   float z = 0;
  // int my_anim_tick = 0;
   float myspeed = .1;
   
   aSTAR(float _x,float _y){
     // set an inital position
      x =  _x;
      y=   _y;
        z = random(width/2);
   
   }
   
      
   void resetMe(){
   
      x = random(-width/2, width/2);
      y = random(-height/2, height/2);
      z = random(width/2);
     
   }
   
   void updateMe(){
   
     z -= myspeed + main_speed;
     
    x += ( noise(z*.01,y*.01, millis()*.0001  )-.5 ) * displace_amount;
    y += ( noise(x*.01,z*.01, millis()*.0001  )-.5 ) * displace_amount;
     
     
      float sx = map(x / z, 0, 1, 0, width/2);
      float sy = map(y / z, 0, 1, 0, height/2);
      
       // I use the z value to increase the star size between a range from 0 to 16.
      float r =   map(z, 0, width/2, 10, 0);
       fill(255,255-1*z);
       noStroke();
       ellipse(sx, sy, r, r);
      
      if(z<4){
       
          resetMe();
      }
     
     /*
     // update routine for each explosion object
     my_anim_tick = animate(
      x,
      y,
      300,300,
      explo_anim,
      my_anim_tick,
      5,
       false,
       true
    );
      */
   }

}