suicmez/tests/fps_game.sui
2025-12-17 16:54:18 +05:30

290 lines
10 KiB
Text

# FPS-Style 3D Game with Sui Language
# Demonstrates WASD movement, mouse look, jumping, sprinting, and physics-based gameplay
fn main() -> int do
# Enable antialiasing
enable_msaa_4x()
# 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()
# Create physics world
let world = ode_world_create()
defer ode_world_destroy(world)
let null_space = 0 as *()
let space = ode_simple_space_create(null_space)
defer ode_space_destroy(space)
# Set gravity
ode_world_set_gravity(world, 0.0, -9.81, 0.0)
# Create contact joint group
let contactgroup = ode_joint_group_create(0)
defer ode_joint_group_destroy(contactgroup)
# 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)
# 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 player mass (box with density 1.0)
ode_body_set_box_mass(player_body, 1.0, 0.8, 1.6, 0.8)
# 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)
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)
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)
# 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
# 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 pitch < -1.5 do
pitch = -1.5
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)
# Update forward and right vectors FIRST (before movement)
forward_x = sin_yaw
forward_y = sin_pitch
forward_z = -cos_yaw
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, &current_vx, &current_vy, &current_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, &current_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)
# 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