Manual/ Referencia de la API

Quat (rotaciones)

Rotaciones sin bloqueo de cardán: mirar hacia, girar con velocidad fija, interpolar.

Un Quat (cuaternión) guarda una rotación sin los problemas de los ángulos de Euler (bloqueo de cardán, saltos al pasar de 359 a 0 grados). Es lo que usa el motor por dentro. No hace falta entender sus números: se crean con las funciones de abajo y se combinan con *.

local q = Quat.euler(0, 90, 0)          -- 90 grados sobre Y
local dir = q * Vec3.forward             -- girar un vector: (-1, 0, 0)
local dos = q * Quat.angleAxis(30, Vec3.right)  -- primero 30 sobre X, luego q

self.entity.quaternion = Quat.lookRotation(objetivo - self.entity.position)
print(self.entity.quaternion:toEuler())  -- en grados, como entity.rotation

Crear rotaciones

FunciónDescripción
Quat.identity, Quat()Sin giro.
Quat.euler(x, y, z), Quat.euler(Vec3)Desde grados, en el mismo orden que entity.rotation (Z, luego X, luego Y, como Unity).
Quat.angleAxis(grados, eje)Un giro de tantos grados alrededor de un eje.
Quat.lookRotation(dirección [, arriba])La rotación que mira hacia dirección (su forward apunta allí). arriba es Vec3.up si no se da.
Quat.fromToRotation(desde, hasta)El giro más corto que lleva una dirección a otra (por ejemplo, alinear con la normal del suelo).
Quat(x, y, z, w)Con sus cuatro números (casi nunca hace falta).

Combinar y girar vectores

OperaciónDescripción
q * vGira el vector v.
q1 * q2Una rotación tras otra: primero q2 y después q1.
q:inverse()La rotación contraria (q:inverse() * q = sin giro).
q:forward(), q:right(), q:up()Los ejes de esa rotación.
q:toEuler()Grados (Vec3), como entity.rotation.
q:normalized(), q:copy()Normalizada y copia independiente.
a == b, tostring(q)Misma rotación (con un margen pequeño) y texto.

Interpolar y medir

FunciónDescripción
Quat.slerp(a, b, t)Rotación intermedia a velocidad constante (t de 0 a 1).
Quat.lerp(a, b, t)Parecido y más rápido; para ángulos pequeños no se nota la diferencia.
Quat.rotateTowards(desde, hasta, grados)Gira hacia hasta como mucho grados: una velocidad de giro fija.
Quat.angle(a, b)Grados que separan dos rotaciones.
Quat.dot(a, b)Producto escalar (1 o -1: la misma rotación).

En una entidad

entity.quaternion es el giro local de la entidad como Quat (lectura y escritura). Es lo mismo que entity.rotation, pero sin pasar por grados: úsalo para interpolar o acumular giros sin saltos.

-- Girar 90 grados por segundo sobre su propio eje Y (acumulando sin errores)
function Molino:Update(dt)
    self.entity.quaternion = self.entity.quaternion * Quat.angleAxis(90 * dt, Vec3.up)
end

Ejemplo: torreta que apunta

Gira hacia el jugador con una velocidad máxima y dispara cuando lo tiene casi delante.

Torreta.lua

local Torreta = { properties = { velocidadGiro = 120.0, alcance = 25.0 } }

function Torreta:Start()
    self.jugador = Scene.find("Jugador")
end

function Torreta:Update(dt)
    if not self.jugador then return end
    local hacia = self.jugador.position - self.entity.position
    if hacia:length() > self.alcance then return end

    local objetivo = Quat.lookRotation(hacia)
    self.entity.quaternion = Quat.rotateTowards(self.entity.quaternion, objetivo, self.velocidadGiro * dt)

    if Quat.angle(self.entity.quaternion, objetivo) < 3 then
        Debug.log("¡Fuego!")
    end
end

return Torreta
La torreta debe estar en la raíz de la escena (o su padre sin girar): quaternion es el giro local. Todos los ángulos de la API van en grados; solo Mathf.sin, Mathf.cos... usan radianes, como en math.

¿Algo no queda claro o falta algo? Pregunta en el Discord.