# Sui Language Game Development Guide ## Overview Sui now has integrated support for game development with **Raylib** (graphics) and **ODE** (physics). This guide explains how to build games with physics simulation and rendering. ## Key Concepts ### 1. Physics Engine (ODE) ODE (Open Dynamics Engine) provides rigid body dynamics, collision detection, and constraint solving. The key components are: - **World**: The container for all physical objects and gravity - **Bodies**: Dynamic rigid bodies with mass, velocity, and position - **Geometries**: Collision shapes (boxes, planes, spheres, etc.) - **Space**: Collision detection space that organizes geometries - **Contacts**: Joint constraints created when objects collide ### 2. Graphics Engine (Raylib) Raylib provides 2D and 3D graphics, input handling, and audio support. ### 3. Integration Pattern The key to proper physics is the **collision detection loop**: ```sui # Initialize ode_init() ode_space_collide(world, space, contactgroup) ode_world_step(world, timestep) ode_joint_group_empty(contactgroup) ``` **Important**: You must call collision detection **before** world step, and clear the contact group **after** the step. ## Step-by-Step Tutorial ### Step 1: Initialize the World ```sui fn main() -> int do # Initialize graphics init_window(800, 600, "My Game") set_target_fps(60) # Initialize physics ode_init() let world = ode_world_create() let space = ode_simple_space_create(0 as *()) let contactgroup = ode_joint_group_create(0) # Set gravity (9.81 m/s² downward) ode_world_set_gravity(world, 0.0, -9.81, 0.0) # ... rest of code end ``` ### Step 2: Create Physics Objects Each dynamic object needs: 1. A **body** - represents mass and motion 2. A **geometry** - collision shape 3. Mass configuration ```sui # Create a cube that falls let body = ode_body_create(world) ode_body_set_position(body, 0.0, 5.0, 0.0) # x, y, z ode_body_set_box_mass(body, 1.0, 1.0, 1.0, 1.0) # density, width, height, length # Create collision geometry let geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) ode_geom_set_body(geom, body) ``` ### Step 3: Create Static Objects (Ground) Static objects are created without a body - they use infinite mass: ```sui # Create a ground plane at y = 0 let ground_geom = ode_create_plane_geom(space, 0.0, 1.0, 0.0, 0.0) # Parameters: space, normal_x, normal_y, normal_z, distance_d ``` ### Step 4: Main Game Loop ```sui while window_should_close() == false do # === PHYSICS STEP === # 1. Detect collisions between all geometries ode_space_collide(world, space, contactgroup) # 2. Simulate physics ode_world_step(world, 1.0 / 60.0) # 60 FPS timestep # 3. Clear contact group to avoid double-application ode_joint_group_empty(contactgroup) # === RENDERING STEP === # Get current position let mut x = 0.0 let mut y = 0.0 let mut z = 0.0 ode_body_get_position(body, &x, &y, &z) # Draw begin_drawing() clear_background(135, 206, 235, 255) # Sky blue begin_mode3d(0.0, 2.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 45.0, 0) draw_cube(x, y, z, 1.0, 1.0, 1.0, 255, 0, 0, 255) # Red cube draw_cube(0.0, -1.0, 0.0, 20.0, 0.1, 20.0, 34, 139, 34, 255) # Green ground end_mode3d() end_drawing() end ``` ### Step 5: Cleanup Always destroy objects in reverse order of creation: ```sui ode_joint_group_destroy(contactgroup) ode_geom_destroy(geom) ode_body_destroy(body) ode_space_destroy(space) ode_world_destroy(world) ode_close() close_window() ``` ## Available Physics Functions ### World Management - `ode_init()` - Initialize ODE - `ode_close()` - Shutdown ODE - `ode_world_create() -> *()` - Create a world - `ode_world_destroy(world)` - Destroy world - `ode_world_set_gravity(world, x, y, z)` - Set gravity vector - `ode_world_step(world, timestep)` - Advance simulation ### Body Management - `ode_body_create(world) -> *()` - Create a dynamic body - `ode_body_destroy(body)` - `ode_body_set_position(body, x, y, z)` - `ode_body_get_position(body, &x, &y, &z)` - Retrieve position via pointers - `ode_body_set_linear_vel(body, vx, vy, vz)` - `ode_body_get_linear_vel(body, &vx, &vy, &vz)` - `ode_body_set_rotation(body, w, x, y, z)` - Set quaternion rotation - `ode_body_get_rotation(body, &w, &x, &y, &z)` - Get quaternion rotation - `ode_body_set_box_mass(body, density, width, height, length)` ### Collision Shapes (Geometries) - `ode_create_box_geom(space, width, height, length) -> *()` - Create box shape - `ode_create_plane_geom(space, nx, ny, nz, d) -> *()` - Create plane shape - `ode_geom_set_body(geom, body)` - Attach geometry to body - `ode_geom_destroy(geom)` ### Collision Spaces - `ode_simple_space_create(parent) -> *()` - Create simple space - `ode_space_destroy(space)` - `ode_space_collide(world, space, contactgroup)` - **Important**: Detect collisions - `ode_joint_group_create(max_size) -> *()` - Create contact joint group - `ode_joint_group_destroy(group)` - `ode_joint_group_empty(group)` - **Important**: Clear contacts after step ## Common Patterns ### Adding Bounce/Restitution Modify the contact properties in libsuicmez.c `near_callback()`: ```c contact[i].surface.bounce = 0.5; // 0 = no bounce, 1 = perfect bounce contact[i].surface.bounce_vel = 0.1; ``` ### Applying Forces ```sui # Set velocity directly ode_body_set_linear_vel(body, 10.0, 0.0, 0.0) ``` Note: ODE also supports force/torque application through lower-level APIs. ### Multiple Objects Create arrays of bodies and simulate them in a loop: ```sui let bodies_count = 5 # In main loop: let mut i = 0 while i < bodies_count do ode_body_get_position(bodies[i], &x, &y, &z) draw_cube(x, y, z, 1.0, 1.0, 1.0, 255, 0, 0, 255) i = i + 1 end ``` ## Advanced Topics ### Custom Contact Properties Edit `suic_ode_set_contact_erp()` and `suic_ode_set_contact_cfm()` to tune physics: - **ERP** (Error Reduction Parameter): 0-1, controls how fast constraint violations are fixed - **CFM** (Constraint Force Mixing): Soft constraint parameter, adds damping ### Quaternion Rotations ODE uses quaternions for 3D rotations. They're represented as (w, x, y, z): ```sui # Identity rotation ode_body_set_rotation(body, 1.0, 0.0, 0.0, 0.0) # Get current rotation let mut w = 0.0 let mut x = 0.0 let mut y = 0.0 let mut z = 0.0 ode_body_get_rotation(body, &w, &x, &y, &z) ``` ### Performance Optimization For large numbers of objects: 1. Use `dBVHSpaceCreate()` (not yet exposed) instead of simple space 2. Reduce collision pairs by using collision filtering 3. Use larger timesteps (but beware stability) 4. Implement sleeping/deactivation for static objects ## Example: Bouncing Ball Game See `tests/game_3d.sui` for a complete working example of: - Physics world setup - Dynamic falling cube - Ground plane - Collision detection - 3D rendering Compile and run: ```bash cargo run tests/game_3d.sui gcc tests/game_3d.c libsuicmez/libsuicmez.c $(pkg-config --cflags --libs raylib ode) -o game ./game ``` ## Troubleshooting ### "Cube falls through ground" - Ensure `ode_space_collide()` is called **before** `ode_world_step()` - Ensure contact group is created with `ode_joint_group_create()` - Call `ode_joint_group_empty()` after each step ### Jittery Physics - Reduce timestep (smaller value in `ode_world_step()`) - Increase ERP with `suic_ode_set_contact_erp()` - Reduce CFM with `suic_ode_set_contact_cfm()` ### Objects moving too slow/fast - Check gravity: `ode_world_set_gravity(world, 0.0, -9.81, 0.0)` - Check body mass: `ode_body_set_box_mass(body, density, w, h, l)` - Check initial velocity: `ode_body_set_linear_vel(body, vx, vy, vz)` ## Next Steps The Sui language is now ready for 3D game development! Future enhancements could include: - Higher-level GameObject system wrapping physics + rendering - Additional collision shapes (spheres, cylinders, meshes) - Particle systems - Audio integration - Input handling improvements - Scripting for game logic Happy game developing! 🎮