Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🦴 ragdoll

A hand-rolled Vulkan playground in modern C++17 — spawn on a procedurally generated island in an endless ocean, build with a live Bullet physics simulation, and survive as the day/night sky turns.

No engine. No asset pipeline. No textures. Just Vulkan, GLM, a physics engine, and a very countable pile of cubes.


✨ What is this?

You spawn onto a single seeded island — a coastal peak rising out of a calm, animated sea. The terrain is a true survival-start: mountains, beaches and plateaus all on one landmass, with nothing but open ocean in every other direction. The day/night clock drives the sun, moon, stars and lighting, so the island changes character as hours pass.

Drop cubes at the point you're aiming at, stack and shove them, walk into them (your body is an invisible kinematic capsule) — then pick one up, hold R to spin it around in your hand, and throw it as hard as you like. Every cube is simulated with mass, friction and restitution, so piles tumble, bounce and topple naturally. Carrying hugs the block to walls and floors instead of driving it through them.

📋 Features

🖥️ Renderer from scratch Instance/device/swapchain setup, resize handling, render-views + D32 depth, mailbox present mode (FIFO fallback), two-frames-in-flight ring buffers with persistent staging — no per-frame vkQueueWaitIdle, no CPU-side reallocation
🏝️ Survival island One seeded island on an endless ocean: a forced origin cell with a random-radius coastal profile and an offset mountain apex, so you never spawn on the mountaintop. Lattice-cell groundwork keeps adding more islands a one-line change away
🌊 Animated ocean Translucent, fresnel-lit, sun-glinting water plane that streams with the camera and hugs coastlines, exactly at sea level so land never sinks
🗺️ Streaming terrain The island (visual mesh 160 m / 96×96, collision mesh 160 m / 64×64) and the water re-center around the player as they move, staying perfectly in sync so gameplay matches the view — the endless ocean feels endless without ever loading more
🎲 Deterministic worlds Seedable noise — --seed N reproduces the exact same world, otherwise every run is unique
☀️ Day/night sky Real-time clock (240 s day) with a gradient sky, sun disc + halo, moon, twinkling stars, sunset corona, and CPU-driven ambient that the shared lighting model reads
📦 Physics cubes Up to 32 simulated cubes: place by raycast aim, knock them, stack them, carry them, throw them, or delete them
🎛️ Carry system Point-to-point constraint to a grab anchor in front of the camera; a forward raycast shortens the hold when a wall or floor is in the way, so the block rests against surfaces instead of jittering, and can be spun in hand (hold R + mouse)
Block outlines 8 px-wide glowing outlines on the carried cube and whatever you're aiming at, drawn through depth-biased line primitives with device line-width support
🏋️ Player collider An invisible kinematic capsule tracks the camera, so you can physically shove the cubes you've placed
🏃 Responsive camera Asymptotic accel/friction, look inertia, head-tilt on turns, speed-based FOV kick, terrain-following eye height (rides slopes, drops off cliffs), jump and gravity
🪟 Animated menus Breathing title glow, staggered fade-ins, hover glow/trail on buttons, and a fully styled settings screen — no pixel-font hacks
⚙️ Persistent settings Mouse sensitivity, FOV and every movement key are rebindable in-game and saved to ~/.config/ragdoll/settings.conf
🧭 Wayland-friendly Native Wayland app-id through GLFW, first-class Linux citizen

🎮 Controls

Input Action
W A S D Move
Mouse Look (pointer captured in-game)
Left click Place a cube at the aim point (re-captures the pointer if released)
Right click Remove the cube under the crosshair, or drop + remove the held one
E Pick up the cube you're looking at / drop the one you're holding
Q Throw the cube you're holding
R Rotate the held cube with the mouse (hold; releases R stops the spin but keeps holding)
Y Respawn
Esc Release the pointer (click to re-capture)
Space Jump
Left Ctrl Sprint
Left Shift Sneak

Movement keys, jump/interact/drop, plus mouse sensitivity and FOV are all rebindable in the Settings menu and persist to disk.

⚙️ Settings

The in-game Settings screen (from the main menu) exposes:

  • Video — mouse sensitivity and field of view sliders.
  • Controls — rebind any of the nine movement/action keys by clicking the binding and pressing a new key (Esc cancels).
  • Reset to Defaults — restores everything.

Values are saved as a plain key = value file to ~/.config/ragdoll/settings.conf (or $XDG_CONFIG_HOME/ragdoll/settings.conf when set).

📦 Dependencies

sudo dnf install -y gcc-c++ cmake glfw-devel glm-devel vulkan-headers vulkan-loader-devel glslc bullet-devel

ImGui is vendored as a git submodule — don't forget git submodule update --init --recursive.

🔨 Build & run

git submodule update --init --recursive
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/ragdoll

glslc compiles the GLSL shaders to SPIR-V during the build, and the .spv files are copied next to the binary automatically.

Reproduce a specific world round-trip:

./build/ragdoll --seed 1337

📁 Project layout

CMakeLists.txt             C++17 build; glslc->SPIR-V; Bullet + ImGui linking
shaders/shader.{vert,frag}  Procedural island terrain (layers + distance fog)
shaders/mesh.{vert,frag}    Instanced cube pipeline
shaders/outline.{vert,frag} Flat-color line pipeline for block outlines
shaders/sky.{vert,frag}     Fullscreen sky triangle: gradient, sun, moon, stars
shaders/water.{vert,frag}   Animated translucent sea plane
src/main.cpp                GLFW window, input, game loop, menu/settings/HUD UI, item logic
src/Camera.hpp/.cpp         FPS movement, look, tilt, FOV kick, jump/gravity, terrain-follow
src/Settings.hpp/.cpp       Persistent settings: load/save + human-readable key names
src/Terrain.hpp/.cpp        Seedable island elevation + climate sampling shared by render & physics
src/VulkanRenderer.hpp/.cpp Vulkan core: swapchain, pipelines, ring-buffered instancing, sky, water, imgui hooks
src/PhysicsWorld.hpp/.cpp   btDiscreteDynamicsWorld wrapper (fixed 1/120 substeps)
third_party/imgui           Dear ImGui submodule (1.93.0 WIP)

⚙️ Movement & physics tuning

Feel constants live in src/Camera.hpp; item/player constants in src/main.cpp; the island terrain sampling model in src/Terrain.cpp (sea level is kSeaLevel = -2.0 in Terrain.hpp).

  • ACCEL_RATE / FRICTION_RATE — body weight (acceleration vs. coasting)
  • LOOK_SMOOTH_RATE — how much the view lags behind the mouse
  • TILT_MAX_DEG / TILT_GAIN — head lean into turns
  • FOV_BOOST / FOV_SPRINT_EXTRA / FOV_SNEAK_REDUCE — FOV kick intensity
  • EYE_HEIGHT / GRAVITY / JUMP_SPEED / STEP_HEIGHT — jump feel, eye clamp, and how steep a slope the camera still rides as "ground"
  • MOVE_SPEED / SPRINT_SPEED / SNEAK_SPEED — top movement speeds
  • kItemSize / kItemMass / kPickupRange / kHoldDist / kHoldDistMin / kThrowSpeed / kMaxItems — cube geometry, carry feel, and throw power

The physics clock steps at a fixed 1/120 s with at most four substeps per frame, so cubes stay stable even under frame hitches.

🗺️ Roadmap

  • Per-object distance + frustum culling tied to the fog distance.
  • More item shapes (spheres, planks, cylinders) and a deletion/undo shortcut.
  • Screenshot capture and in-game audio.
  • Persist placed cubes so a build survives a restart.
  • In-game help overlay bound to the rebindable controls.

📜 License

MIT — go build something weird with it.

About

just a simple performant and lightweight ragdoll / template game

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages