Search code examples
javascriptsimulationp5.jsrandom-walk

struggling to create a smooth-moving snake in p5 js - tail catching up to head


I'm putting together a p5 sketch with little wiggling snakes that move randomly across the screen.

Unfortunately, the tail keeps catching up to the head every time it does a sharpish turn.

Here is the function I'm using to calculate the move, I've tried with a few different ways of calculating the speed, fixed numbers, relative to the snake's length.

It's supposed to work by moving the snakes head (points[3]) in a semi-random direction and then having each body point move towards the one before it by the same amount. This isn't working, and I feel there's something wrong with my algorithm itself. I'm not familiar with these kinds of intermediate random-walks, so I've just been going by guesswork for the most part.

this["moveCurve"] = function() {
    let newDir = this["oldDir"] + (random() - 1/2)*PI/6; 
    let velocity =  createVector(1,0); 
    velocity.setMag(5); 
    velocity.setHeading(newDir); 
    this["points"][3].add(velocity); 
    for (let i = 2; i >= 0; i--) { 
        this["points"][i].add(p5.Vector.sub(this["points"][i + 1],this["points"][i]).setMag(5)); 
    } 
    this["oldDir"] = newDir; 
}

If you have any idea what I could do to make this work properly, I'd love to hear your advice. Thanks!


Solution

  • Fortunately, it turns out p5's documentation itself had the answer for me. By adapting the code from here to use p5 Vectors, I was able to get it all working.

    The segLengths property is defined when the object is made, just takes the distances between all the points.

    this["moveCurve"] = function() {
        let newDir = this["oldDir"] + (random() - 1/2)*PI/6;
        let velocity = p5.Vector.fromAngle(newDir).setMag(5);
        this["points"][3].add(velocity);
        for (let i = 2; i >= 0; i--) {
          this["points"][i].set(p5.Vector.sub(this["points"][i+1], p5.Vector.fromAngle(p5.Vector.sub(this["points"][i+1],this["points"][i]).heading()).setMag(this["segLengths"][i])));
        }
        this["oldDir"] = newDir;
      }
    

    I might spend a little time trying to clean up the code a bit, it's a jot messy for my tastes at the moment. But it works.