This tutorial covers essential vector arithmetic operations, including addition, subtraction, and multiplication, using SplashKit functions. These operations are fundamental for tasks such as calculating movement, force, and direction in game development and physics simulations.
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 Arithmetic
Vector arithmetic involves the addition, subtraction, and multiplication of vectors. These operations are used in various programming scenarios, particularly in game development and physics simulations, to calculate and manipulate directions, positions, and forces.
SplashKit Vector Functions Used in This Tutorial
Vector Add
Vector Subtract
Vector Multiply
Vector Addition
Function
Vector addition combines two vectors into a new vector. The resulting vector represents the cumulative effect of the original vectors. This is particularly useful in scenarios where multiple forces, velocities, or displacements need to be combined.
vector_2d vector_add ( const vector_2d & v1 , const vector_2d & v2 )
public static Vector2D Vector2D . VectorAdd (Vector2D v1, Vector2D v2);
public static Vector2D SplashKit . VectorAdd (Vector2D v1, Vector2D v2);
For example, adding vectors v1
and v2
is computed as:
We can make use of the vector_add
function to compute this as follows:
vector_2d v1 = { 100 , 50 };
vector_2d v2 = { 200 , 150 };
vector_2d result = vector_add (v1, v2);
new Vector2D () {((X = 200 ), (Y = 150 ))}; Vector2D result =
SplashKit . VectorAdd (v1, v2);
result = vector_add ( v1 , v2 )
In this example, v1
and v2
are added together to produce a new vector result
with values (300, 200)
.
Use this code in your own IDE to play with the functions for yourself! const int GRID_SPACING = 50 ;
void draw_cartesian_grid ()
// Draw vertical lines and labels
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 ) // Avoid overlapping with the y-axis label
draw_text ( to_string (x - screen_width () / 2 ), COLOR_BLACK, x, screen_height () / 2 + 5 );
// Draw horizontal lines and labels
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 ) // Avoid overlapping with the x-axis label
draw_text ( to_string ( screen_height () / 2 - y), COLOR_BLACK, screen_width () / 2 + 5 , y);
// Draw x-axis and y-axis
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 );
open_window ( " Vector Addition " , 800 , 600 );
// Calculate vector addition
vector_2d vector_sum = vector_add (vector_a, vector_b);
// Define the origin (centre of the window)
while ( ! window_close_requested ( " Vector Addition " ))
clear_screen (COLOR_WHITE);
// Draw the vectors as lines from the center of the screen
draw_line (COLOR_RED, origin . x , origin . y , origin . x + vector_a . x , origin . y - vector_a . y );
draw_line (COLOR_GREEN, origin . x , origin . y , origin . x + vector_b . x , origin . y - vector_b . y );
draw_line (COLOR_BLUE, origin . x , origin . y , origin . x + vector_sum . x , origin . y - vector_sum . y );
// Display vector properties on the screen
draw_text ( " Vector A (R): " + vector_to_string (vector_a), COLOR_BLACK, 10 , 10 );
draw_text ( " Vector B (G): " + vector_to_string (vector_b), COLOR_BLACK, 10 , 30 );
draw_text ( " Sum (B): " + vector_to_string (vector_sum), COLOR_BLACK, 10 , 50 );
const int GRID_SPACING = 50 ;
// Function to draw the Cartesian grid
// Draw vertical lines and labels
for ( int x = 0 ; x < SplashKit . ScreenWidth (); x += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , x, 0 , x, SplashKit . ScreenHeight ());
if (x != SplashKit . ScreenWidth () / 2 ) // Avoid overlapping with the y-axis label
SplashKit . DrawText ((x - SplashKit . ScreenWidth () / 2 ) . ToString (), Color . Black , x, SplashKit . ScreenHeight () / 2 + 5 );
// Draw horizontal lines and labels
for ( int y = 0 ; y < SplashKit . ScreenHeight (); y += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , 0 , y, SplashKit . ScreenWidth (), y);
if (y != SplashKit . ScreenHeight () / 2 ) // Avoid overlapping with the x-axis label
SplashKit . DrawText (( SplashKit . ScreenHeight () / 2 - y) . ToString (), Color . Black , SplashKit . ScreenWidth () / 2 + 5 , y);
// Draw x-axis and y-axis
SplashKit . DrawLine ( Color . Black , 0 , SplashKit . ScreenHeight () / 2 , SplashKit . ScreenWidth (), SplashKit . ScreenHeight () / 2 ); // x-axis
SplashKit . DrawLine ( Color . Black , SplashKit . ScreenWidth () / 2 , 0 , SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight ()); // y-axis
SplashKit . DrawText ( " 0 " , Color . Black , SplashKit . ScreenWidth () / 2 + 5 , SplashKit . ScreenHeight () / 2 + 5 );
// Main program logic using top-level statements
SplashKit . OpenWindow ( " Vector Addition " , 800 , 600 );
Vector2D vectorA = new Vector2D() { X = 100 , Y = 50 };
Vector2D vectorB = new Vector2D() { X = 200 , Y = 150 };
// Calculate vector addition
Vector2D vectorSum = SplashKit . VectorAdd (vectorA, vectorB);
// Define the origin (center of the window)
Point2D origin = new Point2D() { X = 400 , Y = 300 };
while ( ! SplashKit . WindowCloseRequested ( " Vector Addition " ))
SplashKit . ProcessEvents ();
SplashKit . ClearScreen ( Color . White );
// Draw the vectors as lines from the center of the screen
SplashKit . DrawLine ( Color . Red , origin . X , origin . Y , origin . X + vectorA . X , origin . Y - vectorA . Y );
SplashKit . DrawLine ( Color . Green , origin . X , origin . Y , origin . X + vectorB . X , origin . Y - vectorB . Y );
SplashKit . DrawLine ( Color . Blue , origin . X , origin . Y , origin . X + vectorSum . X , origin . Y - vectorSum . Y );
// Display vector properties on the screen
SplashKit . DrawText ( " Vector A (R): " + SplashKit . VectorToString (vectorA), Color . Black , 10 , 10 );
SplashKit . DrawText ( " Vector B (G): " + SplashKit . VectorToString (vectorB), Color . Black , 10 , 30 );
SplashKit . DrawText ( " Sum (B): " + SplashKit . VectorToString (vectorSum), Color . Black , 10 , 50 );
SplashKit . RefreshScreen ( 60 );
Vector Subtraction
Function
Conversely, vector subtraction finds the difference between two vectors, yielding a vector that points from the end of one vector to the other. This is useful for calculating relative positions, directions, or the change in velocity or force.
vector_2d vector_subtract ( const vector_2d & v1 , const vector_2d & v2 )
public static Vector2D Vector2D . VectorSubtract (Vector2D v1, Vector2D v2);
public static Vector2D SplashKit . VectorSubtract (Vector2D v1, Vector2D v2);
def vector_subtract ( v1 , v2 ) :
For example, subtracting vector v2
from v1
gives:
We can make use of the vector_subtract
function to compute this as follows:
vector_2d v1 = { 300 , 200 };
vector_2d v2 = { 100 , 50 };
vector_2d result = vector_subtract (v1, v2);
new Vector2D () {((X = 100 ), (Y = 50 ))}; Vector2D result =
SplashKit . VectorSubtract (v1, v2);
result = vector_subtract ( v1 , v2 )
In this example, v2
is subtracted from v1
to produce a new vector result
with values (200, 150)
.
Use this code in your own IDE to play with the functions for yourself! const int GRID_SPACING = 50 ;
void draw_cartesian_grid ()
// Draw vertical lines and labels
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 ) // Avoid overlapping with the y-axis label
draw_text ( to_string (x - screen_width () / 2 ), COLOR_BLACK, x, screen_height () / 2 + 5 );
// Draw horizontal lines and labels
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 ) // Avoid overlapping with the x-axis label
draw_text ( to_string ( screen_height () / 2 - y), COLOR_BLACK, screen_width () / 2 + 5 , y);
// Draw x-axis and y-axis
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 );
open_window ( " Vector Subtraction " , 800 , 600 );
// Calculate vector subtraction
vector_2d vector_difference = vector_subtract (vector_a, vector_b);
// Define the origin (centre of the window)
while ( ! window_close_requested ( " Vector Subtraction " ))
clear_screen (COLOR_WHITE);
// Draw the vectors as lines from the center of the screen
draw_line (COLOR_RED, origin . x , origin . y , origin . x + vector_a . x , origin . y - vector_a . y );
draw_line (COLOR_GREEN, origin . x , origin . y , origin . x + vector_b . x , origin . y - vector_b . y );
draw_line (COLOR_ORANGE, origin . x , origin . y , origin . x + vector_difference . x , origin . y - vector_difference . y );
// Display vector properties on the screen
draw_text ( " Vector A (R): " + vector_to_string (vector_a), COLOR_BLACK, 10 , 10 );
draw_text ( " Vector B (G): " + vector_to_string (vector_b), COLOR_BLACK, 10 , 30 );
draw_text ( " Difference (O): " + vector_to_string (vector_difference), COLOR_BLACK, 10 , 50 );
const int GRID_SPACING = 50 ;
// Function to draw the Cartesian grid
// Draw vertical lines and labels
for ( int x = 0 ; x < SplashKit . ScreenWidth (); x += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , x, 0 , x, SplashKit . ScreenHeight ());
if (x != SplashKit . ScreenWidth () / 2 ) // Avoid overlapping with the y-axis label
SplashKit . DrawText ((x - SplashKit . ScreenWidth () / 2 ) . ToString (), Color . Black , x, SplashKit . ScreenHeight () / 2 + 5 );
// Draw horizontal lines and labels
for ( int y = 0 ; y < SplashKit . ScreenHeight (); y += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , 0 , y, SplashKit . ScreenWidth (), y);
if (y != SplashKit . ScreenHeight () / 2 ) // Avoid overlapping with the x-axis label
SplashKit . DrawText (( SplashKit . ScreenHeight () / 2 - y) . ToString (), Color . Black , SplashKit . ScreenWidth () / 2 + 5 , y);
// Draw x-axis and y-axis
SplashKit . DrawLine ( Color . Black , 0 , SplashKit . ScreenHeight () / 2 , SplashKit . ScreenWidth (), SplashKit . ScreenHeight () / 2 ); // x-axis
SplashKit . DrawLine ( Color . Black , SplashKit . ScreenWidth () / 2 , 0 , SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight ()); // y-axis
SplashKit . DrawText ( " 0 " , Color . Black , SplashKit . ScreenWidth () / 2 + 5 , SplashKit . ScreenHeight () / 2 + 5 );
// Main program logic using top-level statements
SplashKit . OpenWindow ( " Vector Subtraction " , 800 , 600 );
Vector2D vectorA = new Vector2D() { X = 300 , Y = 200 };
Vector2D vectorB = new Vector2D() { X = 100 , Y = 50 };
// Calculate vector subtraction
Vector2D vectorDifference = SplashKit . VectorSubtract (vectorA, vectorB);
// Define the origin (center of the window)
Point2D origin = new Point2D() { X = 400 , Y = 300 };
while ( ! SplashKit . WindowCloseRequested ( " Vector Subtraction " ))
SplashKit . ProcessEvents ();
SplashKit . ClearScreen ( Color . White );
// Draw the vectors as lines from the center of the screen
SplashKit . DrawLine ( Color . Red , origin . X , origin . Y , origin . X + vectorA . X , origin . Y - vectorA . Y );
SplashKit . DrawLine ( Color . Green , origin . X , origin . Y , origin . X + vectorB . X , origin . Y - vectorB . Y );
SplashKit . DrawLine ( Color . Orange , origin . X , origin . Y , origin . X + vectorDifference . X , origin . Y - vectorDifference . Y );
// Display vector properties on the screen
SplashKit . DrawText ( " Vector A (R): " + SplashKit . VectorToString (vectorA), Color . Black , 10 , 10 );
SplashKit . DrawText ( " Vector B (G): " + SplashKit . VectorToString (vectorB), Color . Black , 10 , 30 );
SplashKit . DrawText ( " Difference (O): " + SplashKit . VectorToString (vectorDifference), Color . Black , 10 , 50 );
SplashKit . RefreshScreen ( 60 );
Practical Applications of Vector Addition and Subtraction
Vector addition and subtraction are fundamental operations in game development, particularly in handling movement, physics, and collision detection. For example, when simulating a character’s movement in a game, multiple forces like gravity, wind, or user input can be combined using vector addition to determine the character’s final trajectory. Similarly, vector subtraction can be used to calculate the relative velocity between two objects, such as a missile and a target, helping in predicting collisions or adjusting aiming mechanics.
Scenario: Character Movement with Multiple Forces
In a platform game, a character is affected by multiple forces: user input (e.g., moving left or right), gravity, and wind.
Each of these forces can be represented as vectors:
User Input Vector: Represents the direction and speed of movement based on player input (e.g., moving right might be (3, 0)
).
Gravity Vector: Acts downwards, pulling the character down (e.g., (0, -9.8)
).
Wind Vector: Blows horizontally, affecting the character’s movement (e.g., (-2, 0)
if it’s blowing left).
By adding these vectors, you get the character’s final movement vector:
vector_2d user_input = { 35 , 0 }; // Moving right
vector_2d gravity = { 0 , - 9.8 }; // Gravity pulling down
vector_2d wind = { - 20 , 0 }; // Wind blowing left
vector_2d final_movement = vector_add ( vector_add (user_input, gravity), wind); // Combining all forces
Vector2D userInput = new Vector2D() { X = 35 , Y = 0 }; // Moving right
Vector2D gravity = new Vector2D() { X = 0 , Y = - 9.8 }; // Gravity pulling down
Vector2D wind = new Vector2D() { X = - 20 , Y = 0 }; // Wind blowing left
Vector2D finalMovement = SplashKit . VectorAdd ( SplashKit . VectorAdd (userInput, gravity), wind);
Let’s visualise this!
Use this code in your own IDE to play with the functions for yourself! const int GRID_SPACING = 50 ; // Define grid spacing for the Cartesian grid
// Function to draw a vector on the screen
void draw_vector (vector_2d vec , color c , point_2d start_point , string label , double scale )
point_2d end_point = { start_point . x + vec . x_ scale, start_point . y - vec . y_ scale}; // Adjust scale as needed
draw_line (c, start_point . x , start_point . y , end_point . x , end_point . y );
draw_text (label, c, end_point . x + 5 , end_point . y - 15 ); // Adjust text position to avoid overlap
// Function to draw the Cartesian grid
void draw_cartesian_grid ()
// Draw vertical lines and labels
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 ) // Avoid overlapping with the y-axis label
draw_text ( to_string (x - screen_width () / 2 ), COLOR_BLACK, x, screen_height () / 2 + 5 );
// Draw horizontal lines and labels
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 ) // Avoid overlapping with the x-axis label
draw_text ( to_string ( screen_height () / 2 - y), COLOR_BLACK, screen_width () / 2 + 5 , y);
// Draw x-axis and y-axis
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 );
open_window ( " Vector Addition with Moving Player " , 800 , 600 );
// Initial position of the player (starting at 100, 100)
point_2d player_pos = { 100 , 100 };
point_2d initial_pos = player_pos; // Store the initial position for final vector
vector_2d user_input = { 35 , 0 }; // Moving right
vector_2d gravity = { 0 , - 9.8 }; // Gravity pulling down
vector_2d wind = { - 20 , 0 }; // Wind blowing left
// Calculate the final movement vector
vector_2d final_movement = vector_add ( vector_add (user_input, gravity), wind);
while ( ! window_close_requested ( " Vector Addition with Moving Player " ))
clear_screen (COLOR_WHITE);
// Draw the Cartesian grid
// Draw the player (a circle) at the current position
fill_circle (COLOR_PURPLE, player_pos . x , player_pos . y , 10 );
// Draw the individual vectors acting on the player
// Scale factor adjusted to make vectors visible
double scale_factor = 5 ; // Adjust as needed
// Draw user input vector
draw_vector (user_input, COLOR_BLUE, player_pos, " User Input " , scale_factor);
point_2d gravity_end = { player_pos . x , player_pos . y - gravity . y * scale_factor}; // Gravity vector should extend downwards
draw_line (COLOR_RED, player_pos . x , player_pos . y , gravity_end . x , gravity_end . y );
draw_text ( " Gravity " , COLOR_RED, gravity_end . x + 5 , gravity_end . y - 15 ); // Adjust text position to avoid overlap
point_2d wind_end = { player_pos . x + wind . x * scale_factor, player_pos . y }; // Wind vector should extend horizontally to the left
draw_line (COLOR_GREEN, player_pos . x , player_pos . y , wind_end . x , wind_end . y );
draw_text ( " Wind " , COLOR_GREEN, wind_end . x + 5 , wind_end . y - 15 ); // Adjust text position to avoid overlap
// Draw the final movement vector from the initial position to the current position
point_2d final_movement_end = { player_pos . x + final_movement . x * scale_factor, player_pos . y - final_movement . y * scale_factor};
draw_line (COLOR_CHOCOLATE, player_pos . x , player_pos . y , final_movement_end . x , final_movement_end . y );
draw_text ( " Movement Direction " , COLOR_ORANGE, final_movement_end . x + 5 , final_movement_end . y - 15 ); // Adjust text position to avoid overlap
// Update the player's position based on the final movement vector
player_pos . x += final_movement . x ;
player_pos . y -= final_movement . y ; // Inverted Y because of screen coordinates
// Add delay to assist visualisation
const int GRID_SPACING = 50 ; // Define grid spacing for the Cartesian grid
// Function to draw a vector on the screen
void DrawVector (Vector2D vec, Color c, Point2D startPoint, string label, double scale)
Point2D endPoint = new Point2D
X = startPoint . X + vec . X * scale,
Y = startPoint . Y - vec . Y * scale
}; // Adjust scale as needed
SplashKit . DrawLine (c, startPoint . X , startPoint . Y , endPoint . X , endPoint . Y );
SplashKit . DrawText (label, c, endPoint . X + 5 , endPoint . Y - 15 ); // Adjust text position to avoid overlap
// Function to draw the Cartesian grid
// Draw vertical lines and labels
for ( int x = 0 ; x < SplashKit . ScreenWidth (); x += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , x, 0 , x, SplashKit . ScreenHeight ());
if (x != SplashKit . ScreenWidth () / 2 ) // Avoid overlapping with the y-axis label
SplashKit . DrawText ((x - SplashKit . ScreenWidth () / 2 ) . ToString (), Color . Black , x, SplashKit . ScreenHeight () / 2 + 5 );
// Draw horizontal lines and labels
for ( int y = 0 ; y < SplashKit . ScreenHeight (); y += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , 0 , y, SplashKit . ScreenWidth (), y);
if (y != SplashKit . ScreenHeight () / 2 ) // Avoid overlapping with the x-axis label
SplashKit . DrawText (( SplashKit . ScreenHeight () / 2 - y) . ToString (), Color . Black , SplashKit . ScreenWidth () / 2 + 5 , y);
// Draw x-axis and y-axis
SplashKit . DrawLine ( Color . Black , 0 , SplashKit . ScreenHeight () / 2 , SplashKit . ScreenWidth (), SplashKit . ScreenHeight () / 2 ); // x-axis
SplashKit . DrawLine ( Color . Black , SplashKit . ScreenWidth () / 2 , 0 , SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight ()); // y-axis
SplashKit . DrawText ( " 0 " , Color . Black , SplashKit . ScreenWidth () / 2 + 5 , SplashKit . ScreenHeight () / 2 + 5 );
// Main program execution
Window window = SplashKit . OpenWindow ( " Vector Addition with Moving Player " , 800 , 600 );
// Initial position of the player (starting at 100, 100)
Point2D playerPos = new Point2D { X = 100 , Y = 100 };
Vector2D userInput = new Vector2D { X = 35 , Y = 0 }; // Moving right
Vector2D gravity = new Vector2D { X = 0 , Y = - 9.8 }; // Gravity pulling down
Vector2D wind = new Vector2D { X = - 20 , Y = 0 }; // Wind blowing left
// Calculate the final movement vector
Vector2D finalMovement = SplashKit . VectorAdd ( SplashKit . VectorAdd (userInput, gravity), wind);
while ( ! SplashKit . WindowCloseRequested ( " Vector Addition with Moving Player " ))
SplashKit . ProcessEvents ();
SplashKit . ClearScreen ( Color . White );
// Draw the Cartesian grid
// Draw the player (a circle) at the current position
SplashKit . FillCircle ( Color . Purple , playerPos . X , playerPos . Y , 10 );
// Draw the individual vectors acting on the player
double scaleFactor = 5 ; // Adjust as needed
// Draw user input vector
DrawVector (userInput, Color . Blue , playerPos, " User Input " , scaleFactor);
Point2D gravityEnd = new Point2D { X = playerPos . X , Y = playerPos . Y - gravity . Y * scaleFactor }; // Gravity vector should extend downwards
SplashKit . DrawLine ( Color . Red , playerPos . X , playerPos . Y , gravityEnd . X , gravityEnd . Y );
SplashKit . DrawText ( " Gravity " , Color . Red , gravityEnd . X + 5 , gravityEnd . Y - 15 ); // Adjust text position to avoid overlap
Point2D windEnd = new Point2D { X = playerPos . X + wind . X * scaleFactor, Y = playerPos . Y }; // Wind vector should extend horizontally to the left
SplashKit . DrawLine ( Color . Green , playerPos . X , playerPos . Y , windEnd . X , windEnd . Y );
SplashKit . DrawText ( " Wind " , Color . Green , windEnd . X + 5 , windEnd . Y - 15 ); // Adjust text position to avoid overlap
// Draw the final movement vector from the initial position to the current position
Point2D finalMovementEnd = new Point2D
X = playerPos . X + finalMovement . X * scaleFactor,
Y = playerPos . Y - finalMovement . Y * scaleFactor
SplashKit . DrawLine ( Color . Chocolate , playerPos . X , playerPos . Y , finalMovementEnd . X , finalMovementEnd . Y );
SplashKit . DrawText ( " Movement Direction " , Color . Orange , finalMovementEnd . X + 5 , finalMovementEnd . Y - 15 ); // Adjust text position to avoid overlap
// Update the player's position based on the final movement vector
playerPos . X += finalMovement . X ;
playerPos . Y -= finalMovement . Y ; // Inverted Y because of screen coordinates
// Add delay to assist visualization
SplashKit . RefreshScreen ( 60 );
Scenario: Calculating Ship Trajectory
In a navigation simulation game, a ship is moving towards an island, but it has to account for a current that affects its path. You need to calculate the correct heading for the ship to reach the island directly, considering the current’s influence.
Ship’s Velocity Vector: Represents the ship’s intended direction and speed.
Current’s Velocity Vector: Represents the current’s direction and speed affecting the ship’s path.
Target Vector: Represents the direct line from the ship’s current position to the island.
The goal is to determine the required heading for the ship to counteract the current and head directly to the island.
point_2d ship_position = { - 50 , 50 }; // Ship starts at (-50, 50)
point_2d island_position = { 200 , 250 }; // Island at (200, 250)
vector_2d current_vector = { 100 , 5 }; // Current affecting the ship
vector_2d target_vector = vector_point_to_point (ship_position, island_position);
vector_2d required_vector = vector_subtract (target_vector, current_vector);
Point2D shipPosition = new Point2D { X = - 50 , Y = 50 }; // Ship starts at (-50, 50)
Point2D islandPosition = new Point2D { X = 200 , Y = 250 }; // Island at (200, 250)
Vector2D currentVector = new Vector2D { X = 100 , Y = 5 }; // Current affecting the ship
Vector2D targetVector = SplashKit . VectorPointToPoint (shipPosition, islandPosition);
Vector2D requiredVector = SplashKit . VectorSubtract (targetVector, currentVector);
Using the vector_subtract
function from SplashKit, the required_vector
is calculated by subtracting the current_vector
from the target_vector
. This required_vector
represents the direction the ship needs to steer in order to reach the island while counteracting the current.
Use this code in your own IDE to play with the functions for yourself! const int GRID_SPACING = 50 ;
// Function to draw the Cartesian grid
void draw_cartesian_grid ()
int width = screen_width ();
int height = screen_height ();
int center_x = width / 2 ;
int center_y = height / 2 ;
for ( int x = 0 ; x <= width; x += GRID_SPACING)
draw_line (COLOR_LIGHT_GRAY, x, 0 , x, height);
draw_text ( to_string ((x - center_x) / GRID_SPACING), COLOR_BLACK, x + 2 , center_y + 5 );
for ( int y = 0 ; y <= height; y += GRID_SPACING)
draw_line (COLOR_LIGHT_GRAY, 0 , y, width, y);
draw_text ( to_string ((center_y - y) / GRID_SPACING), COLOR_BLACK, center_x + 5 , y - 10 );
draw_line (COLOR_BLACK, 0 , center_y, width, center_y); // x-axis
draw_line (COLOR_BLACK, center_x, 0 , center_x, height); // y-axis
draw_text ( " 0 " , COLOR_BLACK, center_x + 5 , center_y + 15 );
// Function to draw a vector
void draw_vector (point_2d start , vector_2d v , color c , string label , int x_offset , int y_offset )
point_2d end = { start . x + v . x , start . y + v . y }; // Adjust for Cartesian coordinates: y increases downwards
start . x + screen_width () / 2 , screen_height () / 2 - start . y , // Convert Cartesian coordinates to screen coordinates
end . x + screen_width () / 2 , screen_height () / 2 - end . y ); // Convert Cartesian coordinates to screen coordinates
end . x + screen_width () / 2 + x_offset,
screen_height () / 2 - end . y + y_offset); // Convert Cartesian coordinates to screen coordinates
open_window ( " Vector Point to Point Example " , 800 , 600 );
point_2d ship_position = { - 50 , 50 }; // Ship starts at (-50, 50)
point_2d island_position = { 200 , 250 }; // Island at (200, 250)
vector_2d current_vector = { 100 , 5 }; // Current affecting the ship
vector_2d target_vector = vector_point_to_point (ship_position, island_position);
vector_2d required_vector = vector_subtract (target_vector, current_vector);
while ( ! window_close_requested ( " Vector Point to Point Example " ))
clear_screen (COLOR_WHITE);
draw_circle (COLOR_RED, island_position . x + screen_width () / 2 , screen_height () / 2 - island_position . y , 10 );
draw_text ( " Island " , COLOR_BLACK, island_position . x + screen_width () / 2 , screen_height () / 2 - island_position . y - 20 );
draw_circle (COLOR_BLUE, ship_position . x + screen_width () / 2 , screen_height () / 2 - ship_position . y , 10 );
draw_text ( " Ship " , COLOR_BLACK, ship_position . x + screen_width () / 2 , screen_height () / 2 - ship_position . y - 20 );
draw_vector (ship_position, current_vector, COLOR_RED, " Current Vector " , 10 , - 10 );
draw_vector (ship_position, target_vector, COLOR_GREEN, " Target Vector " , 15 , 15 );
draw_vector (ship_position, required_vector, COLOR_BLUE, " Required Vector " , - 50 , - 20 );
close_window ( " Vector Point to Point Example " );
const int GRID_SPACING = 50 ;
// Function to draw the Cartesian grid
public static void DrawCartesianGrid ()
int width = SplashKit . ScreenWidth ();
int height = SplashKit . ScreenHeight ();
int centerY = height / 2 ;
for ( int x = 0 ; x <= width; x += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , x, 0 , x, height);
SplashKit . DrawText (((x - centerX) / GRID_SPACING) . ToString (), Color . Black , x + 2 , centerY + 5 );
for ( int y = 0 ; y <= height; y += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , 0 , y, width, y);
SplashKit . DrawText (((centerY - y) / GRID_SPACING) . ToString (), Color . Black , centerX + 5 , y - 10 );
SplashKit . DrawLine ( Color . Black , 0 , centerY, width, centerY); // x-axis
SplashKit . DrawLine ( Color . Black , centerX, 0 , centerX, height); // y-axis
SplashKit . DrawText ( " 0 " , Color . Black , centerX + 5 , centerY + 15 );
// Function to draw a vector
public static void DrawVector (Point2D start, Vector2D v, Color c, string label, int xOffset, int yOffset)
Point2D end = new Point2D()
start . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - start . Y ,
end . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - end . Y
end . X + SplashKit . ScreenWidth () / 2 + xOffset,
SplashKit . ScreenHeight () / 2 - end . Y + yOffset
public static void Main ()
Window window = SplashKit . OpenWindow ( " Vector Point to Point Example " , 800 , 600 );
Point2D shipPosition = new Point2D() { X = - 50 , Y = 50 }; // Ship starts at (-50, 50)
Point2D islandPosition = new Point2D() { X = 200 , Y = 250 }; // Island at (200, 250)
Vector2D currentVector = new Vector2D() { X = 100 , Y = 5 }; // Current affecting the ship
Vector2D targetVector = SplashKit . VectorPointToPoint (shipPosition, islandPosition);
Vector2D requiredVector = SplashKit . VectorSubtract (targetVector, currentVector);
while ( ! SplashKit . WindowCloseRequested ( " Vector Point to Point Example " ))
SplashKit . ProcessEvents ();
SplashKit . ClearScreen ( Color . White );
SplashKit . DrawCircle ( Color . Red , islandPosition . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - islandPosition . Y , 10 );
SplashKit . DrawText ( " Island " , Color . Black , islandPosition . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - islandPosition . Y - 20 );
SplashKit . DrawCircle ( Color . Blue , shipPosition . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - shipPosition . Y , 10 );
SplashKit . DrawText ( " Ship " , Color . Black , shipPosition . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - shipPosition . Y - 20 );
DrawVector (shipPosition, currentVector, Color . Red , " Current Vector " , 10 , - 10 );
DrawVector (shipPosition, targetVector, Color . Green , " Target Vector " , 15 , 15 );
DrawVector (shipPosition, requiredVector, Color . Blue , " Required Vector " , - 50 , - 20 );
SplashKit . RefreshScreen ( 60 );
Vector Multiplication
For example, if you have a vector v1 = {2, 3}
and you multiply it by a scalar s = 2
, the resulting vector would be {4, 6}
.
vector_multiply
is particularly useful in scenarios where you need to adjust the magnitude of a vector without changing its direction. For example, when developing games, you might want to control the speed of an object by scaling its velocity vector. If an object needs to move faster or slower, multiplying its velocity vector by a scalar can achieve this.
Scenario: Spaceship Afterburners
In a space game, if you want to double the speed of your spaceship by activating the afterburners, you can use the vector_multiply
function to scale the velocity vector representing the spaceship’s movement:
const double SHIP_SPEED = 25.0 ; // Normal speed of the ship
const double AFTERBURNER_MULTIPLIER = 2.0 ; // Afterburner multiplier
vector_2d normal_velocity = { SHIP_SPEED, 0 }; // Normal velocity vector (moving right)
// Use vector_multiply to double the speed for afterburners
vector_2d afterburner_velocity = vector_multiply (normal_velocity, AFTERBURNER_MULTIPLIER);
public const double SHIP_SPEED = 25.0 ; // Normal speed of the ship
public const double AFTERBURNER_MULTIPLIER = 2.0 ; // Afterburner multiplier
Vector2D normalVelocity = new Vector2D { X = SHIP_SPEED, Y = 0 }; // Normal velocity vector (moving right)
// Use VectorMultiply to double the speed for afterburners
Vector2D afterburnerVelocity = SplashKit . VectorMultiply (normalVelocity, AFTERBURNER_MULTIPLIER);
SHIP_SPEED
: Defines the normal speed of the ship, set to 25.0
units per frame.
AFTERBURNER_MULTIPLIER
: Represents the factor by which the speed is increased when afterburners are activated. In this case, it is 2.0
, meaning the speed will be doubled.
normal_velocity
: The ship moves to the right with a speed of 25.0
units and no vertical movement.
afterburner_velocity
: This vector is calculated by multiplying the normal_velocity
vector by the AFTERBURNER_MULTIPLIER
. The vector_multiply
function scales the velocity, effectively doubling the speed of the ship when the afterburners are activated.
Use this code in your own IDE to play with the functions for yourself! const int GRID_SPACING = 50 ;
const double NORMAL_SHIP_VELOCITY = 25.0 ; // Normal speed of the ship
const double AFTERBURNER_MULTIPLIER = 2.0 ; // Afterburner multiplier
// 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 (vector_2d start , vector_2d end , color c , std::string label , int x_offset , int y_offset )
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);
open_window ( " Ship with Velocity Vector " , 800 , 600 );
vector_2d ship_position = { - 300 , 50 }; // Ship starts at (-300, 50)
vector_2d velocity = { NORMAL_SHIP_VELOCITY, 0 }; // Normal velocity vector (moving right)
bool afterburners_activated = false ; // Flag to track afterburner activation
while ( ! window_close_requested ( " Ship with Velocity Vector " ))
clear_screen (COLOR_WHITE);
// Check if the ship has crossed the y-axis
if ( ship_position . x >= 0 )
if ( ! afterburners_activated)
// Activate afterburners (double the speed)
velocity = vector_multiply (velocity, AFTERBURNER_MULTIPLIER);
afterburners_activated = true ; // Set flag to true
// Update ship position based on velocity
ship_position . x += velocity . x ; // Move ship according to the velocity
draw_circle (COLOR_BLUE, ship_position . x + screen_width () / 2 , screen_height () / 2 - ship_position . y , 10 );
draw_text ( " Ship " , COLOR_BLACK, ship_position . x + screen_width () / 2 , screen_height () / 2 - ship_position . y - 20 );
draw_vector (ship_position, { ship_position . x + velocity . x , ship_position . y + velocity . y }, COLOR_RED, " Velocity " , 10 , - 10 );
// Display the magnitude of the velocity vector at the top left
draw_text ( " Velocity Magnitude: " + to_string ( vector_magnitude (velocity)), COLOR_BLACK, 10 , 10 );
// Display message if afterburners are activated
if (afterburners_activated)
draw_text ( " AFTERBURNERS ACTIVATED " , COLOR_GREEN, ship_position . x + screen_width () / 2 - 10 , ship_position . y + screen_height () / 2 + 20 );
close_window ( " Ship with Velocity Vector " );
const int GRID_SPACING = 50 ;
const double NORMAL_SHIP_VELOCITY = 25.0 ; // Normal speed of the ship
const double AFTERBURNER_MULTIPLIER = 2.0 ; // Afterburner multiplier
// Function to draw the Cartesian grid
int screenWidth = SplashKit . ScreenWidth ();
int screenHeight = SplashKit . ScreenHeight ();
int centerX = screenWidth / 2 ;
int centerY = screenHeight / 2 ;
for ( int x = 0 ; x < screenWidth; x += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , x, 0 , x, screenHeight);
SplashKit . DrawText (((x - centerX)) . ToString (), Color . Black , x, centerY + 5 );
for ( int y = 0 ; y < screenHeight; y += GRID_SPACING)
SplashKit . DrawLine ( Color . LightGray , 0 , y, screenWidth, y);
SplashKit . DrawText (((centerY - y)) . ToString (), Color . Black , centerX + 5 , y);
SplashKit . DrawLine ( Color . Black , 0 , centerY, screenWidth, centerY); // x-axis
SplashKit . DrawLine ( Color . Black , centerX, 0 , centerX, screenHeight); // y-axis
SplashKit . DrawText ( " 0 " , Color . Black , centerX + 5 , centerY + 5 );
// Function to draw a vector
void DrawVector (Vector2D start, Vector2D end, Color c, string label, int xOffset, int yOffset)
SplashKit . DrawLine (c, start . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - start . Y , end . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - end . Y );
SplashKit . DrawText (label, c, end . X + SplashKit . ScreenWidth () / 2 + xOffset, SplashKit . ScreenHeight () / 2 - end . Y + yOffset);
SplashKit . OpenWindow ( " Ship with Velocity Vector " , 800 , 600 );
Vector2D shipPosition = new Vector2D() { X = - 300 , Y = 50 }; // Ship starts at (-300, 50)
Vector2D velocity = new Vector2D() { X = NORMAL_SHIP_VELOCITY, Y = 0 }; // Normal velocity vector (moving right)
bool afterburnersActivated = false ; // Flag to track afterburner activation
while ( ! SplashKit . WindowCloseRequested ( " Ship with Velocity Vector " ))
SplashKit . ProcessEvents ();
SplashKit . ClearScreen ( Color . White );
// Check if the ship has crossed the y-axis
if ( ! afterburnersActivated)
// Activate afterburners (double the speed)
velocity = SplashKit . VectorMultiply (velocity, AFTERBURNER_MULTIPLIER);
afterburnersActivated = true ; // Set flag to true
// Update ship position based on velocity
shipPosition = SplashKit . VectorAdd (shipPosition, velocity); // Move ship according to the velocity
SplashKit . DrawCircle ( Color . Blue , shipPosition . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - shipPosition . Y , 10 );
SplashKit . DrawText ( " Ship " , Color . Black , shipPosition . X + SplashKit . ScreenWidth () / 2 , SplashKit . ScreenHeight () / 2 - shipPosition . Y - 20 );
DrawVector (shipPosition, SplashKit . VectorAdd (shipPosition, velocity), Color . Red , " Velocity " , 10 , - 10 );
// Display the magnitude of the velocity vector at the top left
SplashKit . DrawText ( " Velocity Magnitude: " + SplashKit . VectorMagnitude (velocity) . ToString ( " F2 " ), Color . Black , 10 , 10 );
// Display message if afterburners are activated
if (afterburnersActivated)
SplashKit . DrawText ( " AFTERBURNERS ACTIVATED " , Color . Green , shipPosition . X + SplashKit . ScreenWidth () / 2 - 10 , shipPosition . Y + SplashKit . ScreenHeight () / 2 + 20 );
SplashKit . RefreshScreen ();
Conclusion
Here we have explored some simple vector arithmetic operations, including vector addition, subtraction, and multiplication. These fundamental operations are useful in various programming scenarios, particularly in game development. By understanding and applying vector arithmetic, you can effectively calculate and manipulate directions, positions, and forces, enhancing your ability to create realistic and dynamic movements.
Mastering vector arithmetic will empower you to build more complex and interactive systems, laying a solid foundation for advanced topics in physics and game development.