JavaScriptでaddForceみたいな物理演算を実装した形跡があって実際に動いているけどどういうコードなのか分からないという話

pixi.jsで物理演算を実装したかったという気持ちは覚えている。
1年くらい前に必死こいてそれっぽいものを作ったのも覚えている。
しかし、今見直してみると何が書いてあるのかイマイチ読み解けない。
なので戒めとしてここに晒すことにした。

```js:script.js
//Aliases
let Application = PIXI.Application,
    Sprite = PIXI.Sprite,
    Rectangle = PIXI.Rectangle,
    Graphics = PIXI.Graphics;

const width = 800;
const height = width*0.7;

let app= new Application({
    width:width, 
    height:height,
    antialias: false,
    transparent: false,
    resolution: 1,
    backgroundColor: 0xf0ffff,
    autoResize: true,
});

document.getElementById("game").appendChild(app.renderer.view);

let rectangle;
const recwid = 10;
const rechei = 100;
let stage;
let hand;

setup();

function setup(){
    //クリック感知用の透明なコンテナ
    stage = new Sprite();
    stage.width = width;
    stage.height = height;
    stage.x = stage.y = 0;
    stage.interactive = true;
    stage
        .on("pointerdown",onClick)
        .on("pointermove",mouseMove)
        .on("pointerup",outClick)
        .on("pointerout",outClick);
    app.stage.addChild(stage);

    //動く長方形
    rectangle = new Graphics();
    rectangle.beginFill(0x66CCFF);
    rectangle.drawRect(0,0,recwid,rechei);
    rectangle.endFill();
    rectangle.x = 400;
    rectangle.y = 100;
    rectangle.vx = rectangle.vy = rectangle.ax = rectangle.ay = rectangle.rv = 0;
    rectangle.m = 1000;
    rectangle.mm = 10000;
    rectangle.rotation = 40;
    rectangle.pivot.set(recwid/2,rechei/2);
    app.stage.addChild(rectangle);

    //長方形を引き寄せる手
    hand = new Graphics();
    hand.beginFill(0x9966FF);
    hand.drawCircle(0,0,10);
    hand.endFill();
    app.stage.addChild(hand);
    hand.x = 400;
    hand.y = 100;

    app.ticker.add(delta => play(delta));
}



const grav = 100;//重力
const maxVel = 30;//速さの最大
const maxrv = 10;//改定速度の最大
const handForce = 200;//手が引っ張る力
const mouseForce = 10;//マウスが引っ張る力
function play(delta) {

    //マウスで引っ張る部分の座標計算
    rectangle.xx = rectangle.x+Math.sin(-rectangle.rotation)*rechei/2;
    rectangle.yy = rectangle.y+Math.cos(-rectangle.rotation)*rechei/2;
    //手に引っ張られる部分の座標計算
    rectangle.xxx = rectangle.x-Math.sin(-rectangle.rotation)*rechei/2;
    rectangle.yyy = rectangle.y-Math.cos(-rectangle.rotation)*rechei/2;

    rectangle.ax = 0;
    rectangle.ay = 0;
    if(clicking) addForce(rectangle,0,1,mouseForce*(mouse.x-rectangle.xx),mouseForce*(mouse.y-rectangle.yy));//マウス方向に力が働く
    addForce(rectangle,0,0,0,grav);//重力は常に働く
    if(clicking) addForce(rectangle,0,-1,handForce*(hand.x-(rectangle.xxx+rectangle.vx)),handForce*(hand.y-(rectangle.yyy+rectangle.vy)));//手が棒を持つ

    rectangle.vx += rectangle.ax/rectangle.m;
    rectangle.vy += rectangle.ay/rectangle.m;

    rectangle.vx = Math.min(Math.max(rectangle.vx,-maxVel),maxVel);
    rectangle.vy = Math.min(Math.max(rectangle.vy,-maxVel),maxVel);
    rectangle.av = Math.min(Math.max(rectangle.av,-maxrv),maxrv);

    rectangle.rotation += rectangle.rv*2*Math.PI/60;
    rectangle.x += rectangle.vx;
    rectangle.y += rectangle.vy;
}


function hypo(a,b,c,d){//二点間の距離 0の時は0.0001を返す(0除算回避)
    let f = Math.pow(Math.pow(a-c,2)+Math.pow(b-d,2),1/2);
    if (f!=0) return Math.pow(Math.pow(a-c,2)+Math.pow(b-d,2),1/2);
    else return (f+0.0001);
}

function addForce(obj,px,py,x,y){//pは-1~1
    let angle = Math.PI/2 -obj.rotation;

    let d1 = hypo(0,0,x,y);
    let d2 = hypo(0,0,px*obj.width/2,py*obj.height/2);
    let d3 = hypo(0,0,px,py);

    let cos1 = Math.cos(angle);
    let sin1 = Math.sin(angle);
    let cos2 = x/d1;
    let sin2 = y/d1;
    let cos3 = (px*obj.width/2)/d2;
    let sin3 = (py*obj.height/2)/d2;

    obj.rv += d3*d1*((cos1*cos3-sin1*sin3)*cos2 +(sin1*cos3-cos1*sin3)*sin2)/obj.mm;

    obj.ax += x;
    obj.ay += y;
}



//クリックイベント
let mouse = {};
mouse.x = 0;
mouse.y = 0;
let clicking = false;
function onClick(e){
    this.data = e.data;
    mouse.x = this.data.getLocalPosition(this.parent).x![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482250/29dae441-65ee-17b8-f77d-bafdf5470aae.gif)

    mouse.y = this.data.getLocalPosition(this.parent).y
    clicking= true;
}
function outClick(e){
    clicking = false;
    this.data = null;
}
function mouseMove(e){
    this.data = e.data;
    mouse.x = this.data.getLocalPosition(this.parent).x
    mouse.y = this.data.getLocalPosition(this.parent).y
}
```

![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482250/e7262d11-9f9a-4c3c-a715-ae06d2912ed2.gif)
長方形に物理演算が適用されており、クリックしている間は手（紫の円）に強く引っ張られ、同時にマウスポインタに弱く引っ張られるというものだ。

元のコードにはコメントがほとんど書かれていなかったので、今分かる部分には最低限のマナーとしてコメントで補完をした。
特に`addForce`関数の中身が分からない。三角関数の加法定理と睨み合いながら無理やり動くようにしたんだろうなということは分かる。助けて～～～～～