Can't seem to fade out individual particle

edited September 2014 in Questions about Code

Hello!

I'm going to try to get the gist of my problem across without having to paste a novel. I'm using 2 classes, one called Emitter and one called Particle. Each Emitter emits Particles, instantiating a new Particle and appending it to a Particle ArrayList every n number of frames. Each draw() cycle, the Emitters iterate through all of the Particles and call their .update() and .display() functions.

Everything was working as expected until I tried to make the individual Particles fade out over time. Here are the display and update methods from the Particle class;

  void display() {
    pushMatrix();
    strokeWeight(strokeWeight);
    translate(position.x, position.y);
    stroke(colorVals[0], colorVals[1], colorVals[2], colorVals[3]);
    point(0, 0);
    popMatrix();
    t++;
  }

  void update() {

    colorVals[3] -= 5;
    position.add(velocity);
    if(friction > 0) {
      position.mult(friction);
    }

  }

Unfortunately, when I try to use this in conjunction with an Emitter, I can't get individual Particles to fade out after they've been emitted. Instead, the Emitter just emits particles with a lower and lower alpha value until none of the Particles being emitted are visible. Here's the Emitter.display method that loops through the Emitter's List Array:

void display() {

    if(particles.size() > 0) {

      for(i = 0; i < particles.size() - 1; i++) {

        Particle particle = particles.get(i);

        if(particle.position.x > (width / 2) || particle.position.x < (width / -2)) {
          particles.remove(i);
        }

        if(particle.position.y > (height / 2) || particle.position.y < (height / -2)) {
          particles.remove(i);
        }
        pushMatrix();
        translate(position.x, position.y);
        particle.update();
        particle.oscillate();
        particle.draw();
        popMatrix();
      }

   }

}

Can anyone help me achieve the desired result of each Particle fading out at its own rate after it is emitted? If more code is needed to track down the problem, I'd be happy to provide more. Just didn't want to paste too much code. Thanks in advance!

Answers

  • edited September 2014 Answer ✓

    Instead, the Emitter just emits particles with a lower and lower alpha value until none of the Particles being emitted are visible.

    Doesn't a Particle have an initial value for colorVals[3] when it's instantiated?
    Or don't you tell me that colorVals is a "global" sketch's field rather than Particle's! @-)

  • edited September 2014

    Doesn't a Particle have an initial value for colorVals[3] when it's instantiated? Or don't you tell me that colorVals is a "global" sketch's field rather than Particle's!

    It does have an initial value set for colorVals[3], and I'm making change to a member variable of Particle called colorVals. So yes they do and no there isn't a global sketch field called colorVals. These code snippets are part of classes. I didn't post all of the code for each class, but I mentioned it in the post. Let me know if you need me to post the whole class.

  • Well, colorVals[3] is the alpha value. The way you put it makes me believe that Emitter ends up instantiating Particle objects w/ colorVals[3] already 0 or less after some time! It doesn't make any sense for me, sorry!

    Anyways, as extra reference, here's an online example which got an "oversëer" class which instantiates 3 subordinates. Very similar to yours I guess:
    http://studio.processingtogether.com/sp/pad/export/ro.9lTJ6qSlmCidk/latest

  • Hmm, I think that is what is happening. I'll investigate further. I think I accidentally accepted these answers, is there a way to undo that since the question is still open? Thanks!

  • edited September 2014 Answer ✓

    After some looks at Emitter's display() method, inside the for loop...
    I've spotted a classic bug: we can't use remove() for a List, unless it's backwards!
    Take a look at my WaveTrio's script() method. It shows the simplest backwards loop technique for List remove()!

    boolean script() {
      for (int i = waves.size(); i-- != 0;)
        if (waves.get(i).script())  waves.remove(i);
    
      return waves.size() == 0;
    }
    

    While at sketch's draw()'s own loop, a more efficient technique is used! \m/

    for (int len = trios.size(), i = len; i-- != 0;)
      if (trios.get(i).script()) {
        trios.set(i, trios.get(--len));
        trios.remove(len);
      }
    

    P.S.: Even us moderators can't undo it, sorry! :-&

  • After some looks at Emitter's display() method, inside the for loop... I've spotted a classic bug: we can't use remove() for a List, unless it's backwards! Take a look at my WaveTrio's script() method. It shows an advanced technique for List remove()!

    boolean script() {
      for (int i = waves.size(); i-- != 0;)
        if (waves.get(i).script())  waves.remove(i);
    
      return waves.size() == 0;
    }
    

    Thanks GoToLoop! I tried doing it this way, but got a syntax error due to the for loop syntax. I understand the loop, as I've used something similar in other languages, but I am not very familiar with Java. Anyway, I was able to change the loop slightly and get it working using your technique. Much appreciated! Can you explain what is going on that requires this? Thanks again!

    The updated code:

    if(particles.size() > 0) {
    
      for(i = particles.size() - 1; i != 0; i--) {
    
        Particle particle = particles.get(i);
    
        if(particle.position.x > (width / 2) || particle.position.x < (width / -2)) {
          particles.remove(i);
        }
    
        if(particle.position.y > (height / 2) || particle.position.y < (height / -2)) {
          particles.remove(i);
        }
        pushMatrix();
        translate(position.x, position.y);
        particle.update();
        particle.oscillate();
        particle.draw();
        popMatrix();
      }
    
    }
    
  • edited September 2014 Answer ✓

    Can you explain what is going on that requires this?

    That is not restricted to Java. It's how an ordered List is internally organized!
    When a remove() is issued, all indices to its right is left-shifted.
    All of a sudden, the next index becomes the current index!
    So at the next loop index iteration, it ends up skipping that 1!

    A backwards loop fully avoids that problem, b/c indices before the index being removed don't incur any shifting!
    Actually, we can use regular forward loops too, as long as we decrease the iterator after the remove()! :P

    I tried doing it this way, but got a syntax error due to the for loop syntax.

    Can you please try this 1 out and see whether it still works for ya? ;;)

    // forum.processing.org/two/discussion/7090/
    // cant-seem-to-fade-out-individual-particle
    
    int cx = width>>1, cy = height>>1;
    int len = particles.size(), i = len;
    
    while (i-- != 0) {
      Particle p = particles.get(i);
      PVector  v = p.position;
    
      if (v.x>cx | v.x<-cx | v.y>cy | v.y<-cy) {
        particles.set(i, particles.get(--len));
        particles.remove(len);
        continue;
      }
    
      translate(v.x, v.y);
      p.update();
      p.oscillate();
      p.draw();
      resetMatrix();
    }
    

    And I believe this version would be a lil' faster too:

    void display() {
      stroke(colorVals[0], colorVals[1], colorVals[2], colorVals[3]);
      point(position.x, position.y);
      ++t;
    }
    
  • GoToLoop! Thank you! I realized the problem with my syntax was leaving out the second semicolon in the for loop! Now I have your original code working. Also, thank you for the optimization and explanation! Problem solved, thanks so much!

Sign In or Register to comment.