GDScript Vectors Cheat Sheet
Quick-reference for Godot 4 vector math. Each section includes copy-ready snippets with inline output comments using real game scenarios.
Creating Vectors
Vector2 holds x/y, Vector3 holds x/y/z. Both are value types (passed by copy).
var pos := Vector2(100, 200)
var origin := Vector2.ZERO # => (0, 0)
var right := Vector2.RIGHT # => (1, 0)
var up := Vector2.UP # => (0, -1) # Y-down in Godot 2Dvar pos := Vector3(1, 2, 3)
var origin := Vector3.ZERO # => (0, 0, 0)
var forward := Vector3.FORWARD # => (0, 0, -1) # -Z is forward# Create a direction vector from an angle (radians)
var angle := deg_to_rad(45.0)
var dir := Vector2.from_angle(angle)
# dir => roughly (0.707, 0.707)Vector Arithmetic
Vectors support component-wise addition, subtraction, and scalar multiplication.
var a := Vector2(3, 4)
var b := Vector2(1, 2)
var sum := a + b # => (4, 6)
var diff := a - b # => (2, 2)var v := Vector2(3, 4)
var scaled := v * 2.0 # => (6, 8)
var halved := v / 2.0 # => (1.5, 2)# In _physics_process:
var speed := 200.0
var direction := Vector2.RIGHT
velocity = direction * speed
# CharacterBody2D.move_and_slide() uses velocity automaticallyLength and Distance
Use length() for magnitude, distance_to() between two points. Prefer squared versions when comparing.
var v := Vector2(3, 4)
v.length() # => 5.0
v.length_squared() # => 25.0 (avoids sqrt — faster)var player_pos := Vector2(100, 200)
var enemy_pos := Vector2(400, 600)
var dist := player_pos.distance_to(enemy_pos)
# dist => 500.0var detection_range := 300.0
# FAST: compare squared distances (no sqrt)
if global_position.distance_squared_to(target.global_position) < detection_range ** 2:
chase_target()Always use distance_squared_to() in _process/_physics_process for performance. Avoid sqrt every frame.
Normalizing Vectors
A normalized vector has length 1. Essential for consistent movement speed regardless of direction.
var raw := Vector2(3, 4)
var unit := raw.normalized()
# unit => (0.6, 0.8) length => 1.0# Without normalize: diagonal is ~1.41x faster
var input := Vector2(
Input.get_axis("move_left", "move_right"),
Input.get_axis("move_up", "move_down")
)
# Normalize so diagonal speed matches cardinal
if input.length() > 0:
input = input.normalized()
velocity = input * speedvar dir := Vector2(1, 0)
dir.is_normalized() # => true
var raw := Vector2(3, 4)
raw.is_normalized() # => falseDirection and Aiming
direction_to() returns the normalized direction from one point to another. Perfect for aiming and AI.
var dir := global_position.direction_to(player.global_position)
# dir is already normalized — length 1
velocity = dir * chase_speedfunc shoot() -> void:
var bullet := bullet_scene.instantiate()
var aim_dir := global_position.direction_to(get_global_mouse_position())
bullet.direction = aim_dir
get_parent().add_child(bullet)# Point the sprite toward the enemy
var dir := global_position.direction_to(enemy.global_position)
rotation = dir.angle() # angle() returns radiansDot Product
The dot product tells you how aligned two vectors are. 1 = same direction, 0 = perpendicular, -1 = opposite.
var a := Vector2(1, 0)
var b := Vector2(0, 1)
a.dot(b) # => 0.0 (perpendicular)
var c := Vector2(1, 0)
a.dot(c) # => 1.0 (same direction)var facing := Vector2.from_angle(rotation)
var to_enemy := global_position.direction_to(enemy.global_position)
if facing.dot(to_enemy) > 0.5: # ~60 degree cone
can_see_enemy = truevar facing := transform.basis_xform(Vector2.RIGHT)
var to_target := global_position.direction_to(target.global_position)
if facing.dot(to_target) < 0:
# Target is behind us — can't attack
turn_around()Cross Product (Vector3)
The cross product returns a vector perpendicular to both inputs. Only available on Vector3.
var right := Vector3(1, 0, 0)
var up := Vector3(0, 1, 0)
var forward := right.cross(up)
# forward => (0, 0, 1)# Given three vertices of a triangle
var edge1 := vertex_b - vertex_a
var edge2 := vertex_c - vertex_a
var normal := edge1.cross(edge2).normalized()# Vector2 has cross() returning a float (the Z component)
var forward := Vector2(1, 0)
var to_target := Vector2(1, 1).normalized()
var cross := forward.cross(to_target)
# cross > 0 => target is to the left
# cross < 0 => target is to the rightLerp and Smooth Movement
lerp() interpolates between two vectors. Use it for smooth camera tracking, UI animations, and easing.
var start := Vector2(0, 0)
var end := Vector2(100, 100)
var mid := start.lerp(end, 0.5)
# mid => (50, 50)# In camera _physics_process:
var target_pos := player.global_position
global_position = global_position.lerp(target_pos, 5.0 * delta)Multiply weight by delta for frame-rate independent smoothing.
func _physics_process(delta: float) -> void:
var target := player.global_position
global_position = global_position.lerp(target, 3.0 * delta)
# Stop jittering when close enough
if global_position.distance_to(target) < 2.0:
global_position = targetAngle Methods
Convert between vectors and angles. All angle methods use radians.
var dir := Vector2(1, 1).normalized()
dir.angle() # => 0.785... (PI/4, i.e. 45 degrees)var a := Vector2.RIGHT
var b := Vector2.UP
a.angle_to(b) # => -1.5708 (-PI/2, i.e. -90 degrees)angle_to() is signed: positive = clockwise in Godot 2D (Y-down).
var dir := Vector2.RIGHT
var rotated := dir.rotated(deg_to_rad(90))
# rotated => roughly (0, 1) — 90 degrees clockwisefunc shoot_spread(count: int, spread_angle: float) -> void:
var base_dir := global_position.direction_to(get_global_mouse_position())
var step := spread_angle / (count - 1)
var start_angle := -spread_angle / 2.0
for i in range(count):
var angle := start_angle + step * i
var dir := base_dir.rotated(deg_to_rad(angle))
spawn_bullet(dir)Bounce, Reflect, and Slide
Built-in methods for physics-style vector operations against surfaces.
var velocity := Vector2(1, -1)
var wall_normal := Vector2(0, 1) # floor
var bounced := velocity.bounce(wall_normal)
# bounced => (1, 1) — reflected off the floorvar velocity := Vector2(1, -1)
var normal := Vector2(0, 1)
var reflected := velocity.reflect(normal)
# reflected => (-1, 1)bounce() is what you usually want for game physics. reflect() flips both components.
# Remove the component going into the wall
var velocity := Vector2(3, -2)
var wall_normal := Vector2(0, 1)
var slid := velocity.slide(wall_normal)
# slid => (3, 0) — slides along the floorCan you write this from memory?
Create a Vector2 called spawn_position with x=100 and y=200 for placing an enemy.