6

I have written some code to simulate a gravitation-free movement of a ship with a single thruster. Most of the time it works, and the ship reaches it's destination perfectly, but just sometimes it accelerates infinitively. But I can't figure out, why?

seek(target) {
    var desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target
    if (desired.mag()>0.1){

        this.orientation = desired;
        if (this.velocity.heading() - desired.heading() > 0.01 && this.velocity.mag() >0.01) {
            this.orientation = this.velocity.copy().mult(-1);
        }

        if ((this.velocity.mag()*this.velocity.mag())/(2*(this.maxForce/this.mass)) > desired.mag()) {
                this.orientation.mult(-1);
        }

        this.applyForce(this.orientation.normalize().mult(this.maxForce/this.mass));
    } else {
        this.velocity = createVector(0,0);
    }
}

You can test the result here:

https://editor.p5js.org/Ahiru/sketches/r1rQ9-T5m

Hossein Golshani
  • 1,847
  • 5
  • 16
  • 27
Chris
  • 109
  • 1
  • 9
  • Found the mistake: "this.velocity.heading() - desired.heading()" could become negative. An absolute value function around it solved the problem. – Chris Oct 22 '18 at 17:20

2 Answers2

2

The issue of the ship object going past the target is caused by the magnitude delta being too small for the increment that the ship moves in.

In order to get the spaceship object to land on the selected point you need to modify the seek method:

seek(target) {
    var desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target
    if (desired.mag()>.01){

The object is moving in increments that can cause desired.mag to go from a number that is greater than .01 as the object approaches to another magnitude that is larger than .01 as the object passes the target and moves away.

modify

if (desired.mag() > .01)

to

if (desired.mag() > 2.0)

for example and the ship will be captured and land on the target and stay there until another target is selected.

Here is a working example with the delta set to equal the diameter of the target so that the ship appears to land on the surface of the target.

let v;
var targetDiameter = 12;
function setup() {
  pixelDensity(1);
  createCanvas(1000, 1000);
  v = new Vehicle(width / 2, height / 2);
  target = createVector(200, 200);
}

function draw() {
  background(51);

  // Draw an ellipse at the mouse position
  fill(127);
  stroke(200);
  strokeWeight(2);
  ellipse(target.x, target.y, targetDiameter, targetDiameter);

  // Call the appropriate steering behaviors for our agents
  v.seek(target);
  v.update();
  v.display();
}

function mouseClicked() {
  target = createVector(mouseX, mouseY);
  hex = find_HexCoordinates(100, target);
  console.log("click " + hex.x + " " + hex.y + " " + hex.z);
}
class ThrustList {
  constructor(thrust, time) {
    this.thrust = createVector(thrust);
    this.time = time;
  }

  set(thrust, time) {
    this.thrust.set(thrust);
    this.time = time;
  }
}

class ThrustParams {
  constructor (deltaPosition, deltaVelocity, maxForce, mass) {
    this.deltaPosition = createVector(deltaPosition);
    this.deltaVelocity = createVector(deltaVelocity);
    this.maxForce = maxForce;
    this.mass = mass;
  }
}

class hexmetrics {
  constructor (radius) {
    this.outerRadius = radius;
    this.innerRadius = this.outerradius * sqrt(3)/2; 
  }
 
}   

function find_HexCoordinates (radius, position) {
  this.innerRadius = radius;
  this.outerRadius = this.innerRadius * sqrt(3)/2;
  this.px = position.x - 1000/2;
  this.py = position.y - 1000/2;
  this.x = px / this.innerRadius * 2;
  this.y = -x;
  this.offset = py / this.outerRadius * 3;
  this.x -= offset;
  this.y -= offset;
  this.iX = Math.round(x);
  this.iY = Math.round(y);
  this.iZ = Math.round(-x -y);
  if (iX + iY + iZ != 0) {
    dX = Math.abs(x-iX);
    dY = Math.abs(y-iY);
    dZ = Math.abs(-x -y -iZ);
    if (dX > dY && dX > dZ) {
      iX = -iY -iZ;
    }
    else if (dZ > dY) {
      iZ = -iX -iY;
    }
  }
    
  return createVector(this.iX, this.iY, this.iZ);
}

class Vehicle {
  constructor(x, y){
    this.mass = 1;
    this.orientation = createVector(0,1);
    this.turning_speed = 90;
    this.acceleration = createVector(0, 0);
    this.maxForce = .02;
    this.position = createVector(x, y);
    this.r = 3;
    this.velocity = createVector(0, 0);
    } 

  // Method to update location
  update() {
  // Update velocity
  this.velocity.add(this.acceleration);
  // Limit speed
  this.position.add(this.velocity);
  // Reset accelerationelertion to 0 each cycle
  this.acceleration.mult(0);
}

  applyForce(force) {
    this.acceleration.add(force);
  }

  // A method that calculates a steering force towards a target
  // STEER = DESIRED MINUS VELOCITY
  seek(target) {
    var desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target

    if (desired.mag() > targetDiameter){
      this.orientation = desired;
      if (Math.abs(this.velocity.heading() - desired.heading()) > 0.01 && this.velocity.mag() >0.01) {
        this.orientation = this.velocity.copy().mult(-1);
      }

      if ((this.velocity.mag()*this.velocity.mag())/(2*(this.maxForce/this.mass)) > desired.mag()) {
        this.orientation.mult(-1);
      }

      this.applyForce(this.orientation.normalize().mult(this.maxForce/this.mass));
    } else {

    this.velocity = createVector(0,0);
   }
}

  display() {
    // Draw a triangle rotated in the direction of velocity
    var theta = this.orientation.heading() + PI / 2;
    fill(127);
    stroke(200);
    strokeWeight(1);
    push();
    translate(this.position.x, this.position.y);
    rotate(theta);
    beginShape();
    vertex(0, -this.r * 2);
    vertex(-this.r, this.r * 2);
    vertex(this.r, this.r * 2);
    endShape(CLOSE);
    pop();
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
Charlie Wallace
  • 1,810
  • 1
  • 15
  • 17
  • @chris this answer incorporates the absolute value correction you mention and the magnitude delta correction. I know this is an old question but I think the question and answer can be useful for others looking for examples of sketches with movement that interact with the mouse. – Charlie Wallace Mar 05 '19 at 21:51
0

I'm never using p5js before but I think it's because of the applyForce() , it's keep adding new force when user click.

  applyForce(force) {
this.acceleration.add(force);}
Long
  • 1
  • No, that's not it unfortunately - when clicking no force is added: function mouseClicked() { target = mouse; hex = find_HexCoordinates(100, target); console.log("click " + hex.x + " " + hex.y ); } I changed the link, so the complete source-code is visible now. – Chris Oct 12 '18 at 15:25
  • 1
    @Chris Sorry , my mistake. I check on your source , found an issue on desired.mag()>0.01 . It's sometimes never go inside the else clause. Beside , when the ship gonna reach the destination , I change the destination to another , it's keep going forward the old direction too. – Long Oct 15 '18 at 06:54