The Trials, Tribulations, and Triumphs of Simulating Rabbit Behaviour in Unity

When I first decided to embark on the journey of simulating rabbit behavior in Unity, I had visions of adorable, fluffy creatures hopping around a picturesque meadow. Little did I know, this seemingly innocuous project would challenge me at every turn, forcing me to confront the intricacies of Unity, game physics, and the unpredictable nature of AI.

The Basic Hop – More Than Just a Simple Leap:

Every journey starts with a single step—or in this case, a hop. I figured I’d begin with getting the rabbit to move. How hard could it be? Quite hard, as it turns out.

  • The Challenge:
    • Getting the rabbits to move was one thing; getting them to hop realistically was another. The initial attempts were almost comical. Instead of hopping, the rabbits seemed to glide or slide, almost as if they were on an invisible skateboard.
  • Solution:
    • After much research and experimentation, I stumbled upon the sine function, a simple mathematical tool that could mimic the up-and-down motion of a hop. By adjusting the amplitude and frequency, the rabbits began to hop more naturally. It felt like a breakthrough, the first of many.

The Hopping Mechanism Explained:

In 3D simulations, motion can be achieved in various ways. One common approach is to apply forces, mimicking how objects in the real world move due to pushes and pulls. However, in a digital realm, relying solely on forces can lead to unintended consequences, especially when the applied force is too strong or interacts unpredictably with other forces or colliders.

Initially, the rabbit’s hopping mechanism was based on a force that propelled the rabbit upward. But this introduced a problem: the force sometimes caused the rabbit to penetrate the ground collider, making it fall through.

Solution:

Instead of using raw forces, we switched to a more controlled, mathematical approach to simulate the hopping motion. Here’s how it works:

Sinusoidal Movement: The up-and-down motion of hopping can be represented using a sine wave, which oscillates between -1 and 1. By taking the absolute value of this oscillation, we get a smooth curve that starts at 0, peaks at 1, and returns to 0 – perfect for simulating a hop.

float yOffset = Mathf.Abs(Mathf.Sin(hopProgress)) * genetics.hopHeight;

Hop Progress: To move through our sine curve over time, we use a variable called hopProgress. By incrementing this variable over time, we traverse through the sine wave.

hopProgress += genetics.hopSpeed * Time.deltaTime;

Adjusting the Height: The genetics.hopHeight multiplier ensures that different rabbits can hop to different heights based on their genetic traits.

By combining these concepts, we achieved a smooth, controlled hop that was entirely independent of Unity’s physics forces, preventing the rabbit from falling through the ground.

Navigating the Forested Plane:

Introducing trees to the environment seemed like a simple aesthetic enhancement. However, the reality was far more complex.

The Challenge:

Trees, being solid objects, acted as barriers to our rabbits. Due to the simple movement logic initially employed, rabbits often found themselves trapped against a tree, endlessly circling it or even worse, a group of them converging onto a single tree, leading to what looked like a forest rendezvous.

Solution:

Improving the AI’s navigational intelligence was essential. We introduced a series of checks to determine if a rabbit was “stuck” and then adjusted its behavior accordingly:

History Tracking: By keeping a short history of the rabbit’s positions, we could determine if it was making meaningful progress across the terrain or if it was stuck in a loop.

Avoidance Mechanisms: If a rabbit was deemed “stuck”, we implemented a series of movements to help it free itself. This included moving backward, making random turns, or even hopping in place to reorient itself.

Intelligent Targeting: Instead of choosing completely random destinations, the new logic ensured that the target points were within reasonable height differences, preventing the rabbit from endlessly trying to climb a steep hill or jump down a sharp cliff.

By combining these strategies, the rabbits became more adept at navigating the tree-dotted landscape, leading to a more realistic and less “orgy-like” behaviour around obstacles.

Confronting the Environment – Trees, Trees Everywhere!:

Once the hopping was ironed out, it was time to introduce some environmental challenges. I envisioned a plane with trees, where the rabbits could frolic and hide. However, this seemingly simple addition introduced a new set of challenges.

  • The Challenge:
    • A plane with trees sounds straightforward, right? But in the 3D world of Unity, these trees acted as barriers, often causing the rabbits to become trapped or endlessly circle a single tree.
  • Solution:
    • Adjusting the AI’s navigation logic was the key. The rabbits needed a smarter way to navigate around these tree “obstacles”. I revisited the movement algorithms, adding more logic to ensure that these furry creatures could gracefully avoid trees, or at the very least, not treat them like insurmountable walls.

A Thirst for Realism – The Water Detection Dilemma:

Survival instincts were next on the agenda. But my rabbits, in their infinite wisdom, would ignore water, even when they were virtually dying of thirst.

  • The Challenge:
    • How do you make a virtual rabbit thirsty? And once thirsty, how do you make it find water?
  • Solution:
    • I created a thirst mechanic, a counter that would increase over time. Once it reached a critical point, the rabbit would use Raycasting to detect nearby water. But then came the next problem—they recognized the water but didn’t know how to drink it! This required additional scripting to ensure that upon reaching water, the thirst counter reset.

Artificial Intelligence, Real Frustration – Making the Rabbits Think:

While the rabbits were moving and drinking, they weren’t exactly the sharpest tools in the shed. They’d often get stuck, showing no initiative to free themselves.

  • The Challenge:
    • How do you teach a virtual rabbit to think, to show some initiative?
  • Solution:
    • I introduced an “unstuck” mechanism. If a rabbit found itself trapped, it would first try moving backward. If that failed, it would turn in random directions. It was akin to teaching a child to problem-solve, and the results, while not perfect, were heartening.

Sensing the World – The Sensory Range Dilemma:

For added realism, I wanted the rabbits to have a limited sensory range. But this proved more challenging than anticipated.

  • The Challenge:
    • How do you replicate the limited sensory capabilities of a real rabbit in a virtual environment?
  • Solution:
    • After some research, I settled on a sensory range mechanism using the Physics.OverlapSphere. If something, like water, wasn’t within this range, the rabbit wouldn’t detect it. It added a layer of complexity to the simulation but greatly enhanced realism.

The Great Thirst Paradox – A Watery Dilemma:

The rabbits were hopping, navigating around trees, and generally behaving as one would expect. But nature has its demands, and soon enough, our rabbits grew thirsty. Given their new-found intelligence, they sought out water to quench their thirst. But here’s where things got intriguing.

  • The Challenge:
    • As the rabbits approached water sources to hydrate themselves, they didn’t drink. Instead, they started circling the water body, almost ritualistically. From a distance, it looked like a bizarre, fuzzy conga line or, humorously put, a small rabbit orgy.
  • Diagnosis:
    • After some debugging, I realized that while the rabbits were correctly identifying the water source, an essential trigger responsible for the drinking action seemed to be missing or malfunctioning. This meant that the rabbits recognized the water but didn’t know how to drink it.
  • Solution:
    • Ensuring all elements, like the water prefab in Unity, were correctly tagged and set up was crucial. A missing trigger meant the interaction between the rabbit and the water wasn’t being recognized. Adjusting the rabbit’s sensing mechanism to detect not just the proximity but also the “interactability” of the water was essential.

This incident was a classic reminder of the intricacies of game development, where even a tiny oversight can lead to hilariously unexpected results.

This journey is about more than just creating a rabbit simulation in Unity. It is about problem-solving, about facing challenges head-on, and about never settling for mediocrity. As I watched my virtual rabbits hop around, each one a testament to hours of hard work and dedication, I realized that in game development, as in life, the journey is just as important as the destination.