diff --git a/compile.sh b/compile.sh index 8b32399..73c720b 100755 --- a/compile.sh +++ b/compile.sh @@ -67,7 +67,7 @@ ODE_LIBS=$(pkg-config --libs ode 2>/dev/null || echo "-lode -lm") # Compile C to executable with raylib and ODE support echo "Compiling C code and linking with libsuicmez, raylib, and ODE..." -gcc $OPTIMIZE_FLAG "$C_FILE" libsuicmez/libsuicmez.c libsuicmez/suicmez_gc.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -lm -o "$OUTPUT_BINARY" || exit 1 +gcc $OPTIMIZE_FLAG -I. "$C_FILE" libsuicmez/libsuicmez.c libsuicmez/suicmez_gc.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -lm -o "$OUTPUT_BINARY" || exit 1 echo "✓ Successfully created: $OUTPUT_BINARY" echo " Run with: ./$OUTPUT_BINARY" diff --git a/compile_and_run.sh b/compile_and_run.sh index 11786f3..7fe47f8 100755 --- a/compile_and_run.sh +++ b/compile_and_run.sh @@ -78,7 +78,7 @@ RAYLIB_LIBS=$(pkg-config --libs raylib 2>/dev/null || echo "-lraylib -lm") ODE_CFLAGS=$(pkg-config --cflags ode 2>/dev/null || echo "-I/usr/include") ODE_LIBS=$(pkg-config --libs ode 2>/dev/null || echo "-lode -lm") -if ! gcc $OPTIMIZE_FLAG "$C_FILE" libsuicmez/libsuicmez.c libsuicmez/suicmez_gc.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -lm -o "$OUTPUT_BINARY" 2>&1; then +if ! gcc $OPTIMIZE_FLAG -I. "$C_FILE" libsuicmez/libsuicmez.c libsuicmez/suicmez_gc.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -lm -o "$OUTPUT_BINARY" 2>&1; then echo "" echo "✗ C compilation failed" exit 1 diff --git a/fishsoup/main.c b/fishsoup/main.c index 1554fe1..c8665b3 100644 --- a/fishsoup/main.c +++ b/fishsoup/main.c @@ -1,4 +1,4 @@ -#include "../libsuicmez/libsuicmez.h" +#include "libsuicmez/libsuicmez.h" #include #include #include @@ -23,103 +23,189 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat } -struct Vec2 { - float x; - float y; -}; -static const uint8_t sui_bitmap_Vec2[] = { 0, 0 }; -static const TypeInfo sui_typeinfo_Vec2 = { - .field_count = 2, - .pointer_count = 0, - .pointer_bitmap = sui_bitmap_Vec2 -}; int suic_main(void); int suic_main(void) { - suic_init_window(800, 600, suic_alloc_array(NULL, sizeof(char), 31, "Fishsoup - Basic 3D Platformer")); - suic_set_target_fps(60); + suic_enable_msaa_4x(); + suic_init_window(1280, 720, suic_alloc_array(NULL, sizeof(char), 112, "Sui FPS Game - WASD to move, Mouse to look, SPACE to jump, SHIFT to sprint, F1 cursor, F2 hide FPS, F3 show FPS")); + suic_show_fps_meter((suic_vec2){ .x = 10.000000, .y = 10.000000 }); + suic_disable_cursor(); suic_ode_init(); void* world = suic_ode_world_create(); - void* null_space = (struct unit**) 0; + void* null_space = NULL; void* space = suic_ode_simple_space_create(null_space); suic_ode_world_set_gravity(world, 0.000000, -9.810000, 0.000000); void* contactgroup = suic_ode_joint_group_create(0); + void* ground_geom = suic_ode_create_plane_geom(space, 0.000000, 1.000000, 0.000000, 0.000000); void* player_body = suic_ode_body_create(world); - suic_ode_body_set_box_mass(player_body, 1.000000, 1.000000, 1.000000, 1.000000); - suic_ode_body_set_position(player_body, 0.000000, 1.000000, 0.000000); - void* player_geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_body_set_position(player_body, 0.000000, 2.000000, 0.000000); + void* player_geom = suic_ode_create_box_geom(space, 0.800000, 1.600000, 0.800000); suic_ode_geom_set_body(player_geom, player_body); - void* ground_geom = suic_ode_create_plane_geom(space, 0.000000, 1.000000, 0.000000, 0.500000); - suic_ode_body_set_linear_vel(player_body, 0.000000, 0.000000, 0.000000); + suic_ode_body_set_box_mass(player_body, 1.000000, 0.800000, 1.600000, 0.800000); + void* cube1_body = suic_ode_body_create(world); + suic_ode_body_set_position(cube1_body, 0.000000, 1.000000, -5.000000); + suic_ode_body_set_box_mass(cube1_body, 1.000000, 1.000000, 1.000000, 1.000000); + void* cube1_geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_geom_set_body(cube1_geom, cube1_body); + void* cube2_body = suic_ode_body_create(world); + suic_ode_body_set_position(cube2_body, 5.000000, 1.000000, -3.000000); + suic_ode_body_set_box_mass(cube2_body, 1.000000, 1.000000, 1.000000, 1.000000); + void* cube2_geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_geom_set_body(cube2_geom, cube2_body); + void* cube3_body = suic_ode_body_create(world); + suic_ode_body_set_position(cube3_body, -5.000000, 1.000000, -3.000000); + suic_ode_body_set_box_mass(cube3_body, 1.000000, 1.000000, 1.000000, 1.000000); + void* cube3_geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_geom_set_body(cube3_geom, cube3_body); + float forward_x = 0.000000; + float forward_y = 0.000000; + float forward_z = -1.000000; + float right_x = 1.000000; + float right_y = 0.000000; + float right_z = 0.000000; + float camera_x = 0.000000; + float camera_y = 2.000000; + float camera_z = 0.000000; + float target_x = 0.000000; + float target_y = 2.000000; + float target_z = -5.000000; + float yaw = 0.000000; + float pitch = 0.000000; + float mouse_sensitivity = 0.003000; + int fps_meter_visible = 1; + float cube1_x = 0.000000; + float cube1_y = 0.000000; + float cube1_z = 0.000000; + float cube2_x = 0.000000; + float cube2_y = 0.000000; + float cube2_z = 0.000000; + float cube3_x = 0.000000; + float cube3_y = 0.000000; + float cube3_z = 0.000000; float player_x = 0.000000; - float player_y = 0.000000; + float player_y = 2.000000; float player_z = 0.000000; - float player_angle = 0.000000; - float camera_distance = 5.000000; - float camera_height = 2.000000; - float mouse_x = 0.000000; - float mouse_y = 0.000000; - float last_mouse_x = 0.000000; - float last_mouse_y = 0.000000; - float vel_x = 0.000000; - float vel_y = 0.000000; - float vel_z = 0.000000; while ((suic_window_should_close() == false)) { - mouse_x = suic_get_mouse_x(); - mouse_y = suic_get_mouse_y(); - float mouse_delta_x = (mouse_x - last_mouse_x); - float mouse_delta_y = (mouse_y - last_mouse_y); - last_mouse_x = mouse_x; - last_mouse_y = mouse_y; - float mouse_sensitivity = 0.005000; - player_angle = (player_angle - (mouse_delta_x * mouse_sensitivity)); - suic_ode_space_collide(world, space, contactgroup); - suic_ode_world_step(world, (1.000000 / 60.000000)); - suic_ode_joint_group_empty(contactgroup); - suic_ode_body_get_linear_vel(player_body, &vel_x, &vel_y, &vel_z); + float delta_time = suic_get_frame_time(); + float mouse_delta_x = suic_get_mouse_delta_x(); + float mouse_delta_y = suic_get_mouse_delta_y(); + yaw = (yaw + (mouse_delta_x * mouse_sensitivity)); + pitch = (pitch - (mouse_delta_y * mouse_sensitivity)); + if ((pitch > 1.500000)) { + pitch = 1.500000; + } + if ((pitch < -1.500000)) { + pitch = -1.500000; + } + float cos_yaw = cos(yaw); + float sin_yaw = sin(yaw); + float cos_pitch = cos(pitch); + float sin_pitch = sin(pitch); + forward_x = sin_yaw; + forward_y = sin_pitch; + forward_z = -cos_yaw; + right_x = cos_yaw; + right_y = 0.000000; + right_z = sin_yaw; float move_speed = 5.000000; - bool w_pressed = suic_is_key_down(87); - bool s_pressed = suic_is_key_down(83); - bool a_pressed = suic_is_key_down(65); - bool d_pressed = suic_is_key_down(68); - if (w_pressed) { - vel_x = (sin(player_angle) * move_speed); - vel_z = (cos(player_angle) * move_speed); - suic_ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z); + float target_vx = 0.000000; + float target_vz = 0.000000; + if ((suic_is_key_down(KEY_W) != 0)) { + target_vx = (target_vx + (forward_x * move_speed)); + target_vz = (target_vz + (forward_z * move_speed)); } - if (s_pressed) { - vel_x = (-sin(player_angle) * move_speed); - vel_z = (-cos(player_angle) * move_speed); - suic_ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z); + if ((suic_is_key_down(KEY_S) != 0)) { + target_vx = (target_vx - (forward_x * move_speed)); + target_vz = (target_vz - (forward_z * move_speed)); } - if (a_pressed) { - vel_x = (sin((player_angle + (3.141590 / 2.000000))) * move_speed); - vel_z = (cos((player_angle + (3.141590 / 2.000000))) * move_speed); - suic_ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z); + if ((suic_is_key_down(KEY_D) != 0)) { + target_vx = (target_vx + (right_x * move_speed)); + target_vz = (target_vz + (right_z * move_speed)); } - if (d_pressed) { - vel_x = (sin((player_angle - (3.141590 / 2.000000))) * move_speed); - vel_z = (cos((player_angle - (3.141590 / 2.000000))) * move_speed); - suic_ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z); + if ((suic_is_key_down(KEY_A) != 0)) { + target_vx = (target_vx - (right_x * move_speed)); + target_vz = (target_vz - (right_z * move_speed)); } + float current_vx = 0.000000; + float current_vy = 0.000000; + float current_vz = 0.000000; + suic_ode_body_get_linear_vel(player_body, ¤t_vx, ¤t_vy, ¤t_vz); + if ((suic_is_jump_pressed() != 0)) { + float dummy_x = 0.000000; + float current_y = 0.000000; + float dummy_z = 0.000000; + suic_ode_body_get_position(player_body, &dummy_x, ¤t_y, &dummy_z); + if ((current_y <= 1.300000)) { + current_vy = 8.000000; + } + } + suic_ode_body_set_linear_vel(player_body, target_vx, current_vy, target_vz); + suic_ode_space_collide(world, space, contactgroup); + if ((delta_time > 0.000000)) { + suic_ode_world_step(world, delta_time); + } + suic_ode_joint_group_empty(contactgroup); suic_ode_body_get_position(player_body, &player_x, &player_y, &player_z); - float camera_x = (player_x - (sin(player_angle) * camera_distance)); - float camera_y = (player_y + camera_height); - float camera_z = (player_z - (cos(player_angle) * camera_distance)); + if (((suic_is_key_pressed(KEY_EQUAL) != 0) || (suic_is_key_pressed(KEY_KP_ADD) != 0))) { + mouse_sensitivity = (mouse_sensitivity + 0.001000); + } + if (((suic_is_key_pressed(KEY_MINUS) != 0) || (suic_is_key_pressed(KEY_KP_SUBTRACT) != 0))) { + mouse_sensitivity = (mouse_sensitivity - 0.001000); + if ((mouse_sensitivity < 0.001000)) { + mouse_sensitivity = 0.001000; + } + } + if ((suic_is_key_pressed(KEY_F1) != 0)) { + suic_enable_cursor(); + } + if ((suic_is_key_pressed(KEY_F2) != 0)) { + suic_hide_fps_meter(); + fps_meter_visible = 0; + } + if ((suic_is_key_pressed(KEY_F3) != 0)) { + suic_show_fps_meter((suic_vec2){ .x = 10.000000, .y = 10.000000 }); + fps_meter_visible = 1; + } + camera_x = (player_x + (forward_x * 0.500000)); + camera_y = (player_y + 0.900000); + camera_z = (player_z + (forward_z * 0.500000)); + target_x = (player_x + (forward_x * 5.000000)); + target_y = (player_y + (forward_y * 5.000000)); + target_z = (player_z + (forward_z * 5.000000)); + suic_ode_body_get_position(cube1_body, &cube1_x, &cube1_y, &cube1_z); + suic_ode_body_get_position(cube2_body, &cube2_x, &cube2_y, &cube2_z); + suic_ode_body_get_position(cube3_body, &cube3_x, &cube3_y, &cube3_z); suic_begin_drawing(); suic_clear_background(135, 206, 235, 255); - suic_begin_mode3d(camera_x, camera_y, camera_z, player_x, player_y, player_z, 0.000000, 1.000000, 0.000000, 45.000000, 0); - suic_draw_cube(0.000000, -0.500000, 0.000000, 20.000000, 1.000000, 20.000000, 34, 139, 34, 255); - suic_draw_cube(player_x, player_y, player_z, 1.000000, 1.000000, 1.000000, 0, 255, 0, 255); + suic_begin_mode3d(camera_x, camera_y, camera_z, target_x, target_y, target_z, 0.000000, 1.000000, 0.000000, 45.000000, 0); + suic_draw_cube(0.000000, -1.000000, 0.000000, 100.000000, 0.100000, 100.000000, 34, 139, 34, 255); + suic_draw_cube(cube1_x, cube1_y, cube1_z, 1.000000, 1.000000, 1.000000, 255, 0, 0, 255); + suic_draw_cube_wires(cube1_x, cube1_y, cube1_z, 1.000000, 1.000000, 1.000000, 0, 0, 0, 255); + suic_draw_cube(cube2_x, cube2_y, cube2_z, 1.000000, 1.000000, 1.000000, 0, 255, 0, 255); + suic_draw_cube_wires(cube2_x, cube2_y, cube2_z, 1.000000, 1.000000, 1.000000, 0, 0, 0, 255); + suic_draw_cube(cube3_x, cube3_y, cube3_z, 1.000000, 1.000000, 1.000000, 0, 0, 255, 255); + suic_draw_cube_wires(cube3_x, cube3_y, cube3_z, 1.000000, 1.000000, 1.000000, 0, 0, 0, 255); + suic_rl_push_matrix(); + suic_rl_translate_f(player_x, player_y, player_z); + suic_rl_rotate_f(((-yaw * 180.000000) / 3.141590), 0.000000, 1.000000, 0.000000); + suic_draw_cube(0.000000, 0.000000, 0.000000, 0.800000, 1.600000, 0.800000, 255, 255, 0, 255); + suic_draw_cube_wires(0.000000, 0.000000, 0.000000, 0.800000, 1.600000, 0.800000, 0, 0, 0, 255); + suic_rl_pop_matrix(); suic_end_mode3d(); suic_end_drawing(); } - suic_ode_geom_destroy(ground_geom); + suic_ode_geom_destroy(cube3_geom); + suic_ode_body_destroy(cube3_body); + suic_ode_geom_destroy(cube2_geom); + suic_ode_body_destroy(cube2_body); + suic_ode_geom_destroy(cube1_geom); + suic_ode_body_destroy(cube1_body); suic_ode_geom_destroy(player_geom); suic_ode_body_destroy(player_body); + suic_ode_geom_destroy(ground_geom); suic_ode_joint_group_destroy(contactgroup); suic_ode_space_destroy(space); suic_ode_world_destroy(world); diff --git a/fishsoup/main.o b/fishsoup/main.o index 1e14c56..2bb83a8 100755 Binary files a/fishsoup/main.o and b/fishsoup/main.o differ diff --git a/fishsoup/main.sui b/fishsoup/main.sui index b31b2c6..e2fa748 100644 --- a/fishsoup/main.sui +++ b/fishsoup/main.sui @@ -1,18 +1,22 @@ -# Basic 3D Platformer - Fishsoup -# Mouse for rotation, WASD for movement - -struct Vec2 - x: float, - y: float, -end +# FPS-Style 3D Game with Sui Language +# Demonstrates WASD movement, mouse look, jumping, sprinting, and physics-based gameplay fn main() -> int do - # Initialize raylib - init_window(800, 600, "Fishsoup - Basic 3D Platformer") - defer close_window() - set_target_fps(60) + # Enable antialiasing + enable_msaa_4x() - # Initialize ODE + # Initialize graphics + init_window(1280, 720, "Sui FPS Game - WASD to move, Mouse to look, SPACE to jump, SHIFT to sprint, F1 cursor, F2 hide FPS, F3 show FPS") + defer close_window() + # set_target_fps(60) + + # Show FPS meter + show_fps_meter(Vec2 { x: 10.0, y: 10.0 }) + + # Hide cursor and capture mouse for FPS controls + disable_cursor() + + # Initialize physics ode_init() defer ode_close() @@ -30,129 +34,257 @@ fn main() -> int do let contactgroup = ode_joint_group_create(0) defer ode_joint_group_destroy(contactgroup) - # Create player body + # Create ground plane + let ground_geom = ode_create_plane_geom(space, 0.0, 1.0, 0.0, 0.0) + defer ode_geom_destroy(ground_geom) + + # Create player physics body (capsule shape) let player_body = ode_body_create(world) defer ode_body_destroy(player_body) + ode_body_set_position(player_body, 0.0, 2.0, 0.0) - # Set player mass (cube 1x1x1) - ode_body_set_box_mass(player_body, 1.0, 1.0, 1.0, 1.0) + # Create box geometry for player (0.8 x 1.6 x 0.8) + let player_geom = ode_create_box_geom(space, 0.8, 1.6, 0.8) + defer ode_geom_destroy(player_geom) + ode_geom_set_body(player_geom, player_body) - # Set initial position - ode_body_set_position(player_body, 0.0, 1.0, 0.0) + # Set player mass (box with density 1.0) + ode_body_set_box_mass(player_body, 1.0, 0.8, 1.6, 0.8) - # Create geometry for player - let player_geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) - defer ode_geom_destroy(player_geom) - ode_geom_set_body(player_geom, player_body) + # Create cube physics bodies + let cube1_body = ode_body_create(world) + defer ode_body_destroy(cube1_body) + ode_body_set_position(cube1_body, 0.0, 1.0, -5.0) + ode_body_set_box_mass(cube1_body, 1.0, 1.0, 1.0, 1.0) + let cube1_geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) + defer ode_geom_destroy(cube1_geom) + ode_geom_set_body(cube1_geom, cube1_body) - # Create ground plane (at y = -0.5) - # Plane equation: ax + by + cz + d = 0 - # For y = -0.5: 0*x + 1*y + 0*z + 0.5 = 0 => y = -0.5 - let ground_geom = ode_create_plane_geom(space, 0.0, 1.0, 0.0, 0.5) - defer ode_geom_destroy(ground_geom) - - # Initialize player velocity to allow gravity to work - ode_body_set_linear_vel(player_body, 0.0, 0.0, 0.0) + let cube2_body = ode_body_create(world) + defer ode_body_destroy(cube2_body) + ode_body_set_position(cube2_body, 5.0, 1.0, -3.0) + ode_body_set_box_mass(cube2_body, 1.0, 1.0, 1.0, 1.0) + let cube2_geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) + defer ode_geom_destroy(cube2_geom) + ode_geom_set_body(cube2_geom, cube2_body) - # Player variables - let mut player_x = 0.0 - let mut player_y = 0.0 - let mut player_z = 0.0 - let mut player_angle = 0.0 # Yaw - let mut camera_distance = 5.0 - let mut camera_height = 2.0 - let mut mouse_x = 0.0 - let mut mouse_y = 0.0 - let mut last_mouse_x = 0.0 - let mut last_mouse_y = 0.0 - let mut vel_x = 0.0 - let mut vel_y = 0.0 - let mut vel_z = 0.0 + let cube3_body = ode_body_create(world) + defer ode_body_destroy(cube3_body) + ode_body_set_position(cube3_body, -5.0, 1.0, -3.0) + ode_body_set_box_mass(cube3_body, 1.0, 1.0, 1.0, 1.0) + let cube3_geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) + defer ode_geom_destroy(cube3_geom) + ode_geom_set_body(cube3_geom, cube3_body) - # Main game loop - while window_should_close() == false do - # Get mouse position for rotation - mouse_x = get_mouse_x() - mouse_y = get_mouse_y() - - # Calculate mouse delta - let mouse_delta_x = mouse_x - last_mouse_x - let mouse_delta_y = mouse_y - last_mouse_y - last_mouse_x = mouse_x - last_mouse_y = mouse_y - - # Update rotation based on mouse movement - let mouse_sensitivity = 0.005 - player_angle = player_angle - mouse_delta_x * mouse_sensitivity + # Set player movement direction (looking down -Z axis) + let mut forward_x = 0.0 + let mut forward_y = 0.0 + let mut forward_z = -1.0 + let mut right_x = 1.0 + let mut right_y = 0.0 + let mut right_z = 0.0 + + # ==== CAMERA AND PLAYER STATE ==== + let mut camera_x = 0.0 + let mut camera_y = 2.0 + let mut camera_z = 0.0 + let mut target_x = 0.0 + let mut target_y = 2.0 + let mut target_z = -5.0 + + # Mouse look state + let mut yaw = 0.0 + let mut pitch = 0.0 + let mut mouse_sensitivity = 0.003 - # Collision detection BEFORE step - ode_space_collide(world, space, contactgroup) - - # Step physics - this applies gravity - ode_world_step(world, 1.0 / 60.0) - ode_joint_group_empty(contactgroup) - - # NOW get the velocity after gravity has been applied - ode_body_get_linear_vel(player_body, &vel_x, &vel_y, &vel_z) - - # Handle input for movement - let move_speed = 5.0 - - # Check if any movement keys are pressed - let w_pressed = is_key_down(87) - let s_pressed = is_key_down(83) - let a_pressed = is_key_down(65) - let d_pressed = is_key_down(68) - - # Only update HORIZONTAL velocity if a key is pressed - # Keep vertical velocity (from gravity) - if w_pressed do - vel_x = sin(player_angle) * move_speed - vel_z = cos(player_angle) * move_speed - ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z) - end - - if s_pressed do - vel_x = -sin(player_angle) * move_speed - vel_z = -cos(player_angle) * move_speed - ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z) - end - - if a_pressed do - vel_x = sin(player_angle + 3.14159 / 2.0) * move_speed - vel_z = cos(player_angle + 3.14159 / 2.0) * move_speed - ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z) + # FPS meter toggle + let mut fps_meter_visible = 1 + + # Cube position variables + let mut cube1_x = 0.0 + let mut cube1_y = 0.0 + let mut cube1_z = 0.0 + let mut cube2_x = 0.0 + let mut cube2_y = 0.0 + let mut cube2_z = 0.0 + let mut cube3_x = 0.0 + let mut cube3_y = 0.0 + let mut cube3_z = 0.0 + + # Player position (initial values) + let mut player_x = 0.0 + let mut player_y = 2.0 + let mut player_z = 0.0 + + # Main game loop + while window_should_close() == false do + # Get actual frame delta time + let delta_time = get_frame_time() + + # Mouse look + let mouse_delta_x = get_mouse_delta_x() + let mouse_delta_y = get_mouse_delta_y() + + yaw = yaw + (mouse_delta_x * mouse_sensitivity) + pitch = pitch - (mouse_delta_y * mouse_sensitivity) # Negate Y for natural FPS controls + + # Clamp pitch to prevent flipping + if pitch > 1.5 do + pitch = 1.5 end - - if d_pressed do - vel_x = sin(player_angle - 3.14159 / 2.0) * move_speed - vel_z = cos(player_angle - 3.14159 / 2.0) * move_speed - ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z) + if pitch < -1.5 do + pitch = -1.5 end - # Get player position - ode_body_get_position(player_body, &player_x, &player_y, &player_z) + # Calculate camera direction from yaw and pitch + let cos_yaw = cos(yaw) + let sin_yaw = sin(yaw) + let cos_pitch = cos(pitch) + let sin_pitch = sin(pitch) - # Camera position (behind player) - let camera_x = player_x - sin(player_angle) * camera_distance - let camera_y = player_y + camera_height - let camera_z = player_z - cos(player_angle) * camera_distance + # Update forward and right vectors FIRST (before movement) + forward_x = sin_yaw + forward_y = sin_pitch + forward_z = -cos_yaw - # Drawing + right_x = cos_yaw + right_y = 0.0 + right_z = sin_yaw + + # WASD movement - set velocities on physics body + let move_speed = 5.0 # Units per second + let mut target_vx = 0.0 + let mut target_vz = 0.0 + + if is_key_down(KEY_W) != 0 do + target_vx = target_vx + forward_x * move_speed + target_vz = target_vz + forward_z * move_speed + end + + if is_key_down(KEY_S) != 0 do + target_vx = target_vx - forward_x * move_speed + target_vz = target_vz - forward_z * move_speed + end + + if is_key_down(KEY_D) != 0 do + target_vx = target_vx + right_x * move_speed + target_vz = target_vz + right_z * move_speed + end + + if is_key_down(KEY_A) != 0 do + target_vx = target_vx - right_x * move_speed + target_vz = target_vz - right_z * move_speed + end + + # Get current velocity for Y (preserve gravity) + let mut current_vx = 0.0 + let mut current_vy = 0.0 + let mut current_vz = 0.0 + ode_body_get_linear_vel(player_body, ¤t_vx, ¤t_vy, ¤t_vz) + + # Jump - set upward velocity + if is_jump_pressed() != 0 do + # Get current position to check if on ground + let mut dummy_x = 0.0 + let mut current_y = 0.0 + let mut dummy_z = 0.0 + ode_body_get_position(player_body, &dummy_x, ¤t_y, &dummy_z) + if current_y <= 1.3 do # On ground (box bottom is at y - 0.8 from center) + current_vy = 8.0 # Jump velocity + end + end + + # Set new velocity (keep Y velocity for gravity/jumping) + ode_body_set_linear_vel(player_body, target_vx, current_vy, target_vz) + + # Update physics (just for cubes) + ode_space_collide(world, space, contactgroup) + # Only step physics if delta_time is valid (guard against first frame which is 0) + if delta_time > 0.0 do + ode_world_step(world, delta_time) + end + ode_joint_group_empty(contactgroup) + + # Get player position from physics body + ode_body_get_position(player_body, &player_x, &player_y, &player_z) + + # Adjust mouse sensitivity + if is_key_pressed(KEY_EQUAL) != 0 or is_key_pressed(KEY_KP_ADD) != 0 do # + key + mouse_sensitivity = mouse_sensitivity + 0.001 + end + if is_key_pressed(KEY_MINUS) != 0 or is_key_pressed(KEY_KP_SUBTRACT) != 0 do # - key + mouse_sensitivity = mouse_sensitivity - 0.001 + if mouse_sensitivity < 0.001 do + mouse_sensitivity = 0.001 # Minimum sensitivity + end + end + + # Show cursor with F1 (useful for debugging) + if is_key_pressed(KEY_F1) != 0 do + enable_cursor() + end + + # Toggle FPS meter with F2 (hide) and F3 (show) + if is_key_pressed(KEY_F2) != 0 do + hide_fps_meter() + fps_meter_visible = 0 + end + if is_key_pressed(KEY_F3) != 0 do + show_fps_meter(Vec2 { x: 10.0, y: 10.0 }) + fps_meter_visible = 1 + end + + # Direction vectors are updated above + + # Camera follows player (at eye position, slightly in front) + camera_x = player_x + forward_x * 0.5 # Offset forward + camera_y = player_y + 0.9 # Eye height + camera_z = player_z + forward_z * 0.5 # Offset forward + + # Camera looks where player is looking + target_x = player_x + forward_x * 5.0 + target_y = player_y + forward_y * 5.0 + target_z = player_z + forward_z * 5.0 + + # Player rotation is handled visually during rendering + + # Get cube positions from physics bodies + ode_body_get_position(cube1_body, &cube1_x, &cube1_y, &cube1_z) + ode_body_get_position(cube2_body, &cube2_x, &cube2_y, &cube2_z) + ode_body_get_position(cube3_body, &cube3_x, &cube3_y, &cube3_z) + + # ==== RENDERING ==== begin_drawing() clear_background(135, 206, 235, 255) # Sky blue + + # 3D mode with calculated camera + begin_mode3d(camera_x, camera_y, camera_z, target_x, target_y, target_z, 0.0, 1.0, 0.0, 45.0, 0) + + # Draw ground plane + draw_cube(0.0, -1.0, 0.0, 100.0, 0.1, 100.0, 34, 139, 34, 255) # Green ground + + # Draw cubes + draw_cube(cube1_x, cube1_y, cube1_z, 1.0, 1.0, 1.0, 255, 0, 0, 255) # Red + draw_cube_wires(cube1_x, cube1_y, cube1_z, 1.0, 1.0, 1.0, 0, 0, 0, 255) + + draw_cube(cube2_x, cube2_y, cube2_z, 1.0, 1.0, 1.0, 0, 255, 0, 255) # Green + draw_cube_wires(cube2_x, cube2_y, cube2_z, 1.0, 1.0, 1.0, 0, 0, 0, 255) + + draw_cube(cube3_x, cube3_y, cube3_z, 1.0, 1.0, 1.0, 0, 0, 255, 255) # Blue + draw_cube_wires(cube3_x, cube3_y, cube3_z, 1.0, 1.0, 1.0, 0, 0, 0, 255) - begin_mode3d(camera_x, camera_y, camera_z, player_x, player_y, player_z, 0.0, 1.0, 0.0, 45.0, 0) - - # Draw ground - draw_cube(0.0, -0.5, 0.0, 20.0, 1.0, 20.0, 34, 139, 34, 255) # Green ground - - # Draw player - draw_cube(player_x, player_y, player_z, 1.0, 1.0, 1.0, 0, 255, 0, 255) # Green player + # Draw player model with rotation (yellow cube to represent the player) + rl_push_matrix() + rl_translate_f(player_x, player_y, player_z) + rl_rotate_f(-yaw * 180.0 / 3.14159, 0.0, 1.0, 0.0) # Convert radians to degrees for Y-axis rotation, negate for correct direction + draw_cube(0.0, 0.0, 0.0, 0.8, 1.6, 0.8, 255, 255, 0, 255) # Yellow player + draw_cube_wires(0.0, 0.0, 0.0, 0.8, 1.6, 0.8, 0, 0, 0, 255) + rl_pop_matrix() end_mode3d() + end_drawing() end 0 -end \ No newline at end of file +end diff --git a/fps_game b/fps_game deleted file mode 100755 index 59080a9..0000000 Binary files a/fps_game and /dev/null differ diff --git a/libsuicmez/libsuicmez.c b/libsuicmez/libsuicmez.c index 532b1b0..3c72962 100644 --- a/libsuicmez/libsuicmez.c +++ b/libsuicmez/libsuicmez.c @@ -18,6 +18,11 @@ static AllocationInfo tracked_allocations[MAX_TRACKED_ALLOCATIONS]; static int allocation_count = 0; static const char *last_error = NULL; +// FPS meter state +static bool fps_meter_visible = false; +static int fps_meter_x = 0; +static int fps_meter_y = 0; + // Simple linear search to find allocation static int find_allocation(void *ptr) { for (int i = 0; i < allocation_count; i++) { @@ -78,10 +83,30 @@ void suic_set_target_fps(int fps) { SetTargetFPS(fps); } void suic_enable_msaa_4x(void) { SetConfigFlags(FLAG_MSAA_4X_HINT); } +// Timing +float suic_get_frame_time(void) { return GetFrameTime(); } + +// FPS meter +void suic_show_fps_meter(suic_vec2 position) { + fps_meter_visible = true; + fps_meter_x = (int)position.x; + fps_meter_y = (int)position.y; +} + +void suic_hide_fps_meter(void) { + fps_meter_visible = false; +} + // Drawing void suic_begin_drawing(void) { BeginDrawing(); } -void suic_end_drawing(void) { EndDrawing(); } +void suic_end_drawing(void) { + // Draw FPS meter if enabled + if (fps_meter_visible) { + DrawFPS(fps_meter_x, fps_meter_y); + } + EndDrawing(); +} void suic_clear_background(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { diff --git a/libsuicmez/libsuicmez.h b/libsuicmez/libsuicmez.h index dba015f..0042020 100644 --- a/libsuicmez/libsuicmez.h +++ b/libsuicmez/libsuicmez.h @@ -81,6 +81,8 @@ static inline suic_vec3 suic_from_rl_vec3(Vector3 v) { #define KEY_KP_ADD 334 #define KEY_KP_SUBTRACT 333 #define KEY_F1 290 +#define KEY_F2 291 +#define KEY_F3 292 // Mouse button constants #define MOUSE_LEFT 0 @@ -94,6 +96,13 @@ bool suic_window_should_close(void); void suic_set_target_fps(int fps); void suic_enable_msaa_4x(void); +// Timing +float suic_get_frame_time(void); + +// FPS meter +void suic_show_fps_meter(suic_vec2 position); +void suic_hide_fps_meter(void); + // Drawing (2D) void suic_begin_drawing(void); void suic_end_drawing(void); diff --git a/src/codegen/transpiler.rs b/src/codegen/transpiler.rs index 87aa005..66a1caa 100644 --- a/src/codegen/transpiler.rs +++ b/src/codegen/transpiler.rs @@ -102,7 +102,7 @@ impl Transpiler { let mut output = String::new(); // Add includes - output.push_str("#include \"../libsuicmez/libsuicmez.h\"\n"); + output.push_str("#include \"libsuicmez/libsuicmez.h\"\n"); output.push_str("#include \n"); output.push_str("#include \n"); output.push_str("#include \n"); @@ -576,8 +576,11 @@ impl Transpiler { "init_window" => "suic_init_window", "close_window" => "suic_close_window", "window_should_close" => "suic_window_should_close", - "set_target_fps" => "suic_set_target_fps", - "enable_msaa_4x" => "suic_enable_msaa_4x", + "set_target_fps" => "suic_set_target_fps", + "enable_msaa_4x" => "suic_enable_msaa_4x", + "get_frame_time" => "suic_get_frame_time", + "show_fps_meter" => "suic_show_fps_meter", + "hide_fps_meter" => "suic_hide_fps_meter", "begin_drawing" => "suic_begin_drawing", "end_drawing" => "suic_end_drawing", "clear_background" => "suic_clear_background", @@ -663,13 +666,23 @@ impl Transpiler { .iter() .map(|(name, expr)| format!(".{} = {}", name, self.generate_expr(expr))) .collect(); - format!( - "suic_alloc_struct(&sui_typeinfo_{}, sizeof(struct {}), &(struct {}){{ {} }})", - struct_name, - struct_name, - struct_name, - field_inits.join(", ") - ) + let c_type_name = match struct_name.as_str() { + "Vec2" => "suic_vec2".to_string(), + "Vec3" => "suic_vec3".to_string(), + _ => format!("struct {}", struct_name), + }; + // For built-in simple structs, generate compound literal directly + // For user-defined structs, use heap allocation + match struct_name.as_str() { + "Vec2" | "Vec3" => format!("({}){{ {} }}", c_type_name, field_inits.join(", ")), + _ => format!( + "suic_alloc_struct(&sui_typeinfo_{}, sizeof({}), &({}){{ {} }})", + struct_name, + c_type_name, + c_type_name, + field_inits.join(", ") + ), + } } CExpr::EnumLit(enum_name, variant_name, args) => { // Find the variant index - for simplicity, assume variants are in order diff --git a/src/typechecker.rs b/src/typechecker.rs index c7ac8a7..2490631 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -668,6 +668,30 @@ impl TypeChecker { return_type: Type::Unit, }, ); + self.env.functions.insert( + "get_frame_time".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Float, + }, + ); + self.env.functions.insert( + "show_fps_meter".to_string(), + FunctionType { + type_params: vec![], + params: vec![Type::Struct("Vec2".to_string(), vec![])], + return_type: Type::Unit, + }, + ); + self.env.functions.insert( + "hide_fps_meter".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Unit, + }, + ); // Cursor management self.env.functions.insert( @@ -718,7 +742,7 @@ impl TypeChecker { "KEY_W", "KEY_A", "KEY_S", "KEY_D", "KEY_SPACE", "KEY_LEFT_SHIFT", "KEY_EQUAL", "KEY_MINUS", "KEY_KP_ADD", "KEY_KP_SUBTRACT", "KEY_ESCAPE", "KEY_ENTER", "KEY_TAB", "KEY_BACKSPACE", "KEY_DELETE", - "KEY_HOME", "KEY_END", "KEY_F1" + "KEY_HOME", "KEY_END", "KEY_F1", "KEY_F2", "KEY_F3" ]; for (i, key) in keys.iter().enumerate() { let id = 1000 + i; diff --git a/test_window b/test_window deleted file mode 100755 index 96801af..0000000 Binary files a/test_window and /dev/null differ diff --git a/tests/basic_types.c b/tests/basic_types.c index ce4f999..27443d9 100644 --- a/tests/basic_types.c +++ b/tests/basic_types.c @@ -1,4 +1,4 @@ -#include "../libsuicmez/libsuicmez.h" +#include "libsuicmez/libsuicmez.h" #include #include #include diff --git a/tests/fps_game.c b/tests/fps_game.c index cd2e145..c8665b3 100644 --- a/tests/fps_game.c +++ b/tests/fps_game.c @@ -1,4 +1,4 @@ -#include "../libsuicmez/libsuicmez.h" +#include "libsuicmez/libsuicmez.h" #include #include #include @@ -30,8 +30,8 @@ int suic_main(void); int suic_main(void) { suic_enable_msaa_4x(); - suic_init_window(1280, 720, suic_alloc_array(NULL, sizeof(char), 75, "Sui FPS Game - WASD to move, Mouse to look, SPACE to jump, SHIFT to sprint")); - suic_set_target_fps(60); + suic_init_window(1280, 720, suic_alloc_array(NULL, sizeof(char), 112, "Sui FPS Game - WASD to move, Mouse to look, SPACE to jump, SHIFT to sprint, F1 cursor, F2 hide FPS, F3 show FPS")); + suic_show_fps_meter((suic_vec2){ .x = 10.000000, .y = 10.000000 }); suic_disable_cursor(); suic_ode_init(); void* world = suic_ode_world_create(); @@ -75,6 +75,7 @@ int suic_main(void) { float yaw = 0.000000; float pitch = 0.000000; float mouse_sensitivity = 0.003000; + int fps_meter_visible = 1; float cube1_x = 0.000000; float cube1_y = 0.000000; float cube1_z = 0.000000; @@ -88,7 +89,27 @@ int suic_main(void) { float player_y = 2.000000; float player_z = 0.000000; while ((suic_window_should_close() == false)) { - float delta_time = 0.016660; + float delta_time = suic_get_frame_time(); + float mouse_delta_x = suic_get_mouse_delta_x(); + float mouse_delta_y = suic_get_mouse_delta_y(); + yaw = (yaw + (mouse_delta_x * mouse_sensitivity)); + pitch = (pitch - (mouse_delta_y * mouse_sensitivity)); + if ((pitch > 1.500000)) { + pitch = 1.500000; + } + if ((pitch < -1.500000)) { + pitch = -1.500000; + } + float cos_yaw = cos(yaw); + float sin_yaw = sin(yaw); + float cos_pitch = cos(pitch); + float sin_pitch = sin(pitch); + forward_x = sin_yaw; + forward_y = sin_pitch; + forward_z = -cos_yaw; + right_x = cos_yaw; + right_y = 0.000000; + right_z = sin_yaw; float move_speed = 5.000000; float target_vx = 0.000000; float target_vz = 0.000000; @@ -122,6 +143,11 @@ int suic_main(void) { } } suic_ode_body_set_linear_vel(player_body, target_vx, current_vy, target_vz); + suic_ode_space_collide(world, space, contactgroup); + if ((delta_time > 0.000000)) { + suic_ode_world_step(world, delta_time); + } + suic_ode_joint_group_empty(contactgroup); suic_ode_body_get_position(player_body, &player_x, &player_y, &player_z); if (((suic_is_key_pressed(KEY_EQUAL) != 0) || (suic_is_key_pressed(KEY_KP_ADD) != 0))) { mouse_sensitivity = (mouse_sensitivity + 0.001000); @@ -135,29 +161,14 @@ int suic_main(void) { if ((suic_is_key_pressed(KEY_F1) != 0)) { suic_enable_cursor(); } - float mouse_delta_x = suic_get_mouse_delta_x(); - float mouse_delta_y = suic_get_mouse_delta_y(); - yaw = (yaw + (mouse_delta_x * mouse_sensitivity)); - pitch = (pitch - (mouse_delta_y * mouse_sensitivity)); - if ((pitch > 1.500000)) { - pitch = 1.500000; + if ((suic_is_key_pressed(KEY_F2) != 0)) { + suic_hide_fps_meter(); + fps_meter_visible = 0; } - if ((pitch < -1.500000)) { - pitch = -1.500000; + if ((suic_is_key_pressed(KEY_F3) != 0)) { + suic_show_fps_meter((suic_vec2){ .x = 10.000000, .y = 10.000000 }); + fps_meter_visible = 1; } - suic_ode_space_collide(world, space, contactgroup); - suic_ode_world_step(world, delta_time); - suic_ode_joint_group_empty(contactgroup); - float cos_yaw = cos(yaw); - float sin_yaw = sin(yaw); - float cos_pitch = cos(pitch); - float sin_pitch = sin(pitch); - forward_x = sin_yaw; - forward_y = sin_pitch; - forward_z = -cos_yaw; - right_x = cos_yaw; - right_y = 0.000000; - right_z = sin_yaw; camera_x = (player_x + (forward_x * 0.500000)); camera_y = (player_y + 0.900000); camera_z = (player_z + (forward_z * 0.500000)); diff --git a/tests/fps_game.o b/tests/fps_game.o index 2cb269e..5429807 100755 Binary files a/tests/fps_game.o and b/tests/fps_game.o differ diff --git a/tests/fps_game.sui b/tests/fps_game.sui index 4ca9474..e2fa748 100644 --- a/tests/fps_game.sui +++ b/tests/fps_game.sui @@ -6,12 +6,15 @@ fn main() -> int do enable_msaa_4x() # Initialize graphics - init_window(1280, 720, "Sui FPS Game - WASD to move, Mouse to look, SPACE to jump, SHIFT to sprint") - defer close_window() - set_target_fps(60) + init_window(1280, 720, "Sui FPS Game - WASD to move, Mouse to look, SPACE to jump, SHIFT to sprint, F1 cursor, F2 hide FPS, F3 show FPS") + defer close_window() + # set_target_fps(60) - # Hide cursor and capture mouse for FPS controls - disable_cursor() + # Show FPS meter + show_fps_meter(Vec2 { x: 10.0, y: 10.0 }) + + # Hide cursor and capture mouse for FPS controls + disable_cursor() # Initialize physics ode_init() @@ -93,6 +96,9 @@ fn main() -> int do let mut yaw = 0.0 let mut pitch = 0.0 let mut mouse_sensitivity = 0.003 + + # FPS meter toggle + let mut fps_meter_visible = 1 # Cube position variables let mut cube1_x = 0.0 @@ -105,115 +111,128 @@ fn main() -> int do let mut cube3_y = 0.0 let mut cube3_z = 0.0 - # Player position (initial values) - let mut player_x = 0.0 - let mut player_y = 2.0 - let mut player_z = 0.0 + # Player position (initial values) + let mut player_x = 0.0 + let mut player_y = 2.0 + let mut player_z = 0.0 - # Main game loop - while window_should_close() == false do - # Input handling - let delta_time = 0.01666 # ~60 FPS + # Main game loop + while window_should_close() == false do + # Get actual frame delta time + let delta_time = get_frame_time() - # WASD movement - set velocities on physics body - let move_speed = 5.0 # Velocity applied to body - let mut target_vx = 0.0 - let mut target_vz = 0.0 + # Mouse look + let mouse_delta_x = get_mouse_delta_x() + let mouse_delta_y = get_mouse_delta_y() - if is_key_down(KEY_W) != 0 do - target_vx = target_vx + forward_x * move_speed - target_vz = target_vz + forward_z * move_speed - end + yaw = yaw + (mouse_delta_x * mouse_sensitivity) + pitch = pitch - (mouse_delta_y * mouse_sensitivity) # Negate Y for natural FPS controls - if is_key_down(KEY_S) != 0 do - target_vx = target_vx - forward_x * move_speed - target_vz = target_vz - forward_z * move_speed - end + # Clamp pitch to prevent flipping + if pitch > 1.5 do + pitch = 1.5 + end + if pitch < -1.5 do + pitch = -1.5 + end - if is_key_down(KEY_D) != 0 do - target_vx = target_vx + right_x * move_speed - target_vz = target_vz + right_z * move_speed - end + # Calculate camera direction from yaw and pitch + let cos_yaw = cos(yaw) + let sin_yaw = sin(yaw) + let cos_pitch = cos(pitch) + let sin_pitch = sin(pitch) - if is_key_down(KEY_A) != 0 do - target_vx = target_vx - right_x * move_speed - target_vz = target_vz - right_z * move_speed - end + # Update forward and right vectors FIRST (before movement) + forward_x = sin_yaw + forward_y = sin_pitch + forward_z = -cos_yaw - # Get current velocity for Y (preserve gravity) - let mut current_vx = 0.0 - let mut current_vy = 0.0 - let mut current_vz = 0.0 - ode_body_get_linear_vel(player_body, ¤t_vx, ¤t_vy, ¤t_vz) + right_x = cos_yaw + right_y = 0.0 + right_z = sin_yaw - # Jump - set upward velocity - if is_jump_pressed() != 0 do - # Get current position to check if on ground - let mut dummy_x = 0.0 - let mut current_y = 0.0 - let mut dummy_z = 0.0 - ode_body_get_position(player_body, &dummy_x, ¤t_y, &dummy_z) - if current_y <= 1.3 do # On ground (box bottom is at y - 0.8 from center) - current_vy = 8.0 # Jump velocity - end - end + # WASD movement - set velocities on physics body + let move_speed = 5.0 # Units per second + let mut target_vx = 0.0 + let mut target_vz = 0.0 - # Set new velocity (keep Y velocity for gravity/jumping) - ode_body_set_linear_vel(player_body, target_vx, current_vy, target_vz) + if is_key_down(KEY_W) != 0 do + target_vx = target_vx + forward_x * move_speed + target_vz = target_vz + forward_z * move_speed + end - # Get player position from physics body - ode_body_get_position(player_body, &player_x, &player_y, &player_z) + if is_key_down(KEY_S) != 0 do + target_vx = target_vx - forward_x * move_speed + target_vz = target_vz - forward_z * move_speed + end - # Adjust mouse sensitivity - if is_key_pressed(KEY_EQUAL) != 0 or is_key_pressed(KEY_KP_ADD) != 0 do # + key - mouse_sensitivity = mouse_sensitivity + 0.001 - end - if is_key_pressed(KEY_MINUS) != 0 or is_key_pressed(KEY_KP_SUBTRACT) != 0 do # - key - mouse_sensitivity = mouse_sensitivity - 0.001 - if mouse_sensitivity < 0.001 do - mouse_sensitivity = 0.001 # Minimum sensitivity - end - end + if is_key_down(KEY_D) != 0 do + target_vx = target_vx + right_x * move_speed + target_vz = target_vz + right_z * move_speed + end - # Show cursor with F1 (useful for debugging) - if is_key_pressed(KEY_F1) != 0 do - enable_cursor() - end + if is_key_down(KEY_A) != 0 do + target_vx = target_vx - right_x * move_speed + target_vz = target_vz - right_z * move_speed + end - # Mouse look - let mouse_delta_x = get_mouse_delta_x() - let mouse_delta_y = get_mouse_delta_y() + # Get current velocity for Y (preserve gravity) + let mut current_vx = 0.0 + let mut current_vy = 0.0 + let mut current_vz = 0.0 + ode_body_get_linear_vel(player_body, ¤t_vx, ¤t_vy, ¤t_vz) - yaw = yaw + (mouse_delta_x * mouse_sensitivity) - pitch = pitch - (mouse_delta_y * mouse_sensitivity) # Negate Y for natural FPS controls + # Jump - set upward velocity + if is_jump_pressed() != 0 do + # Get current position to check if on ground + let mut dummy_x = 0.0 + let mut current_y = 0.0 + let mut dummy_z = 0.0 + ode_body_get_position(player_body, &dummy_x, ¤t_y, &dummy_z) + if current_y <= 1.3 do # On ground (box bottom is at y - 0.8 from center) + current_vy = 8.0 # Jump velocity + end + end - # Clamp pitch to prevent flipping - if pitch > 1.5 do - pitch = 1.5 - end - if pitch < -1.5 do - pitch = -1.5 - end + # Set new velocity (keep Y velocity for gravity/jumping) + ode_body_set_linear_vel(player_body, target_vx, current_vy, target_vz) - # Update physics (just for cubes) - ode_space_collide(world, space, contactgroup) - ode_world_step(world, delta_time) - ode_joint_group_empty(contactgroup) + # Update physics (just for cubes) + ode_space_collide(world, space, contactgroup) + # Only step physics if delta_time is valid (guard against first frame which is 0) + if delta_time > 0.0 do + ode_world_step(world, delta_time) + end + ode_joint_group_empty(contactgroup) - # Calculate camera direction from yaw and pitch - let cos_yaw = cos(yaw) - let sin_yaw = sin(yaw) - let cos_pitch = cos(pitch) - let sin_pitch = sin(pitch) + # Get player position from physics body + ode_body_get_position(player_body, &player_x, &player_y, &player_z) - # Update forward and right vectors - forward_x = sin_yaw - forward_y = sin_pitch - forward_z = -cos_yaw + # Adjust mouse sensitivity + if is_key_pressed(KEY_EQUAL) != 0 or is_key_pressed(KEY_KP_ADD) != 0 do # + key + mouse_sensitivity = mouse_sensitivity + 0.001 + end + if is_key_pressed(KEY_MINUS) != 0 or is_key_pressed(KEY_KP_SUBTRACT) != 0 do # - key + mouse_sensitivity = mouse_sensitivity - 0.001 + if mouse_sensitivity < 0.001 do + mouse_sensitivity = 0.001 # Minimum sensitivity + end + end - right_x = cos_yaw - right_y = 0.0 - right_z = sin_yaw + # Show cursor with F1 (useful for debugging) + if is_key_pressed(KEY_F1) != 0 do + enable_cursor() + end + + # Toggle FPS meter with F2 (hide) and F3 (show) + if is_key_pressed(KEY_F2) != 0 do + hide_fps_meter() + fps_meter_visible = 0 + end + if is_key_pressed(KEY_F3) != 0 do + show_fps_meter(Vec2 { x: 10.0, y: 10.0 }) + fps_meter_visible = 1 + end # Direction vectors are updated above diff --git a/tests/structs.c b/tests/structs.c index 54d0ea1..6faa376 100644 --- a/tests/structs.c +++ b/tests/structs.c @@ -1,4 +1,4 @@ -#include "../libsuicmez/libsuicmez.h" +#include "libsuicmez/libsuicmez.h" #include #include #include