Last active
July 10, 2019 21:45
-
-
Save 01010111/8ed40ff86454bcbfc253333451726837 to your computer and use it in GitHub Desktop.
Vector class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Math; | |
abstract Vec2(Array<Float>) | |
{ | |
public static var UP (default, never):Vec2 = [0, -1]; | |
public static var DOWN (default, never):Vec2 = [0, 1]; | |
public static var LEFT (default, never):Vec2 = [-1, 0]; | |
public static var RIGHT (default, never):Vec2 = [1, 0]; | |
// Utility | |
static var epsilon:Float = 1e-8; | |
static function zero(n:Float):Float return n.abs() <= epsilon ? 0 : n; | |
public static function run_tests() Vec2Tests.run(); | |
// Array creation/access | |
@:from static function from_array_float(input:Array<Float>) return new Vec2(input[0], input[1]); | |
@:from static function from_array_int(input:Array<Int>) return new Vec2(input[0], input[1]); | |
@:arrayAccess function arr_set(n:Int, v:Float) n < 0 || n > 1 ? return : this[n] = v; | |
@:arrayAccess function arr_get(n:Int):Float return this[n.min(1).max(0).floor()]; | |
// Pooling | |
static var pool:Array<Vec2> = []; | |
public static function get(x:Float = 0, y:Float = 0):Vec2 return pool.length > 0 ? pool.shift().set(x, y) : new Vec2(x, y); | |
public inline function put() | |
{ | |
pool.push(this); | |
this = null; | |
} | |
function new(x:Float = 0, y:Float = 0) this = [x, y]; | |
public inline function set(x:Float = 0, y:Float = 0):Vec2 | |
{ | |
this[0] = zero(x); | |
this[1] = zero(y); | |
return this; | |
} | |
public var x (get, set):Float; | |
function get_x() return this[0]; | |
function set_x(v) return this[0] = v; | |
public var y (get, set):Float; | |
function get_y() return this[1]; | |
function set_y(v) return this[1] = v; | |
public var xx (get, never):Vec2; | |
function get_xx() return Vec2.get(x, x); | |
public var yy (get, never):Vec2; | |
function get_yy() return Vec2.get(y, y); | |
public var length (get, set):Float; | |
inline function get_length() return (x*x + y*y).sqrt(); | |
inline function set_length(v:Float) | |
{ | |
normalize(); | |
scale(v); | |
return v; | |
} | |
public var angle (get, set):Float; | |
function get_angle() return ((Math.atan2(y, x) * (180 / Math.PI)) % 360 + 360) % 360; | |
function set_angle(v:Float) | |
{ | |
v *= (Math.PI / 180); | |
set(length * v.cos(), length * v.sin()); | |
return v; | |
} | |
// These functions modify the vector in place! | |
public inline function copy_from(v:Vec2):Vec2 return set(v.x, v.y); | |
public inline function normalize():Vec2 return set(x / length, y / length); | |
public inline function scale(n:Float):Vec2 return set(x * n, y * n); | |
public inline function copy():Vec2 return Vec2.get(x, y); | |
public inline function equals(v:Vec2):Bool return x == v.x && y == v.y; | |
public inline function dot(v:Vec2):Float return zero(x * v.x + y * v.y); | |
public inline function cross(v:Vec2):Float return zero(x * v.y - y * v.x); | |
public inline function facing(v:Vec2):Float return zero(x / length * v.x / v.length + y / length * v.y / v.length); | |
public inline function distance(v:Vec2):Float return (v - this).length; | |
public inline function toString():String return 'x: $x | y: $y | length: $length | angle: $angle'; | |
// Operator Overloads | |
@:op(A + B) static function add(v1:Vec2, v2:Vec2):Vec2 return Vec2.get(v1.x + v2.x, v1.y + v2.y); | |
@:op(A + B) static function add_f(v:Vec2, n:Float):Vec2 return Vec2.get(v.x + n, v.y + n); | |
@:op(A - B) static function subtract(v1:Vec2, v2:Vec2):Vec2 return Vec2.get(v1.x - v2.x, v1.y - v2.y); | |
@:op(A - B) static function subtract_f(v:Vec2, n:Float):Vec2 return Vec2.get(v.x - n, v.y - n); | |
@:op(A * B) static function multiply(v1:Vec2, v2:Vec2):Vec2 return Vec2.get(v1.x * v2.x, v1.y * v2.y); | |
@:op(A * B) static function multiply_f(v:Vec2, n:Float):Vec2 return Vec2.get(v.x * n, v.y * n); | |
@:op(A / B) static function divide(v1:Vec2, v2:Vec2):Vec2 return Vec2.get(v1.x / v2.x, v1.y / v2.y); | |
@:op(A / B) static function divide_f(v:Vec2, n:Float):Vec2 return Vec2.get(v.x / n, v.y / n); | |
@:op(A % B) static function mod(v1:Vec2, v2:Vec2):Vec2 return Vec2.get(v1.x % v2.x, v1.y % v2.y); | |
@:op(A % B) static function mod_f(v:Vec2, n:Float):Vec2 return Vec2.get(v.x % n, v.y % n); | |
} | |
private class Vec2Tests | |
{ | |
public static function run() | |
{ | |
var pass = true; | |
pass = pass && vector_variables(); | |
pass = pass && vector_methods(); | |
pass = pass && operators(); | |
if (pass) trace('All tests passsed!'); | |
} | |
static function vector_variables():Bool | |
{ | |
var pass = true; | |
var v1 = Vec2.get(1, 0); | |
var v2 = Vec2.get().copy_from(v1); | |
var v3 = Vec2.get().copy_from(v1); | |
v2.angle += 90; | |
v3.length *= 2; | |
pass = pass && eval('Angle', v1.angle == 0 && v2.angle == 90); | |
pass = pass && eval('Length', v1.length == v2.length && v3.length == v1.length * 2); | |
return pass; | |
} | |
static function vector_methods():Bool | |
{ | |
var pass = true; | |
var v1 = Vec2.get(1, 2); | |
var v2 = Vec2.get().copy_from(v1); | |
v2.angle += 90; | |
pass = pass && eval('Copy', v1.copy().equals(v1) && v2.copy() != v2); | |
pass = pass && eval('Copy From', Vec2.get().copy_from(v1).equals(v1)); | |
pass = pass && eval('Equals', v1.equals([1, 2])); | |
pass = pass && eval('Normalize', Vec2.get(20, 50).normalize().length == 1); | |
pass = pass && eval('Scale', v1.scale(2).equals([2, 4])); | |
pass = pass && eval('Dot Product', Vec2.UP.dot(Vec2.RIGHT) == 0); | |
pass = pass && eval('Cross Product', Vec2.RIGHT.cross(Vec2.DOWN) == 1); | |
pass = pass && eval('Facing', v1.facing(v2) == 0); | |
pass = pass && eval('Distance', Vec2.get(0, 3).distance([4, 0]) == 5); | |
return pass; | |
} | |
static function operators():Bool | |
{ | |
var pass = true; | |
pass = pass && eval('Vector Addition', (Vec2.DOWN + Vec2.RIGHT).equals([1, 1])); | |
pass = pass && eval('Vector Subtraction', (Vec2.DOWN - Vec2.LEFT).equals([1, 1])); | |
pass = pass && eval('Vector Multiplication', (Vec2.get(1, 1) * [2, 2]).equals([2, 2])); | |
pass = pass && eval('Vector Division', (Vec2.get(4, 4) / [2, 2]).equals([2, 2])); | |
pass = pass && eval('Vector Modulo', (Vec2.get(3, 4) % [2, 2]).equals([1, 0])); | |
pass = pass && eval('Float Addition', (Vec2.DOWN + 1).equals([1, 2])); | |
pass = pass && eval('Float Subtraction', (Vec2.DOWN - 1).equals([-1, 0])); | |
pass = pass && eval('Float Multiplication', (Vec2.get(1, 1) * 2).equals([2, 2])); | |
pass = pass && eval('Float Division', (Vec2.get(4, 4) / 2).equals([2, 2])); | |
pass = pass && eval('Float Modulo', (Vec2.get(3, 4) % 2).equals([1, 0])); | |
return pass; | |
} | |
static function eval(name:String, exp:Bool) | |
{ | |
if (!exp) trace('$name test failed!'); | |
return exp; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment