Skip to content

Core Concepts

NtinosTheGamer2324 edited this page Mar 7, 2026 · 1 revision

BlitEngine Core Concepts

Understanding these concepts will help you build better games with BlitEngine.

The Game Loop

Every game runs in a continuous loop:

while (blit_is_running(&engine)) {
    // 1. INPUT - Read what the player is doing
    blit_update_input(&engine);
    
    // 2. UPDATE - Process game logic
    update_physics();
    check_collisions();
    update_ai();
    
    // 3. RENDER - Draw everything
    blit_begin_frame(&engine, 0xFF000000);
    draw_background();
    draw_game_objects();
    draw_ui();
    blit_end_frame(&engine);
}

This runs as fast as possible (typically 60+ times per second).

Sprites

Sprites are images you can draw on screen. Think of them as textures or pictures.

Creating Sprites

// Solid color rectangle
Sprite *red_box = blit_sprite_create_color(&engine, 32, 32, 0xFFFF0000);

// Circle
Sprite *blue_ball = blit_sprite_create_circle(&engine, 16, 0xFF0000FF);

// From pixel data
uint32_t pixels[64 * 64];
// ... fill pixels array ...
Sprite *custom = blit_sprite_create(&engine, 64, 64, pixels);

Using Sprites

// Draw at position (100, 200)
blit_sprite_draw(&engine, my_sprite, 100, 200);

// Draw multiple times (efficient!)
for (int i = 0; i < 10; i++) {
    blit_sprite_draw(&engine, coin_sprite, i * 50, 100);
}

Sprite Lifecycle

// 1. Create (once at startup)
Sprite *player_sprite = blit_sprite_create_color(&engine, 32, 32, 0xFF00FF00);

// 2. Use (every frame)
while (blit_is_running(&engine)) {
    blit_sprite_draw(&engine, player_sprite, x, y);
}

// 3. Free (at shutdown)
blit_sprite_free(&engine, player_sprite);

Important: Create sprites once, not every frame!

Entities

Entities are game objects with position, velocity, and optional sprite.

Why Use Entities?

Entities bundle together:

  • Position (x, y)
  • Velocity (vx, vy)
  • Size (width, height)
  • Visual (sprite)
  • State (active/inactive)
  • Custom data (user_data)

This makes game object management much easier!

Creating Entities

// Create sprite first
Sprite *player_sprite = blit_sprite_create_color(&engine, 32, 32, 0xFF00FF00);

// Create entity
Entity *player = blit_entity_create(
    100, 100,      // x, y position
    32, 32,        // width, height (for collision)
    player_sprite  // visual appearance
);

// Set velocity
player->vx = 5;   // Moves 5 pixels right per update
player->vy = -2;  // Moves 2 pixels up per update

Updating Entities

// Manual update
blit_entity_update(player);  // Adds vx to x, vy to y

// Or do it yourself
player->x += player->vx;
player->y += player->vy;

Drawing Entities

blit_entity_draw(&engine, player);

Entity Arrays

Managing multiple entities:

#define MAX_ENEMIES 20

Entity *enemies[MAX_ENEMIES];

// Initialize
for (int i = 0; i < MAX_ENEMIES; i++) {
    enemies[i] = blit_entity_create(
        blit_random_int(0, 800),
        blit_random_int(0, 600),
        24, 24,
        enemy_sprite
    );
    enemies[i]->vy = 2;  // Fall downward
}

// Update all
for (int i = 0; i < MAX_ENEMIES; i++) {
    if (enemies[i]->active) {
        blit_entity_update(enemies[i]);
    }
}

// Draw all
for (int i = 0; i < MAX_ENEMIES; i++) {
    if (enemies[i]->active) {
        blit_entity_draw(&engine, enemies[i]);
    }
}

Entity Utilities

// Check if on screen
if (blit_entity_on_screen(&engine, entity)) {
    blit_entity_draw(&engine, entity);
}

// Keep entity in bounds
blit_entity_clamp_to_screen(&engine, player);

// Collision detection
if (blit_entity_collides(player, enemy)) {
    printf("Hit!\n");
}

Entity Custom Data

Store game-specific data:

typedef struct {
    int health;
    int ammo;
    int score;
} PlayerData;

// Create and attach
PlayerData *data = malloc(sizeof(PlayerData));
data->health = 100;
data->ammo = 50;
player->user_data = data;

// Access later
PlayerData *pd = (PlayerData*)player->user_data;
pd->health -= 10;

Input System

BlitEngine handles input automatically.

Keyboard

// Check if key is currently held down
if (blit_key_down(&engine, KEY_W)) {
    player_y -= speed;  // Continuous movement
}

// Check if key was just pressed (one-shot)
if (blit_key_pressed(&engine, KEY_SPACE)) {
    fire_weapon();  // Fires once per press
}

Common Keys:

KEY_W, KEY_A, KEY_S, KEY_D         // WASD
KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT
KEY_SPACE, KEY_ENTER, KEY_ESC
KEY_1, KEY_2, KEY_3 ... KEY_0

Mouse

// Get position
int mx = engine.input.mouse_x;
int my = engine.input.mouse_y;

// Check buttons (held)
if (blit_mouse_down(&engine, MOUSE_LEFT)) {
    printf("Dragging...\n");
}

// Check buttons (clicked)
if (blit_mouse_clicked(&engine, MOUSE_LEFT)) {
    printf("Just clicked!\n");
}

Mouse Buttons:

MOUSE_LEFT    // Left button (bit 1)
MOUSE_RIGHT   // Right button (bit 2)
MOUSE_MIDDLE  // Middle button (bit 4)

Input Patterns

Movement:

// Smooth 8-direction movement
if (blit_key_down(&engine, KEY_W)) player->vy = -3;
if (blit_key_down(&engine, KEY_S)) player->vy = 3;
if (blit_key_down(&engine, KEY_A)) player->vx = -3;
if (blit_key_down(&engine, KEY_D)) player->vx = 3;

// Apply friction when no keys pressed
if (!blit_key_down(&engine, KEY_A) && !blit_key_down(&engine, KEY_D)) {
    player->vx *= 0.9;
}

Button Actions:

// Prevent rapid-fire with key_pressed (not key_down)
if (blit_key_pressed(&engine, KEY_SPACE)) {
    fire_bullet();  // Only fires when key first pressed
}

Mouse Targeting:

// Point entity toward mouse
int dx = engine.input.mouse_x - player->x;
int dy = engine.input.mouse_y - player->y;
float angle = atan2(dy, dx);  // Calculate angle

Collision Detection

Rectangle Collision

Check if two rectangles overlap:

if (blit_rects_overlap(
    player_x, player_y, player_w, player_h,
    enemy_x, enemy_y, enemy_w, enemy_h
)) {
    printf("Collision!\n");
}

Entity Collision

if (blit_entity_collides(player, enemy)) {
    // Handle collision
    player->health -= 10;
    enemy->active = 0;
}

Point Collision

Check if a point is inside a rectangle:

// Is mouse over button?
if (blit_point_in_rect(mx, my, button_x, button_y, button_w, button_h)) {
    // Highlight button
    if (blit_mouse_clicked(&engine, MOUSE_LEFT)) {
        // Button clicked!
    }
}

Collision Response Patterns

Bounce:

if (ball_x < 0 || ball_x > screen_width) {
    ball_vx = -ball_vx;  // Reverse horizontal velocity
}
if (ball_y < 0 || ball_y > screen_height) {
    ball_vy = -ball_vy;  // Reverse vertical velocity
}

Wrap Around:

if (player_x > screen_width) player_x = 0;
if (player_x < 0) player_x = screen_width;

Stop at Boundary:

if (player_x < 0) {
    player_x = 0;
    player_vx = 0;
}

Math Utilities

Random Numbers

// Random integer (inclusive)
int dice = blit_random_int(1, 6);          // 1, 2, 3, 4, 5, or 6
int spawn_x = blit_random_int(0, 800);     // 0 to 800

// Random float (0.0 to 1.0)
float chance = blit_random_float();
if (chance < 0.1) {  // 10% chance
    spawn_powerup();
}

Distance

// Manhattan distance (fast approximation)
float dist = blit_distance(x1, y1, x2, y2);

// Check if entities are close
if (blit_distance(player->x, player->y, enemy->x, enemy->y) < 50) {
    printf("Enemy nearby!\n");
}

Clamping

Keep values in range:

// Health between 0 and 100
health = blit_clamp(health, 0, 100);

// Speed limit
speed = blit_clamp(speed, -5, 5);

Drawing Functions

Shapes

// Rectangle (filled)
blit_draw_rect(&engine, x, y, width, height, color);

// Rectangle (outline)
blit_draw_rect_outline(&engine, x, y, width, height, color, thickness);

// Circle (filled)
blit_draw_circle(&engine, center_x, center_y, radius, color);

// Line
blit_draw_line(&engine, x0, y0, x1, y1, color, thickness);

Text

// Simple text (each character is a small rectangle)
blit_draw_text(&engine, "Score: 100", 10, 10, 0xFFFFFFFF);

// Dynamic text
char message[64];
snprintf(message, sizeof(message), "Health: %d / 100", player_health);
blit_draw_text(&engine, message, 10, 30, 0xFFFF0000);

Performance Tips

1. Create Assets Once

// GOOD - Create once
Sprite *bullet = blit_sprite_create_circle(&engine, 4, 0xFFFFFF00);
for (int frame = 0; frame < 1000; frame++) {
    blit_sprite_draw(&engine, bullet, x, y);
}

// BAD - Creates 1000 sprites!
for (int frame = 0; frame < 1000; frame++) {
    Sprite *bullet = blit_sprite_create_circle(&engine, 4, 0xFFFFFF00);
    blit_sprite_draw(&engine, bullet, x, y);
    blit_sprite_free(&engine, bullet);
}

2. Skip Inactive Entities

for (int i = 0; i < MAX_ENTITIES; i++) {
    if (!entities[i]->active) continue;  // Skip early
    
    blit_entity_update(entities[i]);
    blit_entity_draw(&engine, entities[i]);
}

3. Cull Off-Screen Objects

if (blit_entity_on_screen(&engine, entity)) {
    blit_entity_draw(&engine, entity);  // Only draw visible ones
}

Next Steps

Now you understand BlitEngine's core! Let's make games! 🎮

Clone this wiki locally