struct Eagle::Vec2

Overview

A 2D vector of Float32, used for positions, velocities, sizes and directions.

Vec2 is an immutable value type. Every operation returns a new vector, so you write pos += vel * dt rather than mutating in place. Eagle's 2D space is y-down, matching the screen: Vec2::UP is (0, -1).

Build one with v2(x, y), Vec2.new(x, y), Vec2.new(n) for (n, n), or Vec2.from_angle(radians, length).

pos = v2(100, 100)
vel = Vec2.from_angle(Mathf.deg2rad(30), 200) # 200 px/s at 30 degrees
pos += vel * 0.016

to_mouse = Input.mouse - pos
if to_mouse.length < 50
  pos -= to_mouse.normalized * 5 # flee
end

g.circle(pos, 8)

Arithmetic works component-wise between vectors (a * b) and with scalars on either side (v * 2, 2 * v).

Defined in:

eagle/math/vec2.cr

Constant Summary

DOWN = Vec2.new(0, 1)

(0, 1).

LEFT = Vec2.new(-1, 0)

(-1, 0).

ONE = Vec2.new(1, 1)

(1, 1), the identity for scaling.

RIGHT = Vec2.new(1, 0)

(1, 0). Also the direction a Node2D with rotation 0 faces.

UP = Vec2.new(0, -1)

(0, -1). Up on screen, because y grows downward.

ZERO = Vec2.new(0, 0)

(0, 0).

Constructors

Instance Method Summary

Constructor Detail

def self.from_angle(radians : Number, length : Number = 1) : Vec2 #

A vector pointing at radians with the given length. Angle 0 points right, and positive angles turn clockwise on screen.

ship = Node2D.new(rotation: Mathf.deg2rad(90))
bullet_vel = Vec2.from_angle(ship.rotation, 600) # => (0, 600), straight down

def self.new(x : Number, y : Number) #

Creates a vector from any two numbers. The shorthand is v2(x, y).


def self.new(v : Number) #

Creates (v, v), which suits uniform scale: Vec2.new(2).


def self.new #

Creates (0, 0).


def self.zero : Vec2 #

Returns (0, 0). Exists so Enumerable#sum works on arrays of vectors.


Instance Method Detail

def *(o : Vec2) : Vec2 #

Component-wise product.


def *(s : Number) : Vec2 #

Scales both components.


def +(o : Vec2) : Vec2 #

Component-wise sum.


def + #

Returns self.


def -(o : Vec2) : Vec2 #

Component-wise difference.


def - : Vec2 #

The vector pointing the opposite way.


def /(o : Vec2) : Vec2 #

Component-wise quotient.


def /(s : Number) : Vec2 #

Divides both components.


def ==(o : Vec2) : Bool #

Exact equality. Use #approx? for computed values.


def abs : Vec2 #

Component-wise absolute value.


def angle : Float32 #

The vector's angle in radians, from the +x axis.


def angle_to(o : Vec2) : Float32 #

Signed angle from this vector to o, in -π..π.


def approx?(o : Vec2, eps = 1e-5) : Bool #

True when both components are within eps of o's.


def ceil : Vec2 #

Component-wise ceiling.


def clamp(lo : Vec2, hi : Vec2) : Vec2 #

Clamps each component between lo and hi, for keeping a player inside the arena.

pos = v2(-20, 900)
pos = pos.clamp(Vec2::ZERO, Window.size) # stays on screen

def cross(o : Vec2) : Float32 #

2D cross product (the z of the 3D cross). Its sign tells you which side of this vector o lies on.


def distance(o : Vec2) : Float32 #

Distance to another point.


def distance_squared(o : Vec2) : Float32 #

Squared distance to another point.


def dot(o : Vec2) : Float32 #

Dot product. Positive when the vectors point the same way, zero when perpendicular, and negative when opposed. Useful for "is the enemy in front of me?".


def floor : Vec2 #

Component-wise floor, for snapping to whole pixels or grid cells.


def hash(h) #
Description copied from struct Struct

See Object#hash(hasher)


def inspect(io : IO) : Nil #
Description copied from struct Struct

Appends this struct's name and instance variables names and values to the given IO.

struct Point
  def initialize(@x : Int32, @y : Int32)
  end
end

p1 = Point.new 1, 2
p1.to_s    # "Point(@x=1, @y=2)"
p1.inspect # "Point(@x=1, @y=2)"

def length : Float32 #

Length (magnitude). Prefer #length_squared when you only compare distances.


def length_squared : Float32 #

Squared length. Cheaper than #length because it skips the square root.

player, enemy = v2(0, 0), v2(60, 80)
in_range = (enemy - player).length_squared < 100 * 100 # => true

def lerp(o : Vec2, t : Number) : Vec2 #

Linear interpolation toward o. For smooth following that doesn't depend on frame rate, use Mathf.damp instead.


def limit(max : Number) : Vec2 #

Clamps the length to at most max and keeps the direction. Good for capping speed.

vel, accel = v2(250, 0), v2(0, 900)
vel = (vel + accel * dt).limit(300)

def max(o : Vec2) : Vec2 #

Component-wise maximum.


def min(o : Vec2) : Vec2 #

Component-wise minimum.


def normalized : Vec2 #

A vector in the same direction with length 1. The zero vector stays zero instead of producing NaN.


def perpendicular : Vec2 #

The vector rotated 90°. Use it for normals of 2D edges or for strafing directions.


def project(onto : Vec2) : Vec2 #

The component of this vector along onto.


def reflect(normal : Vec2) : Vec2 #

Mirrors the vector across a surface with unit normal. This is how a ball bounces off a wall.

vel = v2(120, 300)
vel = vel.reflect(Vec2::UP) # hit the floor => (120, -300)

def rotated(radians : Number) : Vec2 #

The vector rotated by radians (clockwise on screen).


def round : Vec2 #

Component-wise rounding.


def to_a #

Returns [x, y].


def to_s(io : IO) : Nil #
Description copied from struct Struct

Same as #inspect(io).


def to_vec3(z : Number = 0) : Vec3 #

Extends to 3D with the given z.


def x : Float32 #

Horizontal component.


def x=(x : Float32) #

Horizontal component.


def y : Float32 #

Vertical component. Grows downward on screen.


def y=(y : Float32) #

Vertical component. Grows downward on screen.


def zero? : Bool #

True for (0, 0) exactly.