diff --git a/engine/core/vec2.go b/engine/core/vec2.go new file mode 100644 index 0000000..38357a7 --- /dev/null +++ b/engine/core/vec2.go @@ -0,0 +1,125 @@ +// Vec2 is a generic 2D integer vector. +// +// It supports different underlying integer types (e.g., int, uint8) via type +// parameters. +// +// For float-based positions, use rl.Vector2 instead. +package core + +import ( + "math" + + rl "github.com/gen2brain/raylib-go/raylib" + "golang.org/x/exp/constraints" +) + +type Vec2[T constraints.Integer] struct { + X, Y T +} + +func NewVec2[T constraints.Integer](x, y T) Vec2[T] { + return Vec2[T]{ + X: x, + Y: y, + } +} + +func Vec2From[T constraints.Integer, Y constraints.Integer](v Vec2[T]) Vec2[Y] { + return Vec2[Y]{ + X: Y(v.X), + Y: Y(v.Y), + } +} + +func Vec2FromRL[T constraints.Integer](v rl.Vector2) Vec2[T] { + return Vec2[T]{ + X: T(v.X), + Y: T(v.Y), + } +} + +func (v1 Vec2[T]) Add(v2 Vec2[T]) Vec2[T] { + return Vec2[T]{ + X: v1.X + v2.X, + Y: v1.Y + v2.Y, + } +} + +func (v1 Vec2[T]) Subtract(v2 Vec2[T]) Vec2[T] { + return Vec2[T]{ + X: v1.X - v2.X, + Y: v1.Y - v2.Y, + } +} + +func AbsDist[T constraints.Integer](a T, b T) T { + if a > b { + return a - b + } + return b - a +} + +func Abs[T constraints.Integer](value T) T { + if value < T(0) { + return -value + } + return value +} + +func (v1 Vec2[T]) Abs() Vec2[T] { + return Vec2[T]{ + X: Abs(v1.X), + Y: Abs(v1.Y), + } +} + +func (v1 Vec2[T]) SubtractABS(v2 Vec2[T]) Vec2[T] { + return Vec2[T]{ + X: AbsDist(v1.X, v2.X), + Y: AbsDist(v1.Y, v2.Y), + } +} + +func (v Vec2[T]) Scale(value float32) Vec2[T] { + return Vec2[T]{ + X: T(float32(v.X) * value), + Y: T(float32(v.Y) * value), + } +} + +func (v1 Vec2[T]) Distance(v2 Vec2[T]) float64 { + abs := v1.SubtractABS(v2) + dx := float64(abs.X) + dy := float64(abs.Y) + return math.Sqrt((dx * dx) + (dy * dy)) +} + +// ToRL converts the Vec2 to a rl.Vector2 (float32), which is compatible +// with rendering and physics systems. +func (v Vec2[T]) ToRL() rl.Vector2 { + return rl.NewVector2(float32(v.X), float32(v.Y)) +} + +// AddRL adds a float-based rl.Vector2 to the current Vec2, +// returning a new Vec2 after converting the result back to type T. +// Fractional parts are truncated. +func (v1 Vec2[T]) AddRL(v2 rl.Vector2) Vec2[T] { + v1.X += T(v2.X) + v1.Y += T(v2.Y) + return v1 +} + +// Common Vec2 type aliases for convenience. +type ( + Vec2i = Vec2[int] + Vec2i8 = Vec2[int8] + Vec2i16 = Vec2[int16] + Vec2i32 = Vec2[int32] + Vec2i64 = Vec2[int64] + + Vec2u = Vec2[uint] + Vec2u8 = Vec2[uint8] + Vec2u16 = Vec2[uint16] + Vec2u32 = Vec2[uint32] + Vec2u64 = Vec2[uint64] +)