suicmez/GAMEDEV_GUIDE.md

287 lines
7.9 KiB
Markdown
Raw Normal View History

2025-12-17 13:16:53 +05:30
# 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! 🎮