Code Examples

Ready-to-use code snippets and complete examples for SSOEngine

🎯 Basic Examples

Window Setup and Basic Loop

#include "raylib.h"
#include "tools/sso_window.h"

int main() {
    // Initialize window
    SSO::Window window("My Game", 1280, 720);
    window.SetVSync(true);
    window.Center();
    
    // Main game loop
    while (!window.ShouldClose()) {
        // Update logic here
        
        // Rendering
        BeginDrawing();
        ClearBackground(RAYWHITE);
        DrawText("Hello SSOEngine!", 10, 10, 20, BLACK);
        EndDrawing();
    }
    
    return 0;
}

Basic Input Handling

#include "raylib.h"

struct InputState {
    bool up;
    bool down;
    bool left;
    bool right;
    bool action;
    Vector2 mousePosition;
    bool mouseClicked;
};

inline InputState input;

void UpdateInput() {
    // Keyboard input
    input.up = IsKeyDown(KEY_UP) || IsKeyDown(KEY_W);
    input.down = IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S);
    input.left = IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A);
    input.right = IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D);
    input.action = IsKeyPressed(KEY_SPACE) || IsMouseButtonPressed(MOUSE_LEFT_BUTTON);
    
    // Mouse input
    input.mousePosition = GetMousePosition();
    input.mouseClicked = IsMouseButtonPressed(MOUSE_LEFT_BUTTON);
}

// Usage in game loop
void UpdateGame() {
    UpdateInput();
    
    // Move player based on input
    Vector2 movement = {0, 0};
    if (input.left) movement.x -= 5;
    if (input.right) movement.x += 5;
    if (input.up) movement.y -= 5;
    if (input.down) movement.y += 5;
    
    player.position.x += movement.x;
    player.position.y += movement.y;
}

Basic Drawing Operations

#include "raylib.h"

void DrawShapes() {
    // Basic shapes
    DrawCircle(100, 100, 50, RED);
    DrawRectangle(200, 50, 100, 100, BLUE);
    DrawTriangle({350, 150}, {400, 50}, {450, 150}, GREEN);
    
    // Lines and borders
    DrawLine(0, 0, 1280, 720, YELLOW);
    DrawRectangleLines(500, 200, 150, 100, PURPLE);
    
    // Text rendering
    DrawText("Hello World!", 10, 10, 20, BLACK);
    DrawText(TextFormat("Score: %d", score), 10, 40, 20, BLACK);
    
    // Custom colors and transparency
    Color customColor = {255, 128, 64, 255};  // Orange
    DrawCircle(700, 100, 30, customColor);
    
    // Transparent shapes
    DrawRectangle(800, 50, 100, 100, Fade(RED, 0.5f));
}

void DrawWithTexture() {
    // Load texture (usually done once at startup)
    Texture2D texture = LoadTexture("assets/player.png");
    
    // Draw texture
    DrawTexture(texture, 100, 100, WHITE);
    
    // Draw scaled texture
    DrawTextureEx(texture, {200, 200}, 0, 2.0f, WHITE);
    
    // Draw part of texture (source rectangle)
    Rectangle sourceRect = {0, 0, 32, 32};  // First 32x32 pixels
    DrawTextureRec(texture, sourceRect, {300, 300}, WHITE);
    
    // Don't forget to unload when done
    UnloadTexture(texture);
}

🎮 Game Mechanics

Smooth Player Movement

#include "raylib.h"
#include "tools/sso_math.h"

struct Player {
    Vector2 position;
    Vector2 velocity;
    float speed;
    float radius;
    Color color;
};

inline Player player = {{640, 360}, {0, 0}, 300.0f, 20.0f, BLUE};

void UpdatePlayer(float deltaTime) {
    // Get input
    Vector2 input = {0, 0};
    if (IsKeyDown(KEY_RIGHT)) input.x += 1;
    if (IsKeyDown(KEY_LEFT)) input.x -= 1;
    if (IsKeyDown(KEY_UP)) input.y -= 1;
    if (IsKeyDown(KEY_DOWN)) input.y += 1;
    
    // Normalize diagonal movement
    if (input.x != 0 && input.y != 0) {
        input = SSO::Math::Normalize(input);
    }
    
    // Apply acceleration
    Vector2 acceleration = SSO::Math::Scale(input, 1000.0f);
    player.velocity = SSO::Math::Lerp(player.velocity, 
                                      SSO::Math::Add(player.velocity, acceleration), 
                                      deltaTime * 10.0f);
    
    // Limit speed
    float currentSpeed = SSO::Math::Magnitude(player.velocity);
    if (currentSpeed > player.speed) {
        player.velocity = SSO::Math::Scale(player.velocity, player.speed / currentSpeed);
    }
    
    // Update position
    player.position = SSO::Math::Add(player.position, 
                                     SSO::Math::Scale(player.velocity, deltaTime));
    
    // Keep player on screen
    player.position.x = Clamp(player.position.x, player.radius, 1280 - player.radius);
    player.position.y = Clamp(player.position.y, player.radius, 720 - player.radius);
}

Collision Detection System

#include "raylib.h"
#include "tools/sso_math.h"
#include 

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

inline std::vector enemies;

// Circle-circle collision
bool CheckCircleCollision(Vector2 pos1, float radius1, Vector2 pos2, float radius2) {
    float distance = SSO::Math::Distance(pos1, pos2);
    return distance < (radius1 + radius2);
}

// Rectangle-circle collision
bool CheckRectCircleCollision(Rectangle rect, Vector2 circlePos, float radius) {
    // Find closest point on rectangle to circle center
    Vector2 closest = {
        Clamp(circlePos.x, rect.x, rect.x + rect.width),
        Clamp(circlePos.y, rect.y, rect.y + rect.height)
    };
    
    // Check if closest point is within circle
    float distance = SSO::Math::Distance(circlePos, closest);
    return distance < radius;
}

// Line-circle collision
bool CheckLineCircleCollision(Vector2 start, Vector2 end, Vector2 circlePos, float radius) {
    Vector2 lineVec = SSO::Math::Subtract(end, start);
    Vector2 toCircle = SSO::Math::Subtract(circlePos, start);
    
    float lineLength = SSO::Math::Magnitude(lineVec);
    Vector2 lineDir = SSO::Math::Normalize(lineVec);
    
    // Project circle center onto line
    float projection = SSO::Math::Dot(toCircle, lineDir);
    projection = Clamp(projection, 0, lineLength);
    
    Vector2 closestPoint = SSO::Math::Add(start, SSO::Math::Scale(lineDir, projection));
    
    float distance = SSO::Math::Distance(circlePos, closestPoint);
    return distance < radius;
}

void UpdateCollisions() {
    // Check player-enemy collisions
    for (auto& enemy : enemies) {
        if (enemy.active && CheckCircleCollision(player.position, player.radius, 
                                               enemy.position, enemy.radius)) {
            // Collision detected!
            TakeDamage();
            enemy.active = false;
        }
    }
    
    // Check bullet-enemy collisions
    for (auto& bullet : bullets) {
        if (!bullet.active) continue;
        
        for (auto& enemy : enemies) {
            if (enemy.active && CheckCircleCollision(bullet.position, bullet.radius,
                                                   enemy.position, enemy.radius)) {
                bullet.active = false;
                enemy.active = false;
                CreateExplosion(enemy.position);
                score += 100;
            }
        }
    }
}

Advanced Camera Following

#include "raylib.h"
#include "tools/sso_camera.h"
#include "tools/sso_math.h"

SSO::Camera mainCam({0, 0}, 1280, 720);

void UpdateCamera(float deltaTime) {
    // Basic following
    mainCam.Follow(player.position);
    
    // Dynamic zoom based on player speed
    float playerSpeed = SSO::Math::Magnitude(player.velocity);
    float targetZoom = 1.0f + (playerSpeed / player.maxSpeed) * 0.3f;
    float currentZoom = mainCam.GetZoom();
    mainCam.SetZoom(SSO::Math::Lerp(currentZoom, targetZoom, 0.05f));
    
    // Look-ahead based on velocity
    Vector2 lookAhead = SSO::Math::Scale(player.velocity, 0.2f);
    Vector2 targetPos = SSO::Math::Add(player.position, lookAhead);
    mainCam.Follow(targetPos);
    
    // Screen shake on events
    if (explosionActive) {
        mainCam.Shake(15.0f, 0.3f);
        explosionActive = false;
    }
    
    // Camera boundaries
    Rectangle worldBounds = {-2000, -2000, 4000, 4000};
    mainCam.SetBounds(worldBounds);
    
    // Update camera
    mainCam.Update(deltaTime);
}

void RenderGame() {
    BeginMode2D(mainCam.GetCamera2D());
    
    // Draw world grid
    for (int x = -2000; x <= 2000; x += 100) {
        DrawLine(x, -2000, x, 2000, Fade(GRAY, 0.3f));
    }
    for (int y = -2000; y <= 2000; y += 100) {
        DrawLine(-2000, y, 2000, y, Fade(GRAY, 0.3f));
    }
    
    // Draw game objects
    DrawPlayer();
    DrawEnemies();
    DrawBullets();
    
    EndMode2D();
    
    // Draw UI (not affected by camera)
    DrawUI();
}

Simple Particle System

#include "raylib.h"
#include "tools/sso_math.h"
#include 

struct Particle {
    Vector2 position;
    Vector2 velocity;
    float life;
    float maxLife;
    Color color;
    float size;
};

inline std::vector particles;

void CreateExplosion(Vector2 position, int count = 20) {
    for (int i = 0; i < count; i++) {
        Particle particle;
        particle.position = position;
        
        // Random velocity in all directions
        float angle = (float)i / count * 2.0f * PI;
        float speed = SSO::Math::RandomRange(50.0f, 200.0f);
        particle.velocity = {
            cos(angle) * speed,
            sin(angle) * speed
        };
        
        particle.life = 1.0f;
        particle.maxLife = SSO::Math::RandomRange(0.5f, 1.5f);
        particle.color = {
            (unsigned char)SSO::Math::RandomRange(200, 255),
            (unsigned char)SSO::Math::RandomRange(50, 200),
            0,
            255
        };
        particle.size = SSO::Math::RandomRange(2.0f, 8.0f);
        
        particles.push_back(particle);
    }
}

void UpdateParticles(float deltaTime) {
    for (auto& particle : particles) {
        // Update position
        particle.position = SSO::Math::Add(particle.position, 
                                          SSO::Math::Scale(particle.velocity, deltaTime));
        
        // Apply gravity
        particle.velocity.y += 200.0f * deltaTime;
        
        // Apply friction
        particle.velocity = SSO::Math::Scale(particle.velocity, 0.98f);
        
        // Update life
        particle.life -= deltaTime / particle.maxLife;
    }
    
    // Remove dead particles
    particles.erase(
        std::remove_if(particles.begin(), particles.end(),
                      [](const Particle& p) { return p.life <= 0; }),
        particles.end()
    );
}

void DrawParticles() {
    for (const auto& particle : particles) {
        float alpha = particle.life;
        Color color = Fade(particle.color, alpha);
        float size = particle.size * particle.life;
        
        DrawCircleV(particle.position, size, color);
    }
}

🕹️ Complete Game Examples

Pong Game

A complete Pong game implementation:

#include "raylib.h"
#include "tools/sso_camera.h"
#include "tools/sso_math.h"
#include "tools/sso_ui.h"

struct Paddle {
    Rectangle rect;
    float speed;
    Color color;
};

struct Ball {
    Vector2 position;
    Vector2 velocity;
    float radius;
    Color color;
};

inline Paddle player1 = {{50, 300, 15, 100}, 400, WHITE};
inline Paddle player2 = {{1215, 300, 15, 100}, 400, WHITE};
inline Ball ball = {{640, 360}, {200, 150}, 10, WHITE};

inline int player1Score = 0;
inline int player2Score = 0;
inline bool gamePaused = false;

void InitPong() {
    ball.position = {640, 360};
    ball.velocity = {(float)GetRandomValue(-200, 200), (float)GetRandomValue(-150, 150)};
    player1.rect.y = 300;
    player2.rect.y = 300;
}

void UpdatePaddles(float deltaTime) {
    // Player 1 controls (W/S)
    if (IsKeyDown(KEY_W)) {
        player1.rect.y -= player1.speed * deltaTime;
    }
    if (IsKeyDown(KEY_S)) {
        player1.rect.y += player1.speed * deltaTime;
    }
    
    // Player 2 controls (UP/DOWN arrows)
    if (IsKeyDown(KEY_UP)) {
        player2.rect.y -= player2.speed * deltaTime;
    }
    if (IsKeyDown(KEY_DOWN)) {
        player2.rect.y += player2.speed * deltaTime;
    }
    
    // Keep paddles on screen
    player1.rect.y = Clamp(player1.rect.y, 0, 720 - player1.rect.height);
    player2.rect.y = Clamp(player2.rect.y, 0, 720 - player2.rect.height);
}

void UpdateBall(float deltaTime) {
    if (gamePaused) return;
    
    // Update position
    ball.position.x += ball.velocity.x * deltaTime;
    ball.position.y += ball.velocity.y * deltaTime;
    
    // Top and bottom wall collision
    if (ball.position.y - ball.radius <= 0 || ball.position.y + ball.radius >= 720) {
        ball.velocity.y = -ball.velocity.y;
        ball.position.y = Clamp(ball.position.y, ball.radius, 720 - ball.radius);
    }
    
    // Paddle collisions
    Rectangle ballRect = {
        ball.position.x - ball.radius,
        ball.position.y - ball.radius,
        ball.radius * 2,
        ball.radius * 2
    };
    
    if (CheckCollisionRecs(ballRect, player1.rect)) {
        ball.velocity.x = fabs(ball.velocity.x);  // Move right
        ball.position.x = player1.rect.x + player1.rect.width + ball.radius;
        
        // Add spin based on paddle hit position
        float hitPos = (ball.position.y - (player1.rect.y + player1.rect.height/2)) / (player1.rect.height/2);
        ball.velocity.y += hitPos * 100;
    }
    
    if (CheckCollisionRecs(ballRect, player2.rect)) {
        ball.velocity.x = -fabs(ball.velocity.x);  // Move left
        ball.position.x = player2.rect.x - ball.radius;
        
        // Add spin based on paddle hit position
        float hitPos = (ball.position.y - (player2.rect.y + player2.rect.height/2)) / (player2.rect.height/2);
        ball.velocity.y += hitPos * 100;
    }
    
    // Score detection
    if (ball.position.x < 0) {
        player2Score++;
        InitPong();
    }
    if (ball.position.x > 1280) {
        player1Score++;
        InitPong();
    }
}

void DrawPong() {
    // Draw center line
    for (int y = 0; y < 720; y += 20) {
        DrawRectangle(635, y, 10, 10, WHITE);
    }
    
    // Draw paddles
    DrawRectangleRec(player1.rect, player1.color);
    DrawRectangleRec(player2.rect, player2.color);
    
    // Draw ball
    DrawCircleV(ball.position, ball.radius, ball.color);
    
    // Draw scores
    DrawText(TextFormat("%d", player1Score), 580, 50, 60, WHITE);
    DrawText(TextFormat("%d", player2Score), 660, 50, 60, WHITE);
    
    // Draw pause indicator
    if (gamePaused) {
        DrawText("PAUSED", 550, 350, 40, WHITE);
        DrawText("Press SPACE to resume", 520, 400, 20, WHITE);
    }
}

void UpdatePongGame(float deltaTime) {
    // Handle pause
    if (IsKeyPressed(KEY_SPACE)) {
        gamePaused = !gamePaused;
    }
    
    UpdatePaddles(deltaTime);
    UpdateBall(deltaTime);
}

int main() {
    InitWindow(1280, 720, "SSOEngine - Pong");
    SetTargetFPS(60);
    
    InitPong();
    
    while (!WindowShouldClose()) {
        float deltaTime = GetFrameTime();
        
        UpdatePongGame(deltaTime);
        
        BeginDrawing();
        ClearBackground(BLACK);
        DrawPong();
        DrawText("ESC to quit", 10, 690, 20, GRAY);
        EndDrawing();
    }
    
    CloseWindow();
    return 0;
}

Space Shooter

Basic space shooter with enemies and shooting:

#include "raylib.h"
#include "tools/sso_camera.h"
#include "tools/sso_math.h"
#include 

struct Bullet {
    Vector2 position;
    Vector2 velocity;
    bool active;
    float lifetime;
};

struct Enemy {
    Vector2 position;
    Vector2 velocity;
    bool active;
    float health;
    float shootCooldown;
};

inline std::vector bullets;
inline std::vector enemies;
inline Vector2 playerPos = {640, 600};
inline float playerSpeed = 300.0f;
inline float shootCooldown = 0.0f;
inline int score = 0;
inline bool gameOver = false;

void InitGame() {
    playerPos = {640, 600};
    bullets.clear();
    enemies.clear();
    score = 0;
    gameOver = false;
    shootCooldown = 0.0f;
    
    // Spawn initial enemies
    for (int i = 0; i < 5; i++) {
        Enemy enemy;
        enemy.position = {(float)GetRandomValue(100, 1180), (float)GetRandomValue(50, 200)};
        enemy.velocity = {(float)GetRandomValue(-50, 50), 0};
        enemy.active = true;
        enemy.health = 2.0f;
        enemy.shootCooldown = 0.0f;
        enemies.push_back(enemy);
    }
}

void UpdatePlayer(float deltaTime) {
    // Movement
    Vector2 input = {0, 0};
    if (IsKeyDown(KEY_LEFT)) input.x -= 1;
    if (IsKeyDown(KEY_RIGHT)) input.x += 1;
    if (IsKeyDown(KEY_UP)) input.y -= 1;
    if (IsKeyDown(KEY_DOWN)) input.y += 1;
    
    input = SSO::Math::Normalize(input);
    playerPos = SSO::Math::Add(playerPos, SSO::Math::Scale(input, playerSpeed * deltaTime));
    
    // Keep player on screen
    playerPos.x = Clamp(playerPos.x, 20, 1260);
    playerPos.y = Clamp(playerPos.y, 20, 700);
    
    // Shooting
    shootCooldown -= deltaTime;
    if (IsKeyDown(KEY_SPACE) && shootCooldown <= 0) {
        Bullet bullet;
        bullet.position = playerPos;
        bullet.velocity = {0, -500};
        bullet.active = true;
        bullet.lifetime = 2.0f;
        bullets.push_back(bullet);
        shootCooldown = 0.2f;
    }
}

void UpdateBullets(float deltaTime) {
    for (auto& bullet : bullets) {
        if (!bullet.active) continue;
        
        bullet.position = SSO::Math::Add(bullet.position, 
                                         SSO::Math::Scale(bullet.velocity, deltaTime));
        bullet.lifetime -= deltaTime;
        
        // Remove if off screen or expired
        if (bullet.position.y < 0 || bullet.lifetime <= 0) {
            bullet.active = false;
        }
    }
}

void UpdateEnemies(float deltaTime) {
    for (auto& enemy : enemies) {
        if (!enemy.active) continue;
        
        // Movement
        enemy.position = SSO::Math::Add(enemy.position, 
                                       SSO::Math::Scale(enemy.velocity, deltaTime));
        
        // Bounce off screen edges
        if (enemy.position.x <= 20 || enemy.position.x >= 1260) {
            enemy.velocity.x = -enemy.velocity.x;
        }
        
        // Enemy shooting
        enemy.shootCooldown -= deltaTime;
        if (enemy.shootCooldown <= 0) {
            // Simple AI: shoot when aligned with player
            if (fabs(enemy.position.x - playerPos.x) < 50) {
                Bullet bullet;
                bullet.position = enemy.position;
                bullet.velocity = {0, 200};
                bullet.active = true;
                bullet.lifetime = 3.0f;
                bullets.push_back(bullet);
                enemy.shootCooldown = 2.0f;
            }
        }
    }
}

void CheckCollisions() {
    // Player bullets vs enemies
    for (auto& bullet : bullets) {
        if (!bullet.active) continue;
        
        for (auto& enemy : enemies) {
            if (!enemy.active) continue;
            
            if (SSO::Math::Distance(bullet.position, enemy.position) < 20) {
                bullet.active = false;
                enemy.health -= 1.0f;
                
                if (enemy.health <= 0) {
                    enemy.active = false;
                    score += 100;
                    
                    // Spawn new enemy
                    Enemy newEnemy;
                    newEnemy.position = {(float)GetRandomValue(100, 1180), 50};
                    newEnemy.velocity = {(float)GetRandomValue(-50, 50), 20};
                    newEnemy.active = true;
                    newEnemy.health = 2.0f;
                    newEnemy.shootCooldown = 0.0f;
                    enemies.push_back(newEnemy);
                }
                break;
            }
        }
    }
    
    // Enemy bullets vs player
    for (auto& bullet : bullets) {
        if (!bullet.active) continue;
        
        // Check if it's an enemy bullet (moving down)
        if (bullet.velocity.y > 0) {
            if (SSO::Math::Distance(bullet.position, playerPos) < 20) {
                bullet.active = false;
                gameOver = true;
            }
        }
    }
    
    // Enemies vs player
    for (auto& enemy : enemies) {
        if (!enemy.active) continue;
        
        if (SSO::Math::Distance(enemy.position, playerPos) < 30) {
            gameOver = true;
        }
    }
}

void DrawGame() {
    // Draw player
    DrawTriangle(
        {playerPos.x, playerPos.y - 15},
        {playerPos.x - 10, playerPos.y + 15},
        {playerPos.x + 10, playerPos.y + 15},
        WHITE
    );
    
    // Draw enemies
    for (const auto& enemy : enemies) {
        if (enemy.active) {
            DrawRectangle(enemy.position.x - 15, enemy.position.y - 10, 30, 20, RED);
        }
    }
    
    // Draw bullets
    for (const auto& bullet : bullets) {
        if (bullet.active) {
            Color bulletColor = (bullet.velocity.y < 0) ? YELLOW : ORANGE;
            DrawCircleV(bullet.position, 3, bulletColor);
        }
    }
    
    // Draw UI
    DrawText(TextFormat("Score: %d", score), 10, 10, 30, WHITE);
    
    if (gameOver) {
        DrawText("GAME OVER", 550, 350, 60, RED);
        DrawText(TextFormat("Final Score: %d", score), 570, 420, 30, WHITE);
        DrawText("Press R to restart", 560, 470, 20, WHITE);
    }
}

int main() {
    InitWindow(1280, 720, "SSOEngine - Space Shooter");
    SetTargetFPS(60);
    
    InitGame();
    
    while (!WindowShouldClose()) {
        float deltaTime = GetFrameTime();
        
        if (!gameOver) {
            UpdatePlayer(deltaTime);
            UpdateBullets(deltaTime);
            UpdateEnemies(deltaTime);
            CheckCollisions();
        } else {
            if (IsKeyPressed(KEY_R)) {
                InitGame();
            }
        }
        
        BeginDrawing();
        ClearBackground(BLACK);
        DrawGame();
        EndDrawing();
    }
    
    CloseWindow();
    return 0;
}

💡 Tips and Best Practices

Performance Tips

  • • Use delta-time for all movement calculations
  • • Pool objects instead of creating/destroying
  • • Batch similar drawing operations
  • • Use spatial partitioning for many objects
  • • Profile your game regularly
  • • Optimize collision checks with early-outs

Code Organization

  • • Separate game logic from rendering
  • • Use header files for declarations
  • • Group related functionality
  • • Keep functions small and focused
  • • Use meaningful variable names
  • • Comment complex algorithms

Game Design Tips

  • • Start with simple mechanics
  • • Focus on core gameplay loop
  • • Add feedback for all actions
  • • Balance difficulty progression
  • • Test with different players
  • • Iterate based on feedback

Debugging Tips

  • • Add visual debug information
  • • Use logging for important events
  • • Test edge cases thoroughly
  • • Use breakpoints for complex bugs
  • • Save game state for testing
  • • Profile memory usage