lib_vector
v1.0
24/05/2026
sergio de frutos
Hace unos años (cuando GML incorporó los structs) empecé este script que ha ido migrando entre proyectos por si acaso me da por usar vectores. En realidad despues de iterar un par de veces lo único que aprovecho de los structs es poder llamar a .x e .y en lugar de acceder por índice a un array. La idea era formar una biblioteca bastante amplia, así que algunas de las funciones las escribí solo por si acaso (¡adivina cuáles!).
Todas las funciones devuelven un valor, los parámetros no se alteran de ninguna manera. Quiero querer creer que esto ayuda a evitar cometer errores y tener que pensar dos veces (rollo v.normalized y Vector2.Normalize() en Unity). Hacer versiones internas de estas funciones en el struct es escribir el doble de código y complicar la sintaxis.
No tocado casi 3D en game maker, así que la parte de v3 no la comparto porque no está ni estrenada. Y bueno, ya paro, ahí va.
////// LIGHTWEIGHT VECTORS //////
function v2(_x, _y)
{
return {x: _x, y: _y};
}
#macro v2_left v2(-1, 0)
#macro v2_right v2( 1, 0)
#macro v2_up v2( 0, -1)
#macro v2_down v2( 0, 1)
#macro v2_zero v2( 0, 0)
#macro v2_one v2( 1, 1)
function v2_add(_a, _b)
{
return v2(_a.x + _b.x, _a.y + _b.y);
}
function v2_subtract(_a, _b)
{
return v2(_a.x - _b.x, _a.y - _b.y);
}
function v2_scale(_v, _f)
{
return v2(_v.x * _f, _v.y * _f);
}
function v2_hadamard(_a, _b)
{
return v2(_a.x * _b.x, _a.y * _b.y);
}
function v2_dot(_a, _b)
{
return _a.x*_b.x + _a.y*_b.y;
}
function v2_module(_v)
{
return v2_is_zero(_v) ? 0 : point_distance(0, 0, _v.x, _v.y);
}
function v2_sqrmodule(_v)
{
return _v.x*_v.x + _v.y*_v.y;
}
function v2_direction(_v)
{
return point_direction(0, 0, _v.x, _v.y);
}
function v2_lengthdir(_len, _dir)
{
return v2(lengthdir_x(_len, _dir), lengthdir_y(_len, _dir));
}
function v2_is_zero(_v)
{
return _v.x == 0 and _v.y == 0;
}
function v2_normalized(_v)
{
var norm = v2_module(_v);
return v2_scale(_v, norm == 0 ? 1 : 1/norm);
}
function v2_sign(_v)
{
return v2(sign(_v.x), sign(_v.y));
}
function v2_to_array(_v)
{
var array = array_create(2);
array[0] = _v.x;
array[1] = _v.y;
return array;
}
function v2_from_array(_r)
{
return v2(_r[0], _r[1]);
}
function v2_lerp(_a, _b, _t)
{
return v2(lerp(_a.x, _b.x, _t), lerp(_a.y, _b.y, _t));
}
function v2_inside_unit_circle()
{
return v2_lengthdir(1, random(360));
}
function v2_to_string(_v)
{
return $"[{_v.x}, {_v.y}]";
}
//================================================
¡Ey! ¡Aquí, aquí! Un par de aclaraciones / consejos.
¿Por qué existe v2_sqrmodule()?
A los procesadores antiguos les daban susto las raíces cuadradas. Hoy en día son tan rápidos que la decisión de usarlas o no tiene más que ver con el deber moral de gastar menos recursos que con el propio rendimiento.
Aun así, si solo quieres encontrar qué vector es el más largo, basta con comparar los cuadrados de sus módulos. Hacer la raíz no afecta al resultado. Save the planet, etc.
¿Por qué usas funciones builtin de GML?
Porque supongo que la gente que lo programó sabía lo que hacía mejor que yo. Salvo en un caso: sign() is haunted. Alguna vez he pasado un 0 y me ha devuelto un 1. No recuerdo cuándo ocurrió, pero programé mi propia versión porque me dejé de fiar. Fijo que era un bug por mi parte pero llevo años paranoico.