C with Raylib

Setup

  • Install clang :

  • Get the latest RayLib release :

  • File system :

    ๎—ฟ .
    โ”œโ”€โ”€ ๎˜ž main.c    // the main file where the game is
    โ””โ”€โ”€ ๎—ฟ raylib    // folder where I put the downloaded raylib
        โ”œโ”€โ”€ ๓ฐ‚บ README.md
        โ”œโ”€โ”€ ๏€ญ LICENSE
        โ”œโ”€โ”€ ๏€– CHANGELOG
        โ”œโ”€โ”€ ๎—ฟ lib
        โ”‚   โ”œโ”€โ”€ ๎ฎœ raylib.dll
        โ”‚   โ”œโ”€โ”€ ๏…ผ libraylibdll.a
        โ”‚   โ””โ”€โ”€ ๏…ผ libraylib.a
        โ””โ”€โ”€ ๎—ผ include
            โ”œโ”€โ”€ ๎˜ž rlgl.h
            โ”œโ”€โ”€ ๎˜ž raymath.h
            โ””โ”€โ”€ ๎˜ž raylib.h
    
  • Compile :

    • clang main.c -o main.exe -Lraylib/lib -lraylib -lopengl32 -lgdi32 -lwinmm

      • clang

        • Invokes the Clang C compiler.

      • main.c

        • Source file to compile.

      • -o main.exe

        • Sets the output executable name.

      • -Lraylib/lib

        • Adds this directory to the linkerโ€™s search paths.

        • Clang will look here when resolving -l...  flags.

      • -lraylib

        • Links against:

          • raylib/lib/libraylib.a  (static)

          • or

          • raylib/lib/libraylibdll.a  (import lib for DLL)

        • The linker automatically resolves:

          • -lraylib  โ†’ libraylib.a

      • -lopengl32

        • Windows system library, required for raylib.

        • Links OpenGL (graphics backend)

      • -lgdi32

        • Windows system library, required for raylib.

        • Windows GDI (window/context handling pieces)

      • -lwinmm

        • Windows system library, required for raylib.

        • Windows multimedia (timing, audio support)

  • Execute :

    • .\main.exe

Moving Ball

/* 
clang main.c -o main.exe -L../raylib/lib -lraylib -lopengl32 -lgdi32 -lwinmm
*/

#include "../raylib/include/raylib.h"


int main(void) {
    const int SCREEN_WIDTH  = 800;
    const int SCREEN_HEIGHT = 450;

    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Raylib in C | 1_moving_ball");
    SetTargetFPS(60);

    // Initialize ball
    Vector2 ball_position = { (float)SCREEN_WIDTH/2, (float)SCREEN_HEIGHT/2 };

    while (!WindowShouldClose()) {
        // Update ball position
        if (IsKeyDown(KEY_RIGHT)) ball_position.x += 2.0f;
        if (IsKeyDown(KEY_LEFT))  ball_position.x -= 2.0f;
        if (IsKeyDown(KEY_UP))    ball_position.y -= 2.0f;
        if (IsKeyDown(KEY_DOWN))  ball_position.y += 2.0f;

        // Draw
        BeginDrawing();
        ClearBackground(RAYWHITE);

        DrawText("move the ball with arrow keys", 10, 10, 20, DARKGRAY);
        DrawCircleV(ball_position, 50, MAROON);
        
        EndDrawing();
    }

    CloseWindow();

    return 0;
}

Collect The Coins

/* 
clang main.c -o main.exe -L../raylib/lib -lraylib -lopengl32 -lgdi32 -lwinmm
*/

#include "../raylib/include/raylib.h"
#include "../raylib/include/raymath.h"

#include <stdbool.h>

#define MAX_COINS 20
#define PLAYER_SPEED 4.0f

typedef struct Player {
    Vector2 position;
    float   radius;
    int     score;
} Player;

typedef struct Coin {
    Vector2 position;
    float   radius;
    bool    active;
} Coin;

int main(void) {
    const int SCREEN_WIDTH = 800;
    const int SCREEN_HEIGHT = 600;

    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Raylib in C | 2_collect_the_coins");
    SetTargetFPS(60);

    // Initialize player
    Player player = {0};
    player.position = (Vector2){400, 300};
    player.radius = 20;
    player.score = 0;

    // Initialize coins
    Coin coins[MAX_COINS];
    for (int i = 0; i < MAX_COINS; i++) {
        coins[i].position = (Vector2){
            GetRandomValue(20, SCREEN_WIDTH - 20),
            GetRandomValue(20, SCREEN_HEIGHT - 20)
        };
        coins[i].radius = 8;
        coins[i].active = true;
    }

    while (!WindowShouldClose()) {
        // Update player
        if (IsKeyDown(KEY_W)) player.position.y -= PLAYER_SPEED;
        if (IsKeyDown(KEY_S)) player.position.y += PLAYER_SPEED;
        if (IsKeyDown(KEY_A)) player.position.x -= PLAYER_SPEED;
        if (IsKeyDown(KEY_D)) player.position.x += PLAYER_SPEED;

        // Check collisions
        for (int i = 0; i < MAX_COINS; i++) {
            if (coins[i].active)
            {
                float dist = Vector2Distance(player.position, coins[i].position);

                if (dist < player.radius + coins[i].radius)
                {
                    coins[i].active = false;
                    player.score += 1;
                }
            }
        }

        // Draw
        BeginDrawing();
        ClearBackground(DARKGREEN);

        DrawCircleV(player.position, player.radius, BLUE);
        for (int i = 0; i < MAX_COINS; i++) {
            if (coins[i].active) {
                DrawCircleV(coins[i].position, coins[i].radius, GOLD);
            }
        }
        DrawText(TextFormat("Score: %d", player.score), 10, 10, 20, WHITE);

        EndDrawing();
    }

    CloseWindow();
    return 0;
}

Space Invaders

/* 
clang main.c -o main.exe -L../raylib/lib -lraylib -lopengl32 -lgdi32 -lwinmm
*/

#include "../raylib/include/raylib.h"
#include "../raylib/include/raymath.h"

#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>

#define MAX_BULLETS  64
#define BULLET_SPEED 6.0f

typedef struct {
    Vector2 position;
    float   radius;
} Player;

typedef struct {
    Vector2 position;
    Vector2 velocity;
    float   radius;
    bool    active;
} Bullet;

typedef struct {
    Vector2 position;
    float   radius;
    bool    active;
    Color   color;
} Enemy;

void spawn_bullet(Bullet bullets[], int count, Vector2 pos);
void spawn_inactive_enemies(Enemy* enemies, int enemies_count);

int main(void) {
    const int SCREEN_WIDTH = 800;
    const int SCREEN_HEIGHT = 600;

    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Raylib in C | 3_space_invaders");
    SetTargetFPS(60);

    // Initialize player
    Player player = { (Vector2){400, 500}, 20 }; 
    Bullet bullets[MAX_BULLETS] = {0}; // Stack allocation

    // Initialize enemies
    int enemies_count = 20;
    Enemy* enemies = malloc(sizeof(Enemy) * enemies_count); // Heap allocation
    int enemies_destroyed_count = 0;
    spawn_inactive_enemies(enemies, enemies_count);

    while (!WindowShouldClose()) {
        // Update player
        if (IsKeyDown(KEY_A)) player.position.x -= 4;
        if (IsKeyDown(KEY_D)) player.position.x += 4;
        if (IsKeyDown(KEY_W)) player.position.y -= 4;
        if (IsKeyDown(KEY_S)) player.position.y += 4;
        if (IsKeyPressed(KEY_SPACE)) {
            spawn_bullet(bullets, MAX_BULLETS, player.position);
        }

        // Update bullets
        for (int i = 0; i < MAX_BULLETS; i++) {
            if (bullets[i].active) {
                bullets[i].position.x += bullets[i].velocity.x;
                bullets[i].position.y += bullets[i].velocity.y;

                if (bullets[i].position.y < 0) {
                    bullets[i].active = false;
                }
            }
        }

        // Update enemies
        int active_enemies = 0;
        for (int i = 0; i < enemies_count; i++) {
            if (enemies[i].active) {
                enemies[i].position.y += 0.5f;
                active_enemies += 1;
            }
        }

        // Respawn inactive enemies
        if (active_enemies < 5) {
            spawn_inactive_enemies(enemies, enemies_count);
        }

        // Check Collisions
        for (int i = 0; i < MAX_BULLETS; i++) {
            if (!bullets[i].active) continue;

            for (int j = 0; j < enemies_count; j++) {
                if (!enemies[j].active) continue;

                float d = Vector2Distance(bullets[i].position, enemies[j].position);
                float r = bullets[i].radius + enemies[j].radius;

                if (d < r) {
                    bullets[i].active = false;
                    enemies[j].active = false;
                    enemies_destroyed_count += 1;
                }
            }
        }

        BeginDrawing();
        ClearBackground(BLACK);

        DrawCircleV(player.position, player.radius, BLUE);

        for (int i = 0; i < MAX_BULLETS; i++) {
            if (bullets[i].active) {
                DrawCircleV(bullets[i].position, bullets[i].radius, YELLOW);
            }
        }
        for (int i = 0; i < enemies_count; i++) {
            if (enemies[i].active) {
                DrawCircleV(enemies[i].position, enemies[i].radius, enemies[i].color);
            }
        }

        DrawText("Space Invaders: WASD move | SPACE shoot", 10, 10, 20, WHITE);

        char buffer[64];
        snprintf(buffer, sizeof(buffer), "Enemies destroyed: %d", enemies_destroyed_count);
        DrawText(buffer, 10, 40, 20, YELLOW);

        EndDrawing();
    }

    free(enemies);

    CloseWindow();
    return 0;
}


void spawn_bullet(Bullet bullets[], int count, Vector2 pos) {
    for (int i = 0; i < count; i++) {
        if (!bullets[i].active) {
            bullets[i].active = true;
            bullets[i].position = pos;
            bullets[i].velocity = (Vector2){0, -BULLET_SPEED};
            bullets[i].radius = 5;
            return;
        }
    }
}

void spawn_inactive_enemies(Enemy* enemies, int enemies_count) {
    for (int i = 0; i < enemies_count; i++) {
        if (!enemies[i].active) {
            enemies[i].position = (Vector2){
                GetRandomValue(50, 750),
                GetRandomValue(50, 300)
            };
            enemies[i].radius = 15;
            enemies[i].active = true;
            enemies[i].color = (Color){ GetRandomValue(100, 255), GetRandomValue(100, 255), GetRandomValue(100, 255), 255 };
        }
    }
}

Other Examples