Last active
June 21, 2025 15:29
-
-
Save naranyala/a1591e4c61e72b4693477f7b2355bdd4 to your computer and use it in GitHub Desktop.
odin code and raylib library for 3d scene starter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import rl "vendor:raylib" | |
| import "core:math/rand" | |
| import "core:fmt" | |
| import "core:math/linalg" | |
| Ball :: struct { | |
| position: rl.Vector3, | |
| active: bool, | |
| } | |
| main :: proc() { | |
| // Initialize window | |
| rl.InitWindow(800, 600, "3D Scene with Movable Box and Collectible Balls") | |
| defer rl.CloseWindow() | |
| // Set up 3D camera | |
| camera := rl.Camera3D{ | |
| position = {0, 10, 10}, | |
| target = {0, 0, 0}, | |
| up = {0, 1, 0}, | |
| fovy = 45, | |
| projection = .PERSPECTIVE, | |
| } | |
| // Box position and velocity | |
| box_position := rl.Vector3{0, 0.5, 0} // Box base touches plane (Y = 0.5 for 1.0 height) | |
| box_velocity := rl.Vector3{0, 0, 0} | |
| // Movement parameters | |
| acceleration: f32 = 1.4 // How fast the box speeds up | |
| max_speed: f32 = 0.8 // Maximum movement speed | |
| friction: f32 = 0.8 // Slows down when no input (0.0 = instant stop, 1.0 = no friction) | |
| // Game state | |
| score := 0 | |
| max_balls := 10 | |
| balls := make([]Ball, max_balls) | |
| // Generate random balls | |
| plane_size: f32 = 10.0 | |
| plane_half: f32 = plane_size / 2.0 | |
| ball_radius: f32 = 0.3 | |
| for i in 0..<max_balls { | |
| balls[i] = Ball{ | |
| position = { | |
| rand.float32_range(-plane_half + ball_radius, plane_half - ball_radius), | |
| ball_radius + 0.1, | |
| rand.float32_range(-plane_half + ball_radius, plane_half - ball_radius), | |
| }, | |
| active = true, | |
| } | |
| } | |
| // Set target FPS | |
| rl.SetTargetFPS(60) | |
| // Main loop | |
| for !rl.WindowShouldClose() { | |
| // Delta time for frame-rate independent movement | |
| dt := rl.GetFrameTime() | |
| // Box movement input | |
| move_input := rl.Vector3{0, 0, 0} | |
| if rl.IsKeyDown(rl.KeyboardKey.W) { | |
| move_input.z -= 1.0 | |
| } | |
| if rl.IsKeyDown(rl.KeyboardKey.S) { | |
| move_input.z += 1.0 | |
| } | |
| if rl.IsKeyDown(rl.KeyboardKey.A) { | |
| move_input.x -= 1.0 | |
| } | |
| if rl.IsKeyDown(rl.KeyboardKey.D) { | |
| move_input.x += 1.0 | |
| } | |
| // Normalize input to prevent diagonal speed boost | |
| if linalg.length(move_input) > 0 { | |
| move_input = linalg.normalize(move_input) | |
| } | |
| // Apply acceleration | |
| box_velocity += move_input * acceleration * dt | |
| // Apply friction | |
| box_velocity *= friction | |
| // Clamp velocity to max speed | |
| speed := linalg.length(box_velocity) | |
| if speed > max_speed { | |
| box_velocity = linalg.normalize(box_velocity) * max_speed | |
| } | |
| // Update position with boundary checking | |
| box_half_size: f32 = 0.5 | |
| new_position := box_position + box_velocity | |
| // Boundary checks | |
| if new_position.x < -plane_half + box_half_size { | |
| new_position.x = -plane_half + box_half_size | |
| box_velocity.x = 0 | |
| } | |
| if new_position.x > plane_half - box_half_size { | |
| new_position.x = plane_half - box_half_size | |
| box_velocity.x = 0 | |
| } | |
| if new_position.z < -plane_half + box_half_size { | |
| new_position.z = -plane_half + box_half_size | |
| box_velocity.z = 0 | |
| } | |
| if new_position.z > plane_half - box_half_size { | |
| new_position.z = plane_half - box_half_size | |
| box_velocity.z = 0 | |
| } | |
| // Keep Y grounded | |
| new_position.y = 0.5 | |
| box_position = new_position | |
| // Check collision with balls | |
| for &ball in balls { | |
| if ball.active { | |
| distance := rl.Vector3Distance(box_position, ball.position) | |
| collision_distance := box_half_size + ball_radius | |
| if distance < collision_distance { | |
| ball.active = false | |
| score += 1 | |
| } | |
| } | |
| } | |
| // Respawn balls if all collected | |
| all_collected := true | |
| for ball in balls { | |
| if ball.active { | |
| all_collected = false | |
| break | |
| } | |
| } | |
| if all_collected { | |
| for &ball in balls { | |
| ball.position = { | |
| rand.float32_range(-plane_half + ball_radius, plane_half - ball_radius), | |
| ball_radius + 0.1, | |
| rand.float32_range(-plane_half + ball_radius, plane_half - ball_radius), | |
| } | |
| ball.active = true | |
| } | |
| } | |
| // Begin drawing | |
| rl.BeginDrawing() | |
| defer rl.EndDrawing() | |
| // Clear background | |
| rl.ClearBackground(rl.RAYWHITE) | |
| // Begin 3D mode | |
| rl.BeginMode3D(camera) | |
| // Draw the movable box | |
| rl.DrawCube(box_position, 1.0, 1.0, 1.0, rl.RED) | |
| rl.DrawCubeWires(box_position, 1.0, 1.0, 1.0, rl.BLUE) | |
| // Draw collectible balls | |
| for ball in balls { | |
| if ball.active { | |
| rl.DrawSphere(ball.position, ball_radius, rl.GOLD) | |
| rl.DrawSphereWires(ball.position, ball_radius, 8, 8, rl.ORANGE) | |
| } | |
| } | |
| // Draw grid for reference | |
| rl.DrawGrid(10, 1.0) | |
| // End 3D mode | |
| rl.EndMode3D() | |
| // Draw UI | |
| score_text := fmt.ctprintf("Score: %d", score) | |
| rl.DrawText(score_text, 10, 10, 24, rl.DARKGREEN) | |
| rl.DrawText("WASD: Move Box", 10, 40, 20, rl.DARKGRAY) | |
| rl.DrawText("Collect the golden balls!", 10, 70, 20, rl.DARKGRAY) | |
| rl.DrawText("ESC: Exit", 10, 100, 20, rl.DARKGRAY) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment