Vec

·veu .md ↗·chatgpt ↗·claude ↗

Codi

export class Vec {
    x: number
    y: number
    z: number

    constructor(x: number = 0, y: number = 0, z: number = 0) {
        this.x = x
        this.y = y
        this.z = z
    }

    copy(v: Vec): Vec {
        this.x = v.x
        this.y = v.y
        this.z = v.z
        return this
    }

    set(x: number, y: number, z: number = 0): Vec {
        this.x = x
        this.y = y
        this.z = z

        return this
    }

    clone(): Vec {
        return new Vec(this.x, this.y, this.z)
    }

    add(v: Vec): Vec {
        this.x += v.x
        this.y += v.y
        this.z += v.z

        return this
    }

    sub(v: Vec): Vec {
        this.x -= v.x
        this.y -= v.y
        this.z -= v.z

        return this
    }

    mul(v: Vec): Vec {
        this.x *= v.x
        this.y *= v.y
        this.z *= v.z

        return this
    }

    div(v: Vec): Vec {
        this.x /= v.x
        this.y /= v.y
        this.z /= v.z

        return this
    }

    scale(scl: number): Vec {
        this.x *= scl
        this.y *= scl
        this.z *= scl

        return this
    }

    length(): number {
        return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z)
    }

    lerp(target: Vec, alpha: number): Vec {
        this.x = MathUtils.lerp(this.x, target.x, alpha)
        this.y = MathUtils.lerp(this.y, target.y, alpha)
        this.z = MathUtils.lerp(this.z, target.z, alpha)

        return this
    }

    equals(v: Vec): boolean {
        return this.x === v.x && this.y === v.y && this.z === v.z
    }

    dot(v: Vec): number {
        return this.x * v.x + this.y * v.y + this.z * v.z
    }

    distanceTo(v: Vec): Vec {
        return this.clone().sub(v).length()
    }

    normalize(): Vec {
        const L = this.length()
        if (L === 0) return this

        this.x /= L
        this.y /= L
        this.z /= L

        return this
    }
}

Propietats

PropietatDescripció
xComponent horitzontal del vector.
yComponent vertical del vector.
zComponent de profunditat (opcional).

Mètodes principals

MètodeDescripció
copy(v)Copia els valors d'un altre vector.
set(x, y, z)Assigna nous valors ràpidament.
clone()Retorna una còpia del vector actual.
add(v) / sub(v)Suma o resta un altre vector.
mul(v) / div(v)Multiplica o divideix component a component.
scale(s)Escala el vector per un escalar.
length()Retorna la magnitud del vector.
lerp(target, alpha)Interpola entre el vector actual i l'objectiu.
equals(v)Compara si tots dos vectors són idèntics.
dot(v)Calcula el producte escalar.
distanceTo(v)Distància entre dos vectors.
normalize()Normalitza el vector perquè la seva longitud sigui 1.

Exemple amb Nuxt

<script setup lang="ts">
// Pots col·locar la classe a ~/utils/math/vec.ts i importar-la aquí.
import { Vec } from '~/utils/math/vec'

const pointer = ref(new Vec())
const target = new Vec()
let frame: number | null = null

const animate = () => {
  pointer.value.lerp(target, 0.15)
  frame = requestAnimationFrame(animate)
}

const handlePointer = (event: PointerEvent) => {
  target.set(event.clientX, event.clientY)
}

const styleCursor = computed(() => ({
  transform: `translate3d(${pointer.value.x}px, ${pointer.value.y}px, 0)`
}))

onMounted(() => {
  window.addEventListener('pointermove', handlePointer)
  frame = requestAnimationFrame(animate)
})

onUnmounted(() => {
  window.removeEventListener('pointermove', handlePointer)
  if (frame) cancelAnimationFrame(frame)
})
</script>

<template>
  <div class="cursor" :style="styleCursor">Vec</div>
</template>

<style scoped>
.cursor {
  position: fixed;
  inset: 0;
  width: 60px;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background: rgba(37, 99, 235, 0.2);
  border: 1px solid #2563eb;
  border-radius: 999px;
  pointer-events: none;
  font-weight: 600;
}
</style>