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
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With