How can I decelerate a physics object to a stand still?

I am currently working on a little prototype and I am struggling to apply a friction force to slow down the player object.

I have a simple physics engine using the model of setting acceleration, which then is applied to the velocity before being applied to the position. To calculate the friction, before the acceleration is applied to the velocity, I multiply the velocity by -1 to the the opposite direction, then scale the magnitude by 0.5. I then apply this force to the acceleration by adding it to the existing acceleration.

This doesn't seem to work however, and the object just moves back and forwards erratically.


constructor (x, y){
this.r = 20;
this.position = new Vector2(x, y);
this.velocity = new Vector2(0, 0);
this.acceleration = new Vector2(0, 0);
this.maxSpeed = 2.3;
this.friction = 0.5;
this.createSprite();

}

createSprite(){
let sprite = new PIXI.Graphics();
sprite.beginFill(0xFF0000);
sprite.lineStyle(5, 0xBB0000, 1);
sprite.drawCircle(0, 0, this.r);
sprite.endFill();

this.sprite = sprite;
this.sprite.position = this.position;

}

move(){
//this.calcFriction();
this.velocity = this.velocity.add(this.acceleration); //apply acceleration to velocity
this.limitVel();
this.vel

this.sprite.position = this.position;

}

limitVel() {
let mag = this.velocity.magnitude();
if(mag > this.maxSpeed){
this.velocity = this.velocity.setMag(this.maxSpeed);
}
}

}

calcFriction(){
let negVel = this.velocity.scale(-1);
let frictionForce = negVel.scale(this.friction);
console.log(this.acceleration);

}

}


This is the code I have written so far. The move function is called every frame.

I feel like there is one simple but important concept I'm missing here.

Thanks.

I multiply the velocity by -1 to the the opposite direction

That's your mistake. If you do that, you then have to check if you have gone into reverse.

Easier ways focus on scalar rather than vector arithmetic, as it's cheaper and easier to reason about.

Friction works as follows:

const FRICTION = 0.1;
let speed = velocityVector.magnitude();
let speedReduced = speed - FRICTION;
if (speedReduced < 0)
{
speedReduced = 0;
}
velocityVector.normalise(); //same as velocityVector.divide - results in length 1.0
velocityVector.multiply(speedReduced);


Damping brings the value close to zero, arithmetically:

const DAMPING = 0.98;
let speed = velocityVector.magnitude();
let speedDamped = speed * DAMPING;

velocityVector.normalise(); //same as velocityVector.divide - results in length 1.0
velocityVector.multiply(speedDamped);


...this will get very close to zero, but takes a very long time to reach actual zero, so stopping entirely is thus done by adding a logical IF into the above:

const EPSILON = 0.01;
const DAMPING = 0.98;
let speed = velocityVector.magnitude();
let speedReduced = speed * DAMPING;

if (speedReduced < EPSILON)
speedReduced = 0;

velocityVector.normalise(); //same as velocityVector.divide - results in length 1.0
velocityVector.multiply(speedReduced);


Comparison

Multiplication may be preferred over subtraction as you technically don't need the explicit check to see if you are close to zero... you can just let the object sit and continue to be processed at miniscule velocities. But most implementations would include the close-to-zero check.

Note that friction provides a linear reduction in speed, unlike damping - depends what you prefer. The conditional there is mandatory, or else you will start going backwards.