Skip to content

Vector Angles

A guide to understanding vector angles using SplashKit functions, including dot product, vector angle, and angle between vectors.
Written by:
Last updated: 08 Dec 24

While some Python code has been included in basic functions, full Python code for this tutorial is still in development.


Vector Geometry - Angles

Understanding vector angles is important for creating dynamic and engaging gameplay in 2D games. Whether you’re aiming to align a character with a target, calculating the trajectory of a projectile, or determining the angle of impact in a collision, mastering vector angles will enhance your game’s realism and responsiveness. In this tutorial, we will cover the essential SplashKit functions for calculating vector angles, touch on the mathematical principles behind them, and see practical examples of how to use these concepts.

SplashKit Vector Functions Used in This Tutorial

  1. Vector Angle
  2. Dot Product
  3. Angle Between

Introduction to Vector Angles

Understanding the angles between vectors helps to creating realistic movement, collision detection, and NPC behavior. Whether you’re aligning a character’s direction with a target, calculating the trajectory of a projectile, or determining the angle of impact in a collision, vector angles are at the heart of these computations.

Vector angles also play a significant role in various fields of physics, where they help analyse forces and motion, as well as in computer graphics where they are used to control lighting and shading. This tutorial will guide you through the essential SplashKit functions for calculating and understanding vector angles, enabling you to apply these concepts effectively in your game projects and beyond.

Vector Angles

Vector Angles

Use this code in your own IDE to play with the functions for yourself!
#include "splashkit.h"
using std::to_string;
// Function to draw a Cartesian grid
void draw_cartesian_grid()
{
const int GRID_SPACING = 50;
for (int x = 0; x < screen_width(); x += GRID_SPACING)
{
draw_line(COLOR_LIGHT_GRAY, x, 0, x, screen_height());
if (x != screen_width() / 2)
{
draw_text(to_string(x - screen_width() / 2), COLOR_BLACK, x, screen_height() / 2 + 5);
}
}
for (int y = 0; y < screen_height(); y += GRID_SPACING)
{
draw_line(COLOR_LIGHT_GRAY, 0, y, screen_width(), y);
if (y != screen_height() / 2)
{
draw_text(to_string(screen_height() / 2 - y), COLOR_BLACK, screen_width() / 2 + 5, y);
}
}
draw_line(COLOR_BLACK, 0, screen_height() / 2, screen_width(), screen_height() / 2); // x-axis
draw_line(COLOR_BLACK, screen_width() / 2, 0, screen_width() / 2, screen_height()); // y-axis
draw_text("0", COLOR_BLACK, screen_width() / 2 + 5, screen_height() / 2 + 5);
}
// Function to draw a vector and display its angle on the Cartesian plane
void draw_vector_with_angle(point_2d start, vector_2d v, color c, std::string label)
{
point_2d end = {start.x + v.x, start.y + v.y}; // End point of the vector
draw_line(c, start.x + screen_width() / 2, screen_height() / 2 - start.y,
end.x + screen_width() / 2, screen_height() / 2 - end.y);
// Label the vector
draw_text(label, c, end.x + screen_width() / 2 + 10, screen_height() / 2 - end.y);
}
int main()
{
open_window("Vector Angle Example", 800, 600);
vector_2d my_vector = {100, 50}; // Example vector
while (!window_close_requested("Vector Angle Example"))
{
process_events();
clear_screen(COLOR_WHITE);
draw_cartesian_grid();
// Draw the vector on the Cartesian plane
draw_vector_with_angle({0, 0}, my_vector, COLOR_BLUE, "Vector");
// Display the vector angle
double my_vector_angle = vector_angle(my_vector);
draw_text("Angle: " + to_string(my_vector_angle) + " degrees", COLOR_BLACK, 10, 10);
refresh_screen(60);
}
close_window("Vector Angle Example");
return 0;
}

Understanding the angle of a vector is needed in various game development scenarios:

  • Character Orientation: Adjust the orientation of game characters or objects to face specific directions.
  • Movement Mechanics: Implement mechanics that depend on the direction of movement, such as aiming and steering.
  • Visual Indicators: Create visual cues that indicate direction, such as arrows or aiming reticles.

With a clear understanding of vector angles, you can create more intuitive and responsive gameplay experiences by accurately controlling the orientation and direction of game elements.

Dot Product

Now that we have covered the basics of vector angles, we can explore how the dot product further enhances our understanding of vector relationships.

The dot product of two vectors is a scalar value that provides key insights into the relationship between them. If the dot product is positive, the angle is less than 90 degrees, indicating that the vectors are pointing in a generally similar direction. A negative dot product means the angle is greater than 90 degrees, showing that the vectors are pointing in generally opposite directions. If the dot product is zero, the vectors are perpendicular.

double dot_product_result_ab = dot_product(vector_a, vector_b);
double dot_product_result_ac = dot_product(vector_a, vector_c);
double dot_product_result_ad = dot_product(vector_a, vector_d);

Consider the following diagram:

Vector Dot Product

  • The dot product of Vector A and Vector B is positive, which means that they are pointing in relatively the same direction.
  • The dot product of Vector A and Vector C is zero, which means that they are perpendicular to one another.
  • The dot product of Vector A and Vector D is negative, which means that they are pointing in relatively different directions.
Use this code in your own IDE to play with the functions for yourself!
#include "splashkit.h"
using std::to_string;
// Define constants
const int GRID_SPACING = 50;
// Function to draw the Cartesian grid
void draw_cartesian_grid()
{
for (int x = 0; x < screen_width(); x += GRID_SPACING)
{
draw_line(COLOR_LIGHT_GRAY, x, 0, x, screen_height());
if (x != screen_width() / 2)
{
draw_text(to_string(x - screen_width() / 2), COLOR_BLACK, x, screen_height() / 2 + 5);
}
}
for (int y = 0; y < screen_height(); y += GRID_SPACING)
{
draw_line(COLOR_LIGHT_GRAY, 0, y, screen_width(), y);
if (y != screen_height() / 2)
{
draw_text(to_string(screen_height() / 2 - y), COLOR_BLACK, screen_width() / 2 + 5, y);
}
}
draw_line(COLOR_BLACK, 0, screen_height() / 2, screen_width(), screen_height() / 2); // x-axis
draw_line(COLOR_BLACK, screen_width() / 2, 0, screen_width() / 2, screen_height()); // y-axis
draw_text("0", COLOR_BLACK, screen_width() / 2 + 5, screen_height() / 2 + 5);
}
// Function to draw a vector
void draw_vector(point_2d start, vector_2d v, color c, std::string label, int x_offset, int y_offset)
{
point_2d end = {start.x + v.x, start.y + v.y};
draw_line(c, start.x + screen_width() / 2, screen_height() / 2 - start.y,
end.x + screen_width() / 2, screen_height() / 2 - end.y);
draw_text(label, c, end.x + screen_width() / 2 + x_offset, screen_height() / 2 - end.y + y_offset);
}
int main()
{
open_window("Vector Dot Product Example", 800, 600);
// Define two vectors
vector_2d vector_a = {100, 100};
vector_2d vector_b = {100, 80};
vector_2d vector_c = {100, -100};
vector_2d vector_d = {-100, -80};
// Starting point for vectors (origin)
point_2d origin = {0, 0};
// Calculate the dot product
double dot_product_result_ab = dot_product(vector_a, vector_b);
double dot_product_result_ac = dot_product(vector_a, vector_c);
double dot_product_result_ad = dot_product(vector_a, vector_d);
while (!window_close_requested("Vector Dot Product Example"))
{
process_events();
clear_screen(COLOR_WHITE);
draw_cartesian_grid();
// Draw the vectors
draw_vector(origin, vector_a, COLOR_RED, "Vector A", 10, -10);
draw_vector(origin, vector_b, COLOR_BLUE, "Vector B", 10, 10);
draw_vector(origin, vector_c, COLOR_DARK_GREEN, "Vector C", 10, 10);
draw_vector(origin, vector_d, COLOR_ORANGE, "Vector D", 10, 10);
// Display the dot product results
draw_text("Dot Product (A-B):" + to_string(dot_product_result_ab), COLOR_BLACK, 10, 10);
draw_text("Dot Product (A-C):" + to_string(dot_product_result_ac), COLOR_BLACK, 10, 30);
draw_text("Dot Product (A-D):" + to_string(dot_product_result_ad), COLOR_BLACK, 10, 50);
refresh_screen(60);
}
close_window("Vector Dot Product Example");
return 0;
}

One scenario where this may be useful is to determine if two game objects are facing each other or moving in similar directions. For instance, you can use it to check if an enemy is facing the player by comparing their direction vectors:

double dot = dot_product(player_direction, enemy_direction);
if (dot > 0)
{
// Objects are facing each other
}

The dot product is used for other useful things such as determining the vector of a reflection, for example a ball bouncing off of a surface, however that is not within the scope of this tutorial. It is important to understand that using the dot product and calculating the angle between two vectors are both valuable techniques in vector mathematics, but they serve different purposes and have different advantages.

  • The dot product is computationally efficient, as it involves only a few multiplications and additions. This is particularly useful in performance-critical applications like real-time graphics or game development.
  • It can quickly determine if two vectors are pointing in similar or opposite directions without needing to compute the actual angle. This is useful in algorithms that need to classify vectors into different categories based on their alignment.

Let’s dive into how we would calculate the angle between two vectors.

Calculating Angles Between Vectors

To visualise the angle between two vectors, imagine an angle formed by placing a line from the end of the first vector to the end of the second vector. The angle between these vectors represents how much one vector needs to rotate to align with the other. This is helpful in applications where precise directional adjustments or relative orientations are necessary.

double angle = angle_between(vector1, vector2);

Observe the following diagram:

Angle Between Vectors

Note that the green line that connects the two vectors is 135 degrees from the x axis, and not the angle created between the two lines.

Use this code in your own IDE to play with the functions for yourself!
#include "splashkit.h"
using std::to_string;
// Function to draw a Cartesian grid
void draw_cartesian_grid()
{
const int GRID_SPACING = 50;
for (int x = 0; x < screen_width(); x += GRID_SPACING)
{
draw_line(COLOR_LIGHT_GRAY, x, 0, x, screen_height());
if (x != screen_width() / 2)
{
draw_text(to_string(x - screen_width() / 2), COLOR_BLACK, x, screen_height() / 2 + 5);
}
}
for (int y = 0; y < screen_height(); y += GRID_SPACING)
{
draw_line(COLOR_LIGHT_GRAY, 0, y, screen_width(), y);
if (y != screen_height() / 2)
{
draw_text(to_string(screen_height() / 2 - y), COLOR_BLACK, screen_width() / 2 + 5, y);
}
}
draw_line(COLOR_BLACK, 0, screen_height() / 2, screen_width(), screen_height() / 2); // x-axis
draw_line(COLOR_BLACK, screen_width() / 2, 0, screen_width() / 2, screen_height()); // y-axis
draw_text("0", COLOR_BLACK, screen_width() / 2 + 5, screen_height() / 2 + 5);
}
// Function to draw a vector on the Cartesian plane
void draw_vector(point_2d start, vector_2d v, color c, std::string label)
{
point_2d end = {start.x + v.x, start.y + v.y}; // End point of the vector
draw_line(c, start.x + screen_width() / 2, screen_height() / 2 - start.y,
end.x + screen_width() / 2, screen_height() / 2 - end.y);
draw_text(label, c, end.x + screen_width() / 2 + 10, screen_height() / 2 - end.y);
}
int main()
{
open_window("Angle Between Vectors Example", 800, 600);
vector_2d vector1 = {200, 100}; // Example vector 1
vector_2d vector2 = {100, 200}; // Example vector 2
while (!window_close_requested("Angle Between Vectors Example"))
{
process_events();
clear_screen(COLOR_WHITE);
draw_cartesian_grid();
// Draw vectors
draw_vector({0, 0}, vector1, COLOR_BLUE, "Vector 1");
draw_vector({0, 0}, vector2, COLOR_RED, "Vector 2");
draw_vector({vector1.x, vector1.y}, vector_subtract(vector2, vector1), COLOR_GREEN, "");
// Calculate and display the angle between vectors
double angle = angle_between(vector1, vector2);
draw_text("Angle: " + to_string(angle) + " degrees", COLOR_BLACK, 10, 10);
refresh_screen(60);
}
close_window("Angle Between Vectors Example");
return 0;
}

Conclusion

Understanding vector angles is important for crafting realistic and dynamic interactions in game development and computer graphics. SplashKits tools like vector_angle, dot_product, and angle_between can be used to master vector orientation, relationships, and precise directional adjustments. With these concepts, you can enhance character alignment, improve collision detection, and fine-tune movements and animations.