From 1b26754f8f9239b277fe41bf754461a85c3cf060 Mon Sep 17 00:00:00 2001 From: Masashi Date: Wed, 17 Dec 2025 16:54:18 +0530 Subject: [PATCH] delta time usage --- compile.sh | 2 +- compile_and_run.sh | 2 +- fishsoup/main.c | 224 +++++++++++++++-------- fishsoup/main.o | Bin 43560 -> 45304 bytes fishsoup/main.sui | 362 ++++++++++++++++++++++++++------------ fps_game | Bin 49256 -> 0 bytes libsuicmez/libsuicmez.c | 27 ++- libsuicmez/libsuicmez.h | 9 + src/codegen/transpiler.rs | 33 ++-- src/typechecker.rs | 26 ++- test_window | Bin 44536 -> 0 bytes tests/basic_types.c | 2 +- tests/fps_game.c | 61 ++++--- tests/fps_game.o | Bin 44984 -> 45312 bytes tests/fps_game.sui | 209 ++++++++++++---------- tests/structs.c | 2 +- 16 files changed, 639 insertions(+), 320 deletions(-) delete mode 100755 fps_game delete mode 100755 test_window 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 1e14c563fba66044415641b5844683dc3e8810a7..2bb83a88c56fa5233ce054ae90cea906cbb19906 100755 GIT binary patch literal 45304 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 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 59080a9b48efc65e2779ee206bea97089e0b0c69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49256 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 Yu2;(zqmbP~$$9q25`H2_AqTbo2WO>Yr2qf` 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 96801af400dbf07f38585f067e7ce42ce4396a5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44536 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 #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 2cb269e738966b544cc7a668151708efcba2ee2c..5429807391b3a6612ff7de2a55a3f7f22cda921f 100755 GIT binary patch delta 14373 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 H8e;z+ZRapk 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