Parse

File Parse velocity.js

This tree is parsed live from the source file.

Classes

  • {{ item.name }}

    • {{ key }}

Not Classes

{{ getTree() }}

Comments

{{ getTreeComments() }}

Source

            /*
The velocity addon supplies classes and methods for speed and Vector based motion.

A `Vector` is very similar to a `Point`, but is referenced within a point through
`vx`, `vy`

 */


class VelocityReactor {
    constructor(){
        this.tick  = 0
    }

    step() {
        /* perform a tick for every interval, creating points, and pushing
        existing points */
        this.tick += 1

        this.points.forEach((p)=>{
            p.x += p.vx
            p.y += p.vy
        })
    }

    setAll(direction) {
        // this.reactor.setAll(direction)
        this.points.forEach(p=>{
            p.velocity.set(direction.x,direction.y)
        })
    }

    setEach(f){
        // this.reactor.setEach((p)=>random.xy())
        this.points.forEach(p=>{
            let direction = f(p)
            p.velocity.set(direction.x,direction.y)
        })
    }

    randomize(){
        this.setEach((p)=>random.xy.apply(random, arguments))
    }
}


function faceVelocity(p) {
    const vx = p.velocity.x;
    const vy = p.velocity.y;
    // skip if not moving
    if (vx === 0 && vy === 0) return;

    // atan2 gives you radians from the +x-axis, CCW positive
    const angleRad = Math.atan2(vy, vx);

    // convert to degrees
    const angleDeg = angleRad * (180 / Math.PI);

    // assign to your display object’s rotation (assuming 0° faces right)
    p.rotation = angleDeg;
}


class Vector {

    constructor(x=0, y=0, parent=undefined) {
        this.x = x
        this.y = y
        this.parent = parent;
    }

    //  Static methods
    static len(x, y) {
        return Math.sqrt(x * x + y * y);
    }

    static angle(x, y) {
        return Math.atan2(y, x);
    }

    getClass() {
        return this.constructor
    }

    add(v) {
        let C = this.getClass()
        return new C(this.x + v.x, this.y + v.y);
    }

    sub(v) {
        let C = this.getClass()
        return new C(this.x - v.x, this.y - v.y);
    }

    mul(v) {
        let C = this.getClass()
        return new C(this.x * v.x, this.y * v.y);
    }

    div(v) {
        let C = this.getClass()
        return new C(this.x / v.x, this.y / v.y);
    }

    scale(coef) {
        let C = this.getClass()
        return new C(this.x*coef, this.y*coef);
    }

    mutableSet(v) {
        this.x = v.x;
        this.y = v.y;
        return this;
    }

    mutableAdd(v) {
        this.x += v.x;
        this.y += v.y;
        return this;
    }

    mutableSub(v) {
        this.x -= v.x;
        this.y -= v.y;
        return this;
    }

    mutableMul(v) {
        this.x *= v.x;
        this.y *= v.y;
        return this;
    }

    mutableDiv(v) {
        this.x /= v.x;
        this.y /= v.y;
        return this;
    }

    mutableScale(coef) {
        this.x *= coef;
        this.y *= coef;
        return this;
    }

    equals(v) {
        return this.x == v.x && this.y == v.y;
    }

    epsilonEquals(v, epsilon) {
        return Math.abs(this.x - v.x) <= epsilon && Math.abs(this.y - v.y) <= epsilon;
    }

    length(v) {
        return Math.sqrt(this.x*this.x + this.y*this.y);
    }

    length2(v) {
        return this.x*this.x + this.y*this.y;
    }

    dist(v) {
        return Math.sqrt(this.dist2(v));
    }

    dist2(v) {
        var x = v.x - this.x;
        var y = v.y - this.y;
        return x*x + y*y;
    }

    normal() {
        var m = Math.sqrt(this.x*this.x + this.y*this.y);
        let C = this.getClass()
        return new C(this.x/m, this.y/m);
    }

    dot(v) {
        return this.x*v.x + this.y*v.y;
    }

    det(v) {
        return this.x * v.y - this.y * v.x;
    }

    //  Instance methods
    set(x, y) {
        if(arguments.length == 1) {
            y = x.y
            x = x.x
        }
        this.x = x; this.y = y;
    }

    copy(v) {
        this.x = v.x; this.y = v.y;
        return this;
    }

    len(){
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    angle(v){
        if(v === undefined) {
            return Math.atan2(this.y, this.x);
        }
        return this.angleWith(v)
    };

    angleWith(v) {
        return Math.atan2(this.x*v.y-this.y*v.x,this.x*v.x+this.y*v.y);
    }

    angle2(vLeft, vRight) {
        return vLeft.sub(this).angle(vRight.sub(this));
    }

    rotate(origin, theta) {
        var x = this.x - origin.x;
        var y = this.y - origin.y;
        let C = this.getClass()
        return new C(x*Math.cos(theta) - y*Math.sin(theta) + origin.x, x*Math.sin(theta) + y*Math.cos(theta) + origin.y);
    }


    mutableRotate(r) {
        var x = this.x,
            y = this.y,
            c = Math.cos(r),
            s = Math.sin(r);
        this.x = x * c - y * s;
        this.y = x * s + y * c;
    }

    toString() {
        return `(${this.x}, ${this.y})`;
    }

    setLen(l) {
        var s = this.len();
        if( s > 0.0 ) {
            s = l / s;
            this.x *= s;
            this.y *= s;
            return
        }

        this.x = l;
        this.y = 0.0;
    }

    normalize(){
        this.setLen(1.0);
    }

}

/*
Point.vx == Point.velocity.x
Point.vy == Point.velocity.y
 */


class PointSpeed {
    constructor(point) {
        this.point = point;
    }

    get xy() {
        let p = this.point
        if(this._speedValue){ return this._speedValue }
        if(!this.previous) {
            this.previous = [p.x, p.y]
            this._moduloTicker = 0
            return this._speedDistance = [0,0]
        }

        let mo = this._moduloTicker++
        let now = [p.x, p.y]
        if(mo % 2 == 0) {
            let prev = this.previous
            let distance = [now[0] - prev[0], now[1] - prev[1]]
            this._speedDistance = distance
        }
        this.previous = now
        return this._speedDistance

    }

    set xy(v) {
        /* Likely override with a custom value. */
        this._speedValue = v
    }

    absolute(multplier=1) {
        return this.xy.map((b)=>Math.abs(b))
    }

    float(multplier=1) {
        return this.xy.reduce((a,b)=>a+b)
    }

    absFloat(multplier=1) {
        return this.xy.reduce((a,b)=>Math.abs(a)+Math.abs(b))
    }

    direction(multplier=1) {
        // return an angle representing the direction.
        let d = this._speedDistance?this._speedDistance:[0,0];
        return Math.atan2(d[0] * multplier, d[1] * multplier)
    }
}


Polypoint.head.deferredProp('Point', function speed2D(){
    return new PointSpeed(this);
})


Polypoint.head.mixin('Point', {

    velocity: {
        get() {
            let v = this._velocity
            if(v){
                return v
            }
            return this._velocity = new Vector(0,0, this)

        }
        , set(v) {
            this._velocity = v
        }
    }

    , vx: {
        get() {
            return this.velocity.x
        }
        , set(v) {
            this.velocity.x = v
        }
    }
    , vy: {
        get() {
            return this.velocity.y
        }
        , set(v) {
            this.velocity.y = v
        }
    }
})
copy