title: Creating water with p5.js
body: <p>I'm trying to create some water effects in p5.js with waves and everything, but I can't seem to get the waves in the water to work. I am creating the waves off of <a href="https://gamedevelopment.tutsplus.com/tutorials/make-a-splash-with-dynamic-2d-water-effects--gamedev-236" rel="nofollow noreferrer">this</a> article by Michael Hoffman. I created two classes for the water, one class called "Springs," which simulates the spring effect of the water, and one class called "Liquid", which just hold a list of springs and some constants. </p>
  
  <p>To display the water, I used p5's beginShape() and vertex() functions to create the surface of the water. I went through and created a vertex of the height of each spring. </p>
  
  <p>The water right now is staying static. I want the water to create a wave only when a ball hits the surface of the water. I have set the Liquid's "contains" method to true to just to see if the waves are working.</p>
  
  <p>I want to know if there is a problem with the way I am drawing the water. Previously, there would be a spring-like effect when I clicked, except the entire surface of the water would remain a rectangle. Is there something wrong with using vectors to create waves in the water? It seemed like a simpler solution to creating the waves than drawing trapezoids like Hoffman suggests, but it turns out I can draw trapezoids easily with p5.js.</p>
  
  <p>Thanks for the help.</p>
  
  <p>Here is the code:</p>
  
  <pre><code>var balls = [];
  
  var liquid; 
  
  function Liquid(s) {
      this.springs = s;
      this.tension = 0.025;
      this.dampening = 0.025;
      this.spread = 0.25;
  }
  
  function Spring() {
      this.targetHeight = 0;
      this.height = 0;
      this.vel = 0;
  
      this.update = function(dampening, tension) {
          let x = this.targetHeight - this.height;
          this.vel += (tension * x - this.vel * dampening);
          this.height += this.vel;
      }
  }
  
  Liquid.prototype.update = function () {
  
      for (var i = 0; i &lt; this.springs.length; i++)
          this.springs[i].update(this.dampening, this.tension);
  
      var lDeltas = [];
      var rDeltas = [];
  
      // do some passes where columns pull on their neighbours
      for (var j = 0; j &lt; 8; j++)
      {
          for (var i = 0; i &lt; this.springs.length; i++)
          {
              if (i &gt; 0)
              {
                  lDeltas[i] = this.spread * (this.springs[i].height - this.springs[i - 1].height);
                  this.springs[i - 1].vel += lDeltas[i];
              }
              if (i &lt; this.springs.length - 1)
              {
                  rDeltas[i] = this.spread * (this.springs[i].height - this.springs[i + 1].height);
                  this.springs[i + 1].vel += rDeltas[i];
              }
          }
  
          for (var i = 0; i &lt; this.springs.length; i++)
          {
              if (i &gt; 0)
                  this.springs[i - 1].height += lDeltas[i];
              if (i &lt; this.springs.length - 1)
                  this.springs[i + 1].height += rDeltas[i];
          }
      }
  }
  
  Liquid.prototype.splash = function (index, speed) {
      if (index &gt;= 0 &amp;&amp; index &lt; this.springs.length)
          this.springs[i].vel = speed;
  }
  
  Liquid.prototype.display = function () {
      fill(0, 0, 255);
      beginShape();
      vertex(0, height - this.springs[0].height);
      for (var i = 0; i &lt; this.springs.length; i++) {
          vertex(i * (width / this.springs.length), height-this.springs[i].height); //consider using the map function
      }
      vertex(width, height);
      vertex(0, height);
      endShape(CLOSE);
  }
  
  Liquid.prototype.contains = function(m) {
      return true;
  };
  
  function Mover(m, x, y) {
      this.mass = m;
      this.position = createVector(x,y);
      this.velocity = createVector(0,0);
      this.acceleration = createVector(0,0);
  }
  
  // f = m / a --&gt; a = f / m
  
  Mover.prototype.applyForce = function(force) {
      var f = p5.Vector.div(force,this.mass);
      this.acceleration.add(f);
  }
  
  Mover.prototype.update = function() {
      this.velocity.add(this.acceleration);
      this.position.add(this.velocity);
      this.acceleration.mult(0); //acceleration must be cleared; does not add to itself!
  };
  
  Mover.prototype.display = function() {
      stroke(0); //black outline
      strokeWeight(2); //make it more visible
      fill(255,127); //give it a gray color
      ellipse(this.position.x,this.position.y,this.mass*16,this.mass*16); //create an ellipse at the position
  };
  
  function setup() {
      createCanvas(windowWidth, windowHeight);
      background(255);
      var temp = [];
      for (var i = 0; i &lt; 340; i++) { //340 is an arbitrary num
          var tempSpring = new this.Spring();
          tempSpring.targetHeight = height/2;
          tempSpring.height = height/2;
          temp[i] = tempSpring;
      }
      liquid = new Liquid(temp);
      liquid.display();
  }
  
  function draw() {
      background(255);
      for (var i = 0; i &lt; balls.length; i++) {
  
          if(liquid.contains(balls[i])) {
              liquid.splash(balls[i].x, 0.05);
          }
          liquid.update();
          liquid.display();
          // Gravity is scaled by mass here!
          var gravity = createVector(0, 0.1*balls[i].mass);
          // Apply gravity
          balls[i].applyForce(gravity);
          balls[i].update();
          balls[i].display();
  
  
      }
      liquid.display();
  }
  
  function mousePressed() {
      balls[balls.length] = new Mover(5, mouseX, mouseY);
  }
  </code></pre>