How can i get a line to move in a curve to a specific region on the canvas?

Hi guys!

I’m a newbie in programming and could really use the help of you experts for my bachelor project.

What I already have is a line that moves in a curve when turning, based on the arrowkeys. This line is only able to turn left, right, speed up and down.
What I would like to have is a line that is attracted -with a curvy movement like now- by a specific region (see image) on the screen (when pressed on keyboard for example).

Could somebody please help me with this? It would mean so much to me!

let branch;

function setup() {
  createCanvas(windowWidth, windowHeight);
  background(0);
  branch = new Branch(width / 2, height / 2);
}

function draw() {
  if (keyIsPressed) {
    if (keyCode == LEFT_ARROW) {
      branch.turn(1);
    } else if (keyCode == RIGHT_ARROW) {
      branch.turn(-1);
    } else if (keyCode == UP_ARROW) {
      branch.changeSpeed(1);
    } else if (keyCode == DOWN_ARROW) {
      branch.changeSpeed(-1);
    }
  }
  branch.update();
}

class Branch {
  constructor(_x, _y) {
    this.x = _x;
    this.y = _y;
    this.px = _x;
    this.py = _y;
    this.s = 0;
    this.a = PI;
    this.d = 0.05;
  }
  update() {
    this.move();
    this.checkEdges();
    this.show();
  }
  move() {
    this.px = this.x;
    this.py = this.y;
    this.x = this.px + sin(this.a) * this.s;
    this.y = this.py + cos(this.a) * this.s;
  }
  checkEdges() {
    if (this.x > width) {
      this.x = 0;
      this.px = this.x;
    } else if (this.x < 0) {
      this.x = width;
      this.px = this.x;
    }
    if (this.y > height) {
      this.y = 0;
      this.py = this.y;
    } else if (this.y < 0) {
      this.y = height;
      this.py = this.y;
    }
  }
  turn(_d) {
    this.a += _d * this.d;
  }
  changeSpeed(_s) {
    this.s = constrain(this.s + (_s * this.d), 0, 3);
  }
  show() {
    stroke(255);
    strokeWeight(3);
    line(this.px, this.py, this.x, this.y);
  }
}

1 Like

Do you want to replace the arrow keys by an automatic function that would steer the ellipse to the points cat, pappa, law and oh etc. one after another (maybe these points in an random order) ?

Thanks for your input! I actually don’t know how to do that. I made it possible to use speech recognition and when these vowels are recognized, I would like the line to move to a specific direction. For the sake of keeping the question more simple it’s a good start to try it with keyboard presses.

Would you know how to help me with this?

1 Like

here is an example (processing, not p5)

  • he’s following the points stored in targets
  • variable easing dictates how tight the curves are
  • activeSteering() is the interesting part
  • maybe it’d look cooler when he’d turn on the screen borders instead of crossing them

Chrisir

// Walker towards targets

Branch branch;

PVector[] targets = new PVector[15];
int indexTarget=0;

//easing for the angle 
float easing = 0.23; //  0.061288;

int timer; 

void setup() {
  size(990, 800);

  background(0);
  branch = new Branch(width / 2, height / 2);

  // fill targets randomly 
  for (int i2=0; i2<targets.length; i2++) { 
    targets[i2] = new PVector (random(width), random(height));
  }

  timer = millis();
}// func 

void draw() {
  // background(0);

  // readKeys(); 

  branch.update();

  // show target
  showTargets(); 

  // after timer is up 
  if (millis()-timer>1000) {
    // active steering
    activeSteering();
  }//if timer
  //
}//func

//-----------------------------------------------------------------------------------------------------

void showTargets() {
  // show current target
  // fill(255, 0, 0);
  // noStroke(); 
  // ellipse (targets[indexTarget].x, targets[indexTarget].y, 17, 17);

  // show ALL targets 
  int i3=0; 
  strokeWeight(1); 
  for (PVector pv : targets) {
    stroke(111);
    // different shades of red 
    fill( map(i3, 0, targets.length, 40, 255), 0, 0);
    // show current target in BLUE
    if (i3==indexTarget) 
      fill(0, 0, 255); //BLUE
    ellipse (pv.x, pv.y, 
      17, 17);
    i3++;
  }
}//func 

void activeSteering() {
  // active steering

  // core idea
  float targetAngle=getAngle();
  //  showLine(targetAngle); // only for debug 

  if (targetAngle>branch.a) 
    branch.turn(1 * easing);
  else if (targetAngle<branch.a) 
    branch.turn(-1 * easing);
  else if (targetAngle==branch.a) {
    // ignore
    // branch.a = 0;
  }

  // when we reach a target we go to next target 
  if (dist(targets[indexTarget].x, targets[indexTarget].y, branch.x, branch.y)<2) {
    indexTarget++;
    // easing+=.103; // change it 
    println("ellipse: "
      +indexTarget
      +" with easing: "
      +easing);
    timer = millis(); // timer 
    // make a random deviation 
    if (random(100) > 50)
      branch.turn(random(4));
    else 
    branch.turn(-random(4));
    // end of array? 
    if (indexTarget>=targets.length)
      indexTarget=0; //reset
  }//if
}//func 

void readKeys() {
  /*
  if (keyPressed) {
   if (keyCode == LEFT) {
   branch.turn(1);
   } else if (keyCode == RIGHT) {
   branch.turn(-1);
   } else if (keyCode == UP) {
   branch.changeSpeed(1);
   } else if (keyCode == DOWN) {
   branch.changeSpeed(-1);
   }
   }
   */
}// func 

void showLine(float a) {   
  // only for debug 
  pushMatrix();
  translate(branch.x, branch.y); 
  rotate(a);
  translate(28, 0);
  fill(0, 0, 255);
  rect(-30, -5, 60, 10);
  popMatrix();
}

float getAngle() {
  // core idea

  float a = atan2(
    targets[indexTarget].y-branch.y, 
    targets[indexTarget].x-branch.x);

  //----------------------------------------
  if (a<0) {
    a=map(a, -PI, 0, 
      PI, TWO_PI);
  }

  return a;
}

//==========================================================================

class Branch {

  float x, y;    // pos 
  float px, py;  // prev pos 
  float s, // speed 
    a, // angle 
    d;  // damping? 

  Branch(float _x, float  _y) {
    this.x = _x;
    this.y = _y;
    this.px = _x;
    this.py = _y;

    this.s = 1;
    this.a = TWO_PI-PI/2; // PI;
    this.d = 0.05;
  }

  void update() {
    this.move();
    this.checkEdges();
    this.show();
  }

  void move() {
    this.px = this.x;
    this.py = this.y;

    this.x = this.px + cos(this.a) * this.s;
    this.y = this.py + sin(this.a) * this.s;
  }

  void checkEdges() {
    if (this.x > width) {
      this.x = 0;
      this.px = this.x;
    } else if (this.x < 0) {
      this.x = width;
      this.px = this.x;
    }

    if (this.y > height) {
      this.y = 0;
      this.py = this.y;
    } else if (this.y < 0) {
      this.y = height;
      this.py = this.y;
    }
  }

  void turn(float _t) {
    this.a += _t * this.d;
  }

  void changeSpeed(float _s) {
    this.s =
      constrain(this.s + (_s * this.d), 0, 3);
  }

  void show() {
    // stroke(255);
    stroke(0, 255, 0);
    strokeWeight(3);
    line(this.px, this.py, 
      this.x, this.y);
  }
}//class
//
1 Like