Low-poly Rat Simulator
Engine: Unity 2022 LTS • Language: C# • Role: Solo Developer
Overview
A playful low-poly prototype where you control a mischievous rat. The focus was on feel: responsive third-person movement, ragdoll toggling (for chaos/falls), a simple tunnel system for squeezing through narrow spaces, and a clean URP setup with Cinemachine for a dynamic camera.
Footage
Ragdolling
Pushing and Tunnelling
Image Gallery
What I built (programmer focus)
Character controller & camera
- Third-person movement with grounded checks and coyote-time jump feel.
- Cinemachine FreeLook/Virtual Cameras for responsive framing; collision and dead-zone tuning for low-poly sets.
Ragdoll toggle
- Enable/disable ragdoll on demand (e.g., impacts/falls). Animator is disabled while ragdoll is active; on recovery, blend back to an animation pose.
- All limb rigidbodies are toggled between kinematic (animated) and dynamic (ragdoll).
Tunnel mechanics
- When entering a tunnel trigger, swap to a “crawl” state: adjust collider height/center, reduce speed, limit jump.
- Optional camera switch to a tighter Cinemachine Virtual Camera for confined spaces.
URP setup
- Simple low-poly, unlit/flat-lit look for clarity and performance.
- Post-processing profile for subtle vibrance and vignette; kept mobile-friendly.
Representative code
// Toggle ragdoll on/off (attach to root holding Animator + limb rigidbodies)
[SerializeField] Animator animator;
[SerializeField] Rigidbody[] ragdollBodies;
[SerializeField] bool isRagdoll;
void SetRagdoll(bool enabled) {
isRagdoll = enabled;
animator.enabled = !enabled;
foreach (var rb in ragdollBodies) {
rb.isKinematic = !enabled; // dynamic when ragdoll, kinematic when animated
rb.detectCollisions = enabled;
}
// Optionally: add an impulse when entering ragdoll for dramatic effect
} // Simple tunnel enter/exit: shrink collider, adjust movement + optional camera
[SerializeField] CharacterController cc;
[SerializeField] float normalHeight = 1.2f, tunnelHeight = 0.6f;
[SerializeField] float normalSpeed = 5f, tunnelSpeed = 2.5f;
bool inTunnel;
void OnTriggerEnter(Collider other) {
if (other.CompareTag("Tunnel")) {
inTunnel = true;
cc.height = tunnelHeight;
cc.center = new Vector3(0, tunnelHeight * 0.5f, 0);
}
}
void OnTriggerExit(Collider other) {
if (other.CompareTag("Tunnel")) {
inTunnel = false;
cc.height = normalHeight;
cc.center = new Vector3(0, normalHeight * 0.5f, 0);
}
}
void Update() {
float speed = inTunnel ? tunnelSpeed : normalSpeed;
// ... move with speed, clamp jump while inTunnel, etc.
} // Cinemachine: switch VCs (e.g., normal vs tunnel) by priority
[SerializeField] Cinemachine.CinemachineVirtualCamera normalCam;
[SerializeField] Cinemachine.CinemachineVirtualCamera tunnelCam;
void SwitchToTunnelCam(bool tunnel) {
normalCam.Priority = tunnel ? 0 : 10;
tunnelCam.Priority = tunnel ? 10 : 0;
} Results & next steps
- Responsive third-person feel with fun ragdoll moments.
- Camera stays readable in cramped spaces via VC switch + tuned dead-zones.
- Next: add collectibles/objectives, polish recovery from ragdoll with pose matching, and refine tunnel traversal animations.