Skip to content

Instantly share code, notes, and snippets.

@naranyala
Last active June 21, 2025 15:29
Show Gist options
  • Select an option

  • Save naranyala/a1591e4c61e72b4693477f7b2355bdd4 to your computer and use it in GitHub Desktop.

Select an option

Save naranyala/a1591e4c61e72b4693477f7b2355bdd4 to your computer and use it in GitHub Desktop.
odin code and raylib library for 3d scene starter
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