Skip to main content

Spell system overview

Wizard Duel features two distinct spells, each with unique properties. Spells are cast toward your mouse cursor position in world coordinates and travel automatically toward their target.
struct Ball{
    Color spellColor = RED;
    Vector2 ball_pos = {};
    Vector2 target_pos = {};  // Renamed from mouse_pos
    float ball_r = 25.0f;
    float ball_speed;
    float damage = 0.0f;
};

Red spell

The red spell is a slower, larger projectile with higher radius and damage.
Keybind
string
Hold KEY_ONE (1) + Left Mouse Button
Mana cost
float
25.0f (requires at least 25.0f mana to cast)
Color
color
bloodRed { 128, 0, 0, 255 }
Speed
float
2.0f units per frame
Initial radius
float
35.0f pixels
Damage
float
Calculated as 1.0f * ball_r (35.0f damage at full radius)
if (IsKeyDown(KEY_ONE)){
    if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)){
        if (all_players[0].mana >= 25.0f){
            Ball red_ball;
            all_players[0].is_cast = true;
            red_ball.target_pos = mouse_world;
            all_players[0].mana = all_players[0].mana - 5.0f;
            red_ball.spellColor = bloodRed;
            red_ball.ball_speed = 2.0f;
            red_ball.ball_pos = all_players[0].pos;
            red_ball.ball_r = 35.0f;
            red_ball.damage = 1.0f * red_ball.ball_r;
            ball_vec.push_back(red_ball);
        }
    }
}
The red spell’s larger radius (35.0f) makes it easier to hit targets but travels slower at 2.0f speed.

Blue spell

The blue spell is a faster projectile with standard radius, requiring more mana to cast.
Keybind
string
Hold KEY_TWO (2) + Left Mouse Button
Mana cost
float
35.0f (requires at least 35.0f mana to cast)
Color
color
DARKBLUE (Raylib DARKBLUE constant)
Speed
float
4.0f units per frame (2x faster than red spell)
Initial radius
float
25.0f pixels (default Ball radius)
Damage
float
Calculated as 1.0f * ball_r (25.0f damage at full radius)
else if (IsKeyDown(KEY_TWO)){
    if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)){
        if (all_players[0].mana >= 35.0f){
            Ball blue_ball;
            all_players[0].is_cast = true;
            blue_ball.target_pos = mouse_world;
            all_players[0].mana = all_players[0].mana - 5.0f;
            blue_ball.spellColor = DARKBLUE;
            blue_ball.ball_pos = all_players[0].pos;
            blue_ball.ball_speed = 4.0f;
            blue_ball.damage = 1.0f * blue_ball.ball_r;
            ball_vec.push_back(blue_ball);
        }
    }
}
The blue spell is twice as fast (4.0f vs 2.0f) but costs more mana and has a smaller radius.

Spell mechanics

Projectile movement

Spells travel toward their target position using normalized direction vectors:
Vector2 direction = {
    current_ball.target_pos.x - current_ball.ball_pos.x,
    current_ball.target_pos.y - current_ball.ball_pos.y
};

float length = sqrt(direction.x * direction.x +
                   direction.y * direction.y);

if (length > 1.0f)
{
    direction.x /= length;
    direction.y /= length;

    current_ball.ball_pos.x += direction.x * current_ball.ball_speed;
    current_ball.ball_pos.y += direction.y * current_ball.ball_speed;
}

Spell decay

All spells shrink over time at a rate of 0.1f radius per frame:
current_ball.ball_r -= 0.1f;
Spells automatically despawn when their radius reaches zero. Plan your shots carefully!

Tree collision

Spells can destroy trees when colliding with them:
for (int b = 0; b < ball_vec.size(); b++) {
    for (int t = 0; t < tree_pos.size(); t++) {
        Rectangle tree_rect = { tree_pos[t].x, tree_pos[t].y, 20, 60 };

        if (CheckCollisionCircleRec(
                ball_vec[b].ball_pos,
                ball_vec[b].ball_r,
                tree_rect))
        {
            if (ball_vec[b].ball_r >= 4.0f){
                tree_pos[t] = {0, 0};
            }
            ball_vec[b].ball_r -= 5.0f;
            break;
        }
    }
}
Trees are destroyed if the spell radius is at least 4.0f. Each collision reduces spell radius by 5.0f.

Spell comparison

Strengths:
  • Lower mana cost (25.0f vs 35.0f)
  • Larger radius (35.0f vs 25.0f) = easier to hit
  • Higher damage (35.0f vs 25.0f)
Weaknesses:
  • Slower travel speed (2.0f vs 4.0f)
  • Easier for opponents to dodge

Build docs developers (and LLMs) love