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

The Map for the game the rat fully rigged and meshed the rat in its comedic ragdoll state

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.