Skip to content

Next Steps

Congratulations on learning the basics of Pill! Here are some directions to take your game development further.

Building Game Features

Player Movement and Controls

Implement responsive player controls:

rust
fn player_movement_system(engine: &mut Engine) -> Result<()> {
    let dt = engine.get_global_component::<TimeComponent>()?.delta_time;
    let input = engine.get_global_component::<InputComponent>()?;
    
    for (_, transform, player) in engine.iterate_two_components_mut::<
        TransformComponent,
        PlayerController,
    >()? {
        let mut movement = Vector3f::zeros();
        
        // WASD movement
        if input.is_key_pressed(KeyCode::W) {
            movement.z -= 1.0;
        }
        if input.is_key_pressed(KeyCode::S) {
            movement.z += 1.0;
        }
        if input.is_key_pressed(KeyCode::A) {
            movement.x -= 1.0;
        }
        if input.is_key_pressed(KeyCode::D) {
            movement.x += 1.0;
        }
        
        // Normalize and apply speed
        if movement.magnitude() > 0.0 {
            movement = movement.normalize() * player.speed * dt;
            transform.position += movement;
        }
        
        // Mouse look
        let mouse_delta = input.mouse_delta();
        transform.rotation *= Quaternionf::from_euler_angles(
            -mouse_delta.y * 0.001,
            -mouse_delta.x * 0.001,
            0.0
        );
    }
    
    Ok(())
}

Camera Systems

Create different camera types:

Follow Camera

rust
fn follow_camera_system(engine: &mut Engine) -> Result<()> {
    // Get player position
    let player_pos = {
        let mut pos = Vector3f::zeros();
        for (_, transform, _) in engine.iterate_two_components::<
            TransformComponent,
            PlayerTag,
        >()? {
            pos = transform.position;
            break;
        }
        pos
    };
    
    // Update camera position
    for (_, camera_transform, _) in engine.iterate_two_components_mut::<
        TransformComponent,
        CameraComponent,
    >()? {
        let offset = Vector3f::new(0.0, 5.0, 10.0);
        let target = player_pos + offset;
        
        // Smooth lerp
        let alpha = 5.0 * engine.get_global_component::<TimeComponent>()?.delta_time;
        camera_transform.position = camera_transform.position.lerp(&target, alpha);
        
        // Look at player
        camera_transform.look_at(player_pos, Vector3f::y());
    }
    
    Ok(())
}

Orbit Camera

rust
fn orbit_camera_system(engine: &mut Engine) -> Result<()> {
    let input = engine.get_global_component::<InputComponent>()?;
    
    for (_, transform, orbit) in engine.iterate_two_components_mut::<
        TransformComponent,
        OrbitCamera,
    >()? {
        // Mouse input for orbiting
        let mouse_delta = input.mouse_delta();
        orbit.yaw -= mouse_delta.x * 0.003;
        orbit.pitch -= mouse_delta.y * 0.003;
        orbit.pitch = orbit.pitch.clamp(-1.5, 1.5);
        
        // Mouse wheel for zoom
        orbit.distance -= input.mouse_wheel_delta() * 0.5;
        orbit.distance = orbit.distance.clamp(2.0, 50.0);
        
        // Calculate position
        let x = orbit.distance * orbit.pitch.cos() * orbit.yaw.sin();
        let y = orbit.distance * orbit.pitch.sin();
        let z = orbit.distance * orbit.pitch.cos() * orbit.yaw.cos();
        
        transform.position = orbit.target + Vector3f::new(x, y, z);
        transform.look_at(orbit.target, Vector3f::y());
    }
    
    Ok(())
}

Physics Integration

Use physics for realistic gameplay:

rust
// Create dynamic physics object
engine.build_entity(scene)
    .with_component(TransformComponent::builder()
        .position(Vector3f::new(0.0, 10.0, 0.0))
        .build())
    .with_component(MeshRenderingComponent::builder()
        .mesh(&mesh)
        .material(&material)
        .build())
    .with_component(RigidBodyComponent::builder()
        .body_type(RigidBodyType::Dynamic)
        .linear_damping(0.5)  // Air resistance
        .angular_damping(0.5)  // Rotation resistance
        .build())
    .with_component(ColliderComponent::builder()
        .shape(SharedShape::ball(1.0))
        .mass(10.0)
        .restitution(0.7)  // Bounciness
        .friction(0.5)
        .build())
    .build();

Applying Forces

rust
fn apply_force_system(engine: &mut Engine) -> Result<()> {
    let input = engine.get_global_component::<InputComponent>()?;
    
    for (_, rigidbody, _) in engine.iterate_two_components_mut::<
        RigidBodyComponent,
        PlayerTag,
    >()? {
        if input.is_key_just_pressed(KeyCode::Space) {
            // Apply upward impulse
            rigidbody.apply_impulse(Vector3f::new(0.0, 500.0, 0.0));
        }
        
        if input.is_key_pressed(KeyCode::W) {
            // Apply forward force
            rigidbody.apply_force(Vector3f::new(0.0, 0.0, -100.0));
        }
    }
    
    Ok(())
}

AI and Behavior

Implement simple AI systems:

rust
define_component!(AIComponent {
    state: AIState,
    target: Option<EntityHandle>,
    patrol_points: Vec<Vector3f>,
    current_patrol: usize,
});

enum AIState {
    Idle,
    Patrol,
    Chase,
    Attack,
}

fn ai_system(engine: &mut Engine) -> Result<()> {
    let dt = engine.get_global_component::<TimeComponent>()?.delta_time;
    
    // Get player position
    let player_pos = get_player_position(engine)?;
    
    for (entity, transform, ai) in engine.iterate_two_components_mut::<
        TransformComponent,
        AIComponent,
    >()? {
        let distance_to_player = (player_pos - transform.position).magnitude();
        
        match ai.state {
            AIState::Patrol => {
                // Move to patrol point
                let target = ai.patrol_points[ai.current_patrol];
                move_towards(transform, target, 2.0 * dt);
                
                // Check if reached
                if (target - transform.position).magnitude() < 0.5 {
                    ai.current_patrol = (ai.current_patrol + 1) % ai.patrol_points.len();
                }
                
                // Check for player
                if distance_to_player < 10.0 {
                    ai.state = AIState::Chase;
                }
            }
            AIState::Chase => {
                // Chase player
                move_towards(transform, player_pos, 3.0 * dt);
                
                // Check if in attack range
                if distance_to_player < 2.0 {
                    ai.state = AIState::Attack;
                }
                // Check if lost player
                else if distance_to_player > 15.0 {
                    ai.state = AIState::Patrol;
                }
            }
            AIState::Attack => {
                // Attack logic
                look_at(transform, player_pos);
                
                if distance_to_player > 3.0 {
                    ai.state = AIState::Chase;
                }
            }
            _ => {}
        }
    }
    
    Ok(())
}

Networking Multiplayer Games

Setting Up Networking

Enable networking in your Cargo.toml:

toml
[dependencies]
pill_engine = { path = "../Pill-Engine/engine/pill_engine", features = ["net"] }

Client Setup

rust
#[cfg(feature = "net")]
{
    use pill_engine::{NetState, NetworkStateComponent};
    use rand::Rng;
    
    // Create client instance
    let client_id = rand::thread_rng().gen_range(1..=10_000_000);
    let server_addr = "127.0.0.1:5000";
    
    engine.add_global_component(NetState::new_client(server_addr, client_id)?)?;
    
    // Add network component to player
    engine.add_component_to_entity(
        scene,
        player_entity,
        NetworkStateComponent {
            net_entity_id: rand::thread_rng().gen_range(1..=1000),
            owner_id: client_id,
            state: NetEntityState::Spawn,
            transform: Some(initial_transform.clone()),
        },
    )?;
}

Server Setup

rust
#[cfg(feature = "net")]
{
    let port = 5000;
    engine.add_global_component(NetState::new_server(port)?)?;
    
    // Add networking system
    engine.add_system("NetworkingServer", pill_engine::networking_system_server)?;
}

Advanced Topics

Custom Shaders

While Pill handles shaders internally, you can customize rendering:

rust
// Future: Custom shader support
// Check res/shaders/ for built-in shaders

Post-Processing Effects

Add screen-space effects:

rust
// Future: Post-processing API
// Currently configured through renderer settings

Scene Management

Switch between multiple scenes:

rust
// Create multiple scenes
let menu_scene = engine.create_scene("Menu")?;
let game_scene = engine.create_scene("Game")?;
let pause_scene = engine.create_scene("Pause")?;

// Switch scenes
engine.set_active_scene(game_scene)?;

// Later...
fn pause_game(engine: &mut Engine) -> Result<()> {
    let pause_scene = engine.get_scene("Pause")?;
    engine.set_active_scene(pause_scene)?;
    Ok(())
}

Save/Load System

Implement game state persistence:

rust
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct SaveData {
    player_position: Vector3f,
    score: i32,
    level: i32,
    inventory: Vec<Item>,
}

fn save_game(engine: &Engine) -> Result<()> {
    let save_data = SaveData {
        player_position: get_player_position(engine)?,
        score: engine.get_global_component::<GameState>()?.score,
        level: engine.get_global_component::<GameState>()?.level,
        inventory: get_player_inventory(engine)?,
    };
    
    let json = serde_json::to_string_pretty(&save_data)?;
    std::fs::write("save.json", json)?;
    
    Ok(())
}

fn load_game(engine: &mut Engine) -> Result<()> {
    let json = std::fs::read_to_string("save.json")?;
    let save_data: SaveData = serde_json::from_str(&json)?;
    
    // Restore game state
    set_player_position(engine, save_data.player_position)?;
    engine.get_global_component_mut::<GameState>()?.score = save_data.score;
    // ... restore other data
    
    Ok(())
}

Learning Resources

Example Projects

Study the included examples:

  • Empty: Starting template - minimal setup
  • Floating-Pills: Basic rendering and entities
  • Trucks: Physics, controls, and camera systems
  • Italian-Brainrot: Advanced features showcase
  • Net-Minimal: Networking basics

Community and Support

  • GitHub Issues: Report bugs and request features
  • Discussions: Ask questions and share projects
  • Examples: Browse example projects for patterns

Rust Game Development

Expand your knowledge:

Performance Optimization

Profiling

Measure performance to find bottlenecks:

rust
use std::time::Instant;

fn expensive_system(engine: &mut Engine) -> Result<()> {
    let start = Instant::now();
    
    // Your system logic
    
    let elapsed = start.elapsed();
    if elapsed.as_millis() > 16 {
        println!("Warning: System took {}ms", elapsed.as_millis());
    }
    
    Ok(())
}

Optimization Tips

  1. Minimize entity iteration: Only query what you need
  2. Cache lookups: Store frequently accessed data
  3. Use spatial partitioning: For collision detection and visibility
  4. Batch operations: Group similar entities together
  5. LOD systems: Use lower detail for distant objects

Memory Management

rust
// Remove entities when no longer needed
engine.destroy_entity(scene, entity_handle)?;

// Unload unused resources
engine.remove_resource::<Mesh>(&unused_mesh_handle)?;

Debugging Tips

Visual Debugging

Draw debug information:

rust
fn debug_draw_system(engine: &mut Engine) -> Result<()> {
    // Future: Debug drawing API
    // For now, use temporary entities
    
    Ok(())
}

Logging

Use Rust's logging:

rust
use log::{info, warn, error, debug};

fn my_system(engine: &mut Engine) -> Result<()> {
    info!("System running");
    debug!("Entity count: {}", entity_count);
    warn!("Low health detected");
    error!("Critical error occurred");
    
    Ok(())
}

What's Next?

You now have the knowledge to build complete games with Pill. Here are some project ideas:

Beginner Projects

  • Collect the Pills: Simple collection game
  • Physics Playground: Experiment with physics
  • Walking Simulator: Exploration game

Intermediate Projects

  • Tower Defense: Strategy and AI
  • Racing Game: Vehicle physics and tracks
  • Platformer: Jumping and obstacles

Advanced Projects

  • Multiplayer Arena: Networking and combat
  • Open World: Large environments and streaming
  • Procedural Generation: Dynamic content

Remember to check the Troubleshooting page if you encounter any issues!