Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

8 years ago by SteamPunkProgrammer

I've been looking in the source for impactJS and I havent seen alot of vector math functions that you normally see in game engines, is there a library everyone uses?

I've just been writing the functions as I need them for now.

8 years ago by Arantor

Vector math functions to do what, exactly?

8 years ago by SteamPunkProgrammer

the normal stuff, get a vectors magnitude, normalize, rotate vector, vector to angle, the things you normally need to do to have any kind of complex logic involving movement.

8 years ago by Arantor

First up, I wouldn't call any of that 'the normal stuff', especially since all you're ending up doing it converting it back and forth to a system Impact isn't even using (and you're doing that once per frame, which has got to hurt performance)

Regarding a 'library', there isn't one - mostly because people don't use it that much, as most of what's been built thus far is platformers or Zelda-type games, neither of which use much in the way of angular maths.

Then again, even the lunar lander I did, I don't recall that using vector math.

8 years ago by SteamPunkProgrammer

it is normal stuff when you are talking about vector math, which I am. I need to be able to do vector math to determine the direction and angle of free floating entities. It doesn't matter to much, I was just wondering if someone had already written this stuff so I dont have to write a function everytime I hit one I dont have already.

8 years ago by Arantor

Entities already have angleTo methods to determine the relative angles to each other...

8 years ago by Skywalker

angleTo doesn't tell you what direction the entity was moving when calculating deflection.

I'm a bit in the same boat since I added collision recognition for circular entities, I have to manually determine the vector's based on the x/y velocity to deflect it properly

8 years ago by anthonycosgrave

I've started trying to put together a basic list of functions if it's of any help. I haven't tested everything yet but I'm happy to share what I have. I'd like to add that I'm new to JavaScript so if there are any mistakes or optimizations that could be made, please let me know :)

I don't have a vector class created, instead I wrote these functions to work so you can pass in a your 'entity.pos' for example.

    vectAdd: function( vectA, vectB) {
        return {x:(vectA.x + vectB.x), y:(vectA.y + vectB.y)};
    },
    
    vectSub: function(vectA, vectB) {
        return {x:(vectA.x - vectB.x), y:(vectA.y - vectB.y)};
    },
    
    // multiplying by a scalar changes the magnitude but leaves the direction
    // the same.
    vectScalarMult: function(vect, scalar) {
        return {x:(vect.x * scalar), y:(vect.y * scalar)};
    },
    
    // returns true if vectA equals vectB.
    vectEquals: function(vectA, vectB) {
        return (vectA.x == vectB.x && vectA.y == vectB.y);
    },
    
    // calculate the magnitude (i.e. the length) of a vector.
    vectMag: function(vect) {
        return Math.sqrt((vect.x * vect.x) + (vect.y * vect.y));
    },
    
    // normalize a vector (i.e. get the direction, reduce the length to 1).
    vectNorm: function(vect) {
        var magnitude = this.vectMag(vect);
        
        return {x: (vect.x / magnitude), y:(vect.y / magnitude)};
    },
    
    // calculate Dot product.
    vectDot: function(vectA, vectB) {
        return (vectA.x * vectB.x + vectA.y * vectB.y);
    },
    
    // calculate the length of a vector.
    vectLength: function(vect) {
        return Math.sqrt(vect.x * vect.x + vect.y * vect.y);
    },
    
    // returns a perpendicular vector to vect.
    vectPerp: function(vect) {
        return {x: -vect.y, y: vect.x};
    },
    
    // returns distance between vectA and vectB.
    vectDist: function(vectA, vectB) {
        var sub = this.vectSub(vectA, vectB);
        
        return this.vectLength(sub);
    },
    
    // returns the reverse of vect.
    vectReverse: function(vect) {
        return {x:-vect.x, y:-vect.y};
    }

7 years ago by hurik

hi,

working on a project with uses a lot of vector operations.

so i made this little plugin which gives you an easy way to use this functions.

github repo and information how you can use it: https://github.com/hurik/impact-vector2d

@anthonycosgrave:
it based on your work. i expanded it a little bit. i hope it is ok ...

7 years ago by quidmonkey

I wrote one some time ago:

ig.module(
    'plugins.vec2'
)
.requires(
    'impact.entity'
)
.defines(function(){
    
iig.Vec2 = ig.Class.extend({

    x: 0,
    y: 0,

    init: function (x, y) {
        this.x = x;
        this.y = y;
    },

    //angle of this vector relative to axis
    angle: function () {
        return Math.atan2(this.y, this.x);
    },

    //get new instance of this vector
    clone: function () {
        return new ig.Vec2(this.x, this.y);
    },

    //get dot product between this vector
    //and passed in vector
    dot: function (vec2) {
        return this.x * vec2.x + this.y * vec2.y;
    },

    //compares a passed in vector to this vector
    //to see if they are equal
    equals: function (vec2) {
        return !(this.x !== vec2.x || this.y !== vec2.y);
    },

    //invert this vector
    invert: function () {
        this.x = -this.x;
        this.y = -this.y;
        return this;
    },

    //get interpolated vector between this vector
    //and passed in vector
    lerp: function (vec2, proportion) {
        return new ig.Vec2(
        	this.x + proportion * (vec2.x - this.x),
        	this.y + proportion * (vec2.y - this.y)
        );
    },

    //get magnitude of this vector
    magnitude: function () {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    },

    //normalize this vector
    normalize: function () {
        return this.scale(1 / this.magnitude());
    },

    //get vector orthogonal to this vector
    orthogonal: function () {
        return new ig.Vec2(-this.y, this.x);
    },

    //dot product of passed in vector
    //and perpendicular of this vector
    //this is the 2d equivalent of a 3d cross product
    perproduct: function (vec2) {
        return vec2.x * this.y - vec2.y * this.x;
    },

    //reflect this vector around the passed in vector
    reflect: function (vec2) {
        return this.sum(vec2.clone().normalize().orthogonal().scale(this.dot(vec2) * 2).inverse());
    },

    //rotate this vector
    rotate: function (angle) {
        var cos = Math.cos(angle),
            sin = Math.sin(angle),
            x = this.x,
            y = this.y;
        this.x = x * cos - y * sin;
        this.y = x * sin + y * cos;
        return this;
    },

    //rotate this vector around a specified point
    rotateAroundPoint: function (angle, point) {
        return this.sum(-point).rotate(angle).sum(point);
    },

    //scale this vector
    //will scale by passed in value or vec2
    scale: function (scalar) {
        if (scalar instanceof ig.Vec2) {
            this.x *= scalar.x;
            this.y *= scalar.y;
        } else {
            this.x *= scalar;
            this.y *= scalar;
        }
        return this;
    },

    //sum this vector with another vector
    sum: function (vec2) {
        this.x += vec2.x;
        this.y += vec2.y;
        return this;
    },

    //convert from vector back to a generic object
    toObj: function () {
        return ig.Vec2.toObj(this);
    }

});

ig.Vec2.Zero = new ig.Vec2(0, 0);
ig.Vec2.One = new ig.Vec2(1, 1);
ig.Vec2.UnitX = new ig.Vec2(1, 0);
ig.Vec2.UnitY = new ig.Vec2(0, 1);
ig.Vec2.TileOrigin = ig.Vec2.UnitX.clone().rotate(Math.PI / 4).invert();

//convert an object with x & y properties to a vector
//if properties don't exit, return zero vector
ig.Vec2.toVec2 = function (obj) {
    return new ig.Vec2(obj.x || 0, obj.y || 0);
};

//convert from vector back to a generic object
ig.Vec2.toObj = function (vec2) {
    return {
        x: vec2.x || 0,
        y: vec2.y || 0
    };
};

});

Be careful using vectors. Your natural inclination to is to return a new vector object { x: xVal, y: yVal }, but spewing out objects in Javascript is a bad idea because it leads to a vast amount of garbage.

7 years ago by Xatruch

Quote from quidmonkey
Be careful using vectors. Your natural inclination to is to return a new vector object { x: xVal, y: yVal }, but spewing out objects in Javascript is a bad idea because it leads to a vast amount of garbage.


So does creating a new instance of b2.Vec2 in box2d for example, does create alot of garbage?

7 years ago by hurik

When you work with vectors a lot, doesn't you get more overhead with classes?

Was thinking about changing my functions to something like this:
add: function(result, vectA, vectB) {
	result.x = (vectA.x + vectB.x);
	result.y = (vectA.y + vectB.y);
},

This way it doesn't create a new object (call by reference). and the result is written in the existing object.


Second question: Why did you return this? when you already have written the result into this.x and this.y!?!?!?

7 years ago by quidmonkey

For my Vec2 class, I change the object in place when it makes sense. You'll notice that I only create a new Vec2 for cloning, lerping and getting an orthogonal. You could make the argument that a new Vec2 should only be created for cloning, but I found in practice that I always wanted a clone for a lerp or orthogonal.

Yes, Box2d does create a lot of garbage!

I return this to chain method calls. If you take a look at the reflect or rotateAroundPoint methods you can see it in action. Returning this does not create a new Object - very handy!

7 years ago by vincentpiel

@quidmonkey your lib is very interesting, thanks. And you're 100% right about doing things 'in place' to avoid those random slowdown the garbage collector can create.

But hurik is right : the simple fact of using ig.Class creates quite some overhead. Since you don't use inject nor extend with it your vectors, you should go with a simple Javascript function, not an ig.Class.

It is much faster on object creation, will have a faster ++ or +++ execution depending on the javascript engine, and uses much less memory thanks to prototype.

ig.Vect2 = function(x,y) {
   this.x = x;
   this.y = y;          // hard to have a simpler/faster constructor !!!
};

//angle of this vector relative to axis
ig.Vect2.prototype.angle = function () {
        return Math.atan2(this.y, this.x);
    };

//get new instance of this vector
ig.Vect2.prototype.clone = function () {
        return new ig.Vec2(this.x, this.y);
};

//get dot product between this vector
//and passed in vector
ig.Vect2.prototype.dot = function (vec2) {
        return this.x * vec2.x + this.y * vec2.y;
 };

... etc ...

Rq   : as it is, rotateAroundPoint  doesn't work ( - Vec2 does not give the opposite 
vector but try to get a number from Vec2, fails, and returns Nan ) .
Rq2 : scale() is polymorphic : it prevents most Js engine from optimizing : split
 scale(NumberOrVector) into scale (someNumber) and scaleByVector(someVec2).
Rq3 : equals should take rounding issues in consideration, 
       since for instance 0.1+ 0.2  !==  0.3  in javascript due to number representation.
       and first step of equals should be object equality test ( === )
Rq4 : a 'generic object' doesn't exist in javascript. all objects are generic. I don't see
 why someone would want an object with same x and y, but giving ( obj  instanceof 
Vec2 === false). 
Rq5: a sqMagnitude function could be intersting to have also, since then you could 
compare the square of two vectors norms to avoid two sqrt. 
Rq6: in normalize, divise x and y directly to reduce rounding errors.


7 years ago by quidmonkey

Quite right. Impact's functional wrapping forces scoping overhead vs. creating your own prototype. Both creation and calling of the object will be slower. But in my experience, garbage collection and drawing are always the main culprits when I encounter performance issues. For this, I wanted an Impact plugin for the module benefits, and that outweighs the performance trade-off for me. But then again, I've never created a game where that level of optimization is required.

I'm gonna throw this out on Github soon. Feel free to fork it and create a non-module version.

7 years ago by vincentpiel

@quidmonkey : it might be clear for you, but a module might contain anything, ranging from the classical ig.Class to a Base64image, ... or anything. Modules are just a way to execute functions in a given order.
For the optimisation 'needs' : anyway we are making efforts only for slower devices here, because on modern desktop with latest Chrome, reaching 60 fps is not an issue.
And for this vector thing, the memory cost should be 6 times higher with ig.Class. (Look at ig.Class.extend, it creates a closure with quite a few variables. )
And it's slower.
All that for no benefits.
So you'd better do a module with plain Javascript function : best of both worlds !

7 years ago by hurik

why do it your self when someone already has done the work!?!?

http://stepheneb.github.com/webgl-matrix-benchmarks/matrix_benchmark.html

google closure seems to be one of the best. anyone an idea how to get it work with impact? so that it get baked too?

or must i copy the functions in a plugin?

edit:
"made" this here:
/*
 * Vec2
 * https://github.com/hurik/impact-vec2
 *
 * v1.0.0
 *
 * Andreas Giemza
 * andreas@giemza.net
 * http://www.hurik.de/
 *
 * Based on:
 * https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/math/vec2.js
 *
 */

ig.module(
	'plugins.vec2'
)
.defines(function(){ "use strict";
/**
 * Class for a two-dimensional vector object and assorted functions useful for
 * manipulating points.
 *
 * @param {number} x The x coordinate for the vector.
 * @param {number} y The y coordinate for the vector.
 * @constructor
 */
ig.Vec2 = function(x, y) {
	this.x = x;
	this.y = y;
};


/**
 * @return {!ig.Vec2} A random unit-length vector.
 */
ig.Vec2.randomUnit = function() {
	var angle = Math.random() * Math.PI * 2;
	return new ig.Vec2(Math.cos(angle), Math.sin(angle));
};


/**
 * @return {!ig.Vec2} A random vector inside the unit-disc.
 */
ig.Vec2.random = function() {
	var mag = Math.sqrt(Math.random());
	var angle = Math.random() * Math.PI * 2;

	return new ig.Vec2(Math.cos(angle) * mag, Math.sin(angle) * mag);
};


/**
 * @return {!ig.Vec2} A new vector with the same coordinates as this one.
 * @override
 */
ig.Vec2.prototype.clone = function() {
	return new ig.Vec2(this.x, this.y);
};


/**
 * Returns the magnitude of the vector measured from the origin.
 * @return {number} The length of the vector.
 */
ig.Vec2.prototype.magnitude = function() {
	return Math.sqrt(this.x * this.x + this.y * this.y);
};


/**
 * Returns the squared magnitude of the vector measured from the origin.
 * NOTE(brenneman): Leaving out the square root is not a significant
 * optimization in JavaScript.
 * @return {number} The length of the vector, squared.
 */
ig.Vec2.prototype.squaredMagnitude = function() {
	return this.x * this.x + this.y * this.y;
};


/**
 * Scales the current vector by a constant.
 * @param {number} s The scale factor.
 * @return {!ig.Vec2} The scaled vector.
 */
ig.Vec2.prototype.scale = function(s) {
	this.x *= s;
	this.y *= s;
	return this;
};


/**
 * Reverses the sign of the vector. Equivalent to scaling the vector by -1.
 * @return {!ig.Vec2} The inverted vector.
 */
ig.Vec2.prototype.invert = function() {
	this.x = -this.x;
	this.y = -this.y;
	return this;
};


/**
 * Normalizes the current vector to have a magnitude of 1.
 * @return {!ig.Vec2} The normalized vector.
 */
ig.Vec2.prototype.normalize = function() {
	return this.scale(1 / this.magnitude());
};


/**
 * Adds another vector to this vector in-place.
 * @param {!ig.Vec2} b The vector to add.
 * @return {!ig.Vec2}  This vector with {@code b} added.
 */
ig.Vec2.prototype.add = function(b) {
	this.x += b.x;
	this.y += b.y;
	return this;
};


/**
 * Subtracts another vector from this vector in-place.
 * @param {!ig.Vec2} b The vector to subtract.
 * @return {!ig.Vec2} This vector with {@code b} subtracted.
 */
ig.Vec2.prototype.subtract = function(b) {
	this.x -= b.x;
	this.y -= b.y;
	return this;
};


/**
 * Returns the angle of the vector from the origin.
 * @return {number} The angle, in radians, clockwise from the positive X
 *     axis.
 */
ig.Vec2.prototype.azimuth = function() {
	return Math.atan2(this.y, this.x);
};


/**
 * Rotates this vector in-place by a given angle, specified in radians.
 * @param {number} angle The angle, in radians.
 * @return {!ig.Vec2} This vector rotated {@code angle} radians.
 */
ig.Vec2.prototype.rotate = function(angle) {
	var cos = Math.cos(angle);
	var sin = Math.sin(angle);
	var newX = this.x * cos - this.y * sin;
	var newY = this.y * cos + this.x * sin;
	this.x = newX;
	this.y = newY;
	return this;
};


/**
 * Rotates a vector by a given angle, specified in radians, relative to a given
 * axis rotation point. The returned vector is a newly created instance - no
 * in-place changes are done.
 * @param {!ig.Vec2} v A vector.
 * @param {!ig.Vec2} axisPoint The rotation axis point.
 * @param {number} angle The angle, in radians.
 * @return {!ig.Vec2} The rotated vector in a newly created instance.
 */
ig.Vec2.rotateAroundPoint = function(v, axisPoint, angle) {
	var res = v.clone();
	return res.subtract(axisPoint).rotate(angle).add(axisPoint);
};


/**
 * Compares this vector with another for equality.
 * @param {!ig.Vec2} b The other vector.
 * @return {boolean} Whether this vector has the same x and y as the given
 *     vector.
 */
ig.Vec2.prototype.equals = function(b) {
	return this == b || !! b && this.x == b.x && this.y == b.y;
};


/**
 * Returns the distance between two vectors.
 * @param {!ig.Vec2} a The first vector.
 * @param {!ig.Vec2} b The second vector.
 * @return {number} The distance.
 */
ig.Vec2.distance = function(a, b) {
	var dx = a.x - b.x;
	var dy = a.y - b.y;
	return Math.sqrt(dx * dx + dy * dy);
};

/**
 * Returns the squared distance between two coordinates. Squared distances can
 * be used for comparisons when the actual value is not required.
 *
 * Performance note: eliminating the square root is an optimization often used
 * in lower-level languages, but the speed difference is not nearly as
 * pronounced in JavaScript (only a few percent.)
 *
 * @param {!ig.Vec2} a The first vector.
 * @param {!ig.Vec2} b The second vector.
 * @return {number} The squared distance.
 */
ig.Vec2.squaredDistance = function(a, b) {
	var dx = a.x - b.x;
	var dy = a.y - b.y;
	return dx * dx + dy * dy;
};


/**
 * Compares vectors for equality.
 * @param {!ig.Vec2} a The first vector.
 * @param {!ig.Vec2} b The second vector.
 * @return {boolean} Whether the vectors have the same x and y coordinates.
 */
ig.Vec2.equals = function(a, b) {
	if(a == b) {
		return true;
	}
	if(!a || !b) {
		return false;
	}
	return a.x == b.x && a.y == b.y;
};


/**
 * Returns the sum of two vectors as a new Vec2.
 * @param {!ig.Vec2} a The first vector.
 * @param {!ig.Vec2} b The second vector.
 * @return {!ig.Vec2} The sum vector.
 */
ig.Vec2.sum = function(a, b) {
	return new ig.Vec2(a.x + b.x, a.y + b.y);
};


/**
 * Returns the difference between two vectors as a new Vec2.
 * @param {!ig.Vec2} a The first vector.
 * @param {!ig.Vec2} b The second vector.
 * @return {!ig.Vec2} The difference vector.
 */
ig.Vec2.difference = function(a, b) {
	return new ig.Vec2(a.x - b.x, a.y - b.y);
};


/**
 * Returns the dot-product of two vectors.
 * @param {!ig.Vec2} a The first vector.
 * @param {!ig.Vec2} b The second vector.
 * @return {number} The dot-product of the two vectors.
 */
ig.Vec2.dot = function(a, b) {
	return a.x * b.x + a.y * b.y;
};


/**
 * Returns a new Vec2 that is the linear interpolant between vectors a and b at
 * scale-value x.
 * @param {!ig.Vec2} a Vector a.
 * @param {!ig.Vec2} b Vector b.
 * @param {number} x The proportion between a and b.
 * @return {!ig.Vec2} The interpolated vector.
 */
ig.Vec2.lerp = function(a, b, x) {
	return new ig.Vec2(a.x + x * (b.x - a.x), a.y + x * (b.y - a.y));
};

});


the question is how is the best way to implement some other functions i need:
for example i need a vHeading vector, which is the current velocity normalized. but i didn't want to create a new verctor in every update. would that be a good idea?
ig.Vec2.prototype.setNormalized = function(a) {
	var mag = Math.sqrt(a.x * a.x + a.y * a.y);

	this.x = a.x / mag;
	this.y = a.y / mag;
};

7 years ago by quidmonkey

Quote from vincentpiel
And for this vector thing, the memory cost should be 6 times higher with ig.Class. (Look at ig.Class.extend, it creates a closure with quite a few variables. )
And it's slower.


That's another great point. I hadn't considered using Impact's module system with prototypal Object creation.

I threw together a performance test comparing the prototypal (Google-style) vs. the module (Impact-style) way of creating objects. The results are staggering: the prototypal way is 50 times faster than the module way! I couldn't throw this up on jsPerf due to Impact being proprietary, but I uploaded my test to Github (along with both plugins).

Here's my test:
update: function () {
    var start, stop, gElapsed, iElapsed;

    // google test
    start = Date.now();

    for (var i = 0, len = 100000; i < len; i++) {
        new ig.Vec2g.random().clone().rotate(Math.PI).sum(ig.Vec2g.One).normalize().magnitude();
    }

    stop = Date.now();
    gElapsed = stop - start;

    console.log('***Google***');
    console.log('start', start);
    console.log('stop', stop);
    console.log('elapsed', gElapsed);

    // impact test
    start = Date.now();

    for (var i = 0, len = 100000; i < len; i++) {
        new ig.Vec2i.random().clone().rotate(Math.PI).sum(ig.Vec2i.One).normalize().magnitude();
    }

    stop = Date.now();
    iElapsed = stop - start;

    console.log('***Impact***');
    console.log('start', start);
    console.log('stop', stop);
    console.log('elapsed', iElapsed);

    console.log('Google is ' + (iElapsed / gElapsed).round(1) + ' times faster!');

    ig.system.stopRunLoop();
}

Here's a sample run (in latest version of Chrome v23):
***Google***
start 1353681314920
stop 1353681314957
elapsed 37
***Impact***
start 1353681314964
stop 1353681316888
elapsed 1924
Google is 52 times faster! 

7 years ago by amadeus

On the subject of high performance JS, I created a 'Class' system that has a very similar API to MooTools (and by proxy, Impact's) however it's super light weight and creates no closures.

It does however have a couple pitfalls, mostly related to creating sub objects on your prototype which need to be manually re-generated on the constructor call.

A quick example of performance:

http://jsperf.com/atlas-class-tests

It carries no performance impact vs a straight function, however it still provides a nice clean API for generating 'classes'.

I may look at porting this into an Impact Utilities project, since it is part of an internal library I use for personal projects that includes a hand full of useful stuff (Class api, object implement, extends, browser compatibility, dom manipulation, etc) and it all comes in under 10kb gzipped.

7 years ago by lachsen

In case anybody is interested:
I created a collection of helper functions to do vectore computations some time ago.
Those functions operator on generic objects with "x" and "y" member. Event if the object does not contain any of those members, they simply assume the value 0.
Most functions have the option to generate a new object or modify one of the given vectors.

The way those methods are used is not the most convenient (there are not nice to chain), however, there are two advantages:
1. They can be efficently inlined using closure compiler(or rather a variant of closure compiler that supports forced inline: https://github.com/bramstein/closure-compiler-inline )
2. They are not bound to any vector class and can be applied to generic objects, things you usually get from assets (in JSON format) etc.

Anyway, here's the code:
// Vector tools

var Vec2 = {};
/**
 * @inline
 * @param otherVec
 */
Vec2.create = function(otherVec){
    var res = {};
    res.x = (otherVec && otherVec.x || 0);
    res.y = (otherVec && otherVec.y || 0);
    return res;
};
/**
 * @inline
 * @param x
 * @param y
 */
Vec2.createC = function(x,y){
    var res = {};
    res.x = (x || 0);
    res.y = (y || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param v2
 */
Vec2.assign = function(v1, v2){
    v1.x = (v2.x || 0);
    v1.y = (v2.y || 0);
    return v1;
};
/**
 * @inline
 * @param v
 * @param x
 * @param y
 */
Vec2.assignC = function(v, x, y){
    v.x = (x || 0);
    v.y = (y || 0);
    return v;
};
/**
 * @inline
 * @param v1
 * @param v2
 * @param {boolean=} copy
 */
Vec2.add = function(v1, v2, copy){
    var res = copy || false ? {} : v1;
    res.x = (v1.x || 0) + (v2.x || 0);
    res.y = (v1.y || 0) + (v2.y || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param x
 * @param y
 * @param {boolean=} copy
 */
Vec2.addC = function(v1, x, y, copy){
    var res = copy || false ? {} : v1;
    y = y === undefined || y === null ? x: y;
    res.x = (v1.x || 0) + (x || 0);
    res.y = (v1.y || 0) + (y || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param v2
 * @param {boolean=} copy
 */
Vec2.sub = function(v1, v2, copy){
    var res = copy || false ? {} : v1;
    res.x = (v1.x || 0) - (v2.x || 0);
    res.y = (v1.y || 0) - (v2.y || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param x
 * @param y
 * @param {boolean=} copy
 */
Vec2.subC = function(v1, x, y, copy){
    var res = copy ? {} : v1;
    y = y === undefined || y === null ? x: y;
    res.x = (v1.x || 0) - (x || 0);
    res.y = (v1.y || 0) - (y || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param v2
 * @param {boolean=} copy
 */
Vec2.mul = function(v1, v2, copy){
    var res = copy || false ? {} : v1;
    res.x = (v1.x || 0) * (v2.x || 0);
    res.y = (v1.y || 0) * (v2.y || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param x
 * @param y
 * @param {boolean=} copy
 */
Vec2.mulC = function(v1, x, y, copy){
    var res = copy || false ? {} : v1;
    y = y === undefined || y === null ? x: y;
    res.x = (v1.x || 0) * (x || 0);
    res.y = (v1.y || 0) * (y || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param f
 * @param {boolean=} copy
 */
Vec2.mulF = function(v1, f, copy){
    var res = copy || false ? {} : v1;
    res.x = (v1.x || 0) * (f || 0);
    res.y = (v1.y || 0) * (f || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param v2
 * @param {boolean=} copy
 */
Vec2.div = function(v1, v2, copy){
    var res = copy || false ? {} : v1;
    res.x = (v1.x || 0) / (v2.x || 0);
    res.y = (v1.y || 0) / (v2.y || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param x
 * @param y
 * @param {boolean=} copy
 */
Vec2.divC = function(v1, x, y, copy){
    var res = copy || false ? {} : v1;
    y = y === undefined || y === null ? x: y;
    res.x = (v1.x || 0) / (x || 0);
    res.y = (v1.y || 0) / (y || 0);
    return res;
};
/**
 * @inline
 * @param v1
 * @param v2
 */
Vec2.dot = function(v1, v2){
    return (v1.x || 0)* (v2.x || 0) + (v1.y || 0)*(v2.y || 0);
};
/**
 * @inline
 * @param v1
 * @param v2
 */
Vec2.dotR = function(v1, v2){
    return  -(v1.y || 0) * (v2.x || 0) + (v1.x || 0) * (v2.y || 0);
};
/**
 * @inline
 * @param v
 * @param newLength
 * @param {boolean=} copy
 */
Vec2.length = function(v, newLength, copy){
    var oldLength = Math.sqrt((v.x || 0)*(v.x || 0) + (v.y || 0)* (v.y || 0));
    if(newLength){
        return Vec2.mulC(v, oldLength ? newLength / oldLength : 1, null, copy);
    }
    else
        return oldLength;
};
/**
 * @inline
 * @param v
 * @param min
 * @param max
 * @param {boolean=} copy
 */
Vec2.limit = function(v, min, max, copy){
    var length = Vec2.length(v);
    if(length > max){
        return Vec2.mulC(v, max / length, null, copy);
    }
    else if(length < min){
        return Vec2.mulC(v, min / length, null, copy);
    }
    else{
        return copy || false ? Vec2.create(v) : v;
    }
};
/**
 * @inline
 * @param v
 * @param {boolean=} copy
 */
Vec2.normalize = function(v, copy){
    return Vec2.length(v, 1, copy);
};
/**
 * @inline
 * @param v
 */
Vec2.clockangle = function(v){
    var result = Math.acos(-(v.y || 0) / Vec2.length(v) );
    if(v.x < 0) result = 2*Math.PI - result;
    return result || 0;
};
/**
 * @inline
 * @param v1
 * @param v2
 */
Vec2.angle = function(v1, v2)
{
    var result = Math.acos(  Vec2.dot(v1,v2)  / ( Vec2.length(v1)*Vec2.length(v2) ));
    return result || 0;
};
/**
 * @inline
 * @param v
 * @param angle
 * @param {boolean=} copy
 */
Vec2.rotate = function(v, angle, copy){
    var res = copy || false ? {} : v;
    var x = v.x || 0;
    res.x = Math.cos(angle) * x + Math.sin(angle) * (v.y || 0);
    res.y = Math.sin(-angle) * x + Math.cos(angle) * (v.y || 0);
    return res;
};
/**
 * @inline
 * @param v
 * @param {boolean=} copy
 */
Vec2.rotate90CW = function(v, copy)
{
    var res = copy || false ? {} : v;
    var x = (v.x || 0);
    res.x = (v.y || 0);
    res.y = -x ;
    return res;
};
/**
 * @inline
 * @param v
 * @param {boolean=} copy
 */
Vec2.rotate90CCW = function(v, copy)
{
    var res = copy || false ? {} : v;
    var x = (v.x || 0);
    res.x = -(v.y || 0);
    res.y = x;
    return res;
};
/**
 * @inline
 * @param v
 * @param {boolean=} copy
 */
Vec2.flip = function(v, copy){
    var res = copy || false ? {} : v;
    res.x = -v.x;
    res.y = -v.y;
    return res;
};
/**
 * @inline
 * @param v1
 * @param v2
 */
Vec2.equal = function(v1,v2){
    return v1.x == v2.x && v1.y == v2.y;
};
/**
 * @inline
 * @param v1
 * @param v2
 */
Vec2.distance = function(v1,v2){
    var x = ((v1.x - v2.x) || 0);
    var y = ((v1.y - v2.y) || 0);
    return  Math.sqrt( x * x + y * y);
};
/**
 * @inline
 * @param v1
 * @param v2
 * @param i
 * @param {boolean=} copy
 */
Vec2.lerp = function(v1,v2, i, copy){
    var res = copy || false ? {} : v1;
    res.x = (v1.x || 0)*(1-i) + (v2.x || 0)*i;
    res.y = (v1.y || 0)*(1-i) + (v2.y || 0)*i;
    return res;
}
Page 1 of 1
« first « previous next › last »