Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Space-Ship movement - simulation

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

like image 245
Chris Avatar asked Oct 11 '18 16:10

Chris


1 Answers

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>
like image 69
Charlie Wallace Avatar answered Nov 16 '22 02:11

Charlie Wallace