• Pedro Civa Wiltuschnig

Drunkard Development Diary



I've always wanted to develop a ragdoll game, as I find physics simulation an amazing topic.

So I remembered this browser game I used to play a long time ago called Home Run Albanifest 2004, it's a infinite-runner type game where the character is drunk and the player needs to make sure he doesn't fall, by using the mouse to balance the character.


My idea was to try to re-create this game, but in Unity 3D using the assets and knowledge I have to make a more in-depth and fun experience.


First things first and probably the most important: The physics, I've always loved the way Euphoria Physics works (like in GTA) and the way they react to the environment around them, I knew I needed to somehow couple my character animations with the Unity Physics systems as well as some joints to glue everything together in a realistic way, so I went to Google and started doing some research. After some Googling I came across something called Active Ragdolls, it is something Sergio Abreu Garcia created, and in his own words translates to:

"Ragdolls that physically play animations through the use of joints and rigid bodies."


If anyone is interested, this is the Github Repo of his amazing work: https://github.com/sergioabreu-g/active-ragdolls.


I've decided to use Sergio's implementation of this system and make my game based on that. Thank you Sergio for your amazing work!


Development

The game has a simple concept, it consists of the player moving forward, while trying to maintain balance and avoid obstacles while the difficulty increases.



Part 1- Drunk Mechanics


On the first part of development I've decided to implement the basics, that is, player movement, what I called the drunk mechanics (what makes the player lose balance) and the controls for balancing the character.


For the basic player movement, I used the character prefab Sergio Abreu has already set up in his Github project and simply restricted the movement so the character is only able to move forward. (Thanks again Sergio!)


Next, for the drunk mechanics. It consists of a force that is applied on the character's Rigidbody component, either on it's right or left side ( X axis ), by a certain amount.

I've added a few parameters that we can customize, such as the drunk force (amount of force applied to our character), how long it takes to reach that force. I created a coroutine to make all of this happen. To better explain it, here's a snippet of the code:

The way it works is we first set a random value between our specified min and max (how strong we want the pushes to be). Then we say how long we want this to take, then we basically lerp the value until it reaches our randomVal while simultaneously applying the force to our character. Once we reach the value, we start over again.


If we didn't have the timeToReachTarget, the player would be pushed at once, but since we want to simulate unbalance, we want the force to be applied little by little over time, we accomplish that by using the Unity Lerp method.

We use a bool in the end to flag when we've reached the desired force, so that we can start pushing again, with a new value. It looks something like this on our Update() method.

 if (hasReachedPush == true)
            {
                hasReachedPush = false;
                StartCoroutine("PushPlayer");
            }

This is all for the drunk mechanics. The next step is to set up the player controls, so that we can balance the character. My initial thought was to use the mouse to balance the player, but to make matters simpler and easier for testing, I've decided to use the A and D keyboard keys instead (for now).


It is really very simple; all we have to do is apply a certain force to the character in whichever axis we define and multiply it by the force we want to apply. In my case I used the method Input.GetAxis("Horizontal"), "Horizontal" being the axis I want to use.

 float translate = Input.GetAxis("Horizontal") * force;
            if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D))
            {
                playerRB.AddForce(translate, 0f, 0f);
            }

This all comes down to 1 (left) or -1 (right) * force, applied to the X axis of our characters Rigidbody.

That's all for the basic mechanics. This is what the end result looks like:





Part 2- The Map

The next thing I wanted to work on was adding some environment to the game. The infinite runner style game has an issue; it needs an infinitely large map. Of course this is undoable due to obvious restrictions, but there are workarounds.


I've decided to implement a script to generate new parts and destroy old parts of the map at runtime.


For now, the floor is one big stretched game object, I am still working on a way to improve that (as I plan to have different terrains in the future). For generating the buildings, I've created a list that contains all the different buildings prefabs I wanted the map to have.


Then I set a few parameters:


1- The number of buildings to Instantiate on each batch.

2- The distance between buildings, for this one I decided to use a "one size fits all" type of approach, since the buildings have different sizes. In other words, I found a distance that seems to look good for most of the buildings.

3- How far the player has to move before the script generates more buildings.

4- A reference to the first building on the right side and another of for the first building on the left side (already on the map). They will serve as position references for the next ones to come.

references


This is what the method for generating the buildings look like:

First of all, "numOfBuildings" is how many of them we want to instantiate.

I've also declared some indexes for the right side and left side so the buildings are different in each side.


We Instantiate a new building based on the previous position + the build distance (moving towards the Z axis in our case), we then set the current building to be the newly Intantiated one, randomize the indexes again, and keep going until the number of buildings is reached.

The lamps are generated in the same way.

I've also assigned each game object to a container so that our hierarchy is organized.


Now that the main functionality is set up, when do we trigger this script?

As I said before, the script will trigger once the character reaches a certain distance, in our case we can use the Score system, which is based in distance. To explain how the score system works, it's pretty simple. I set a start line empty gameObject and attached a script to it; the script calculates the distance between the player and the Start Line using Vector3.Distance() method; it then updates the score text based on that.



That's it, it all looks good! But there's only one problem, the player will be able to see when the buildings pop up, he would also be able to see that there's nothing on the horizon except for a few buildings that don't go too far.



To fix this I added some fog to the scene. And made sure to match the distance for generating the buildings with our fog distance to that it all works seamlessly.

autoGenerateMapDist = RenderSettings.fogEndDistance;

This is what the end result looks like:

As you can see, the map is generated seamlessly on the fly!


The last thing to do was to destroy the old game objects, the easiest way I found to do that was to use a very neat Unity method called OnBecameInvisible(), this method is called every time no cameras in the scene are rendering an object. I've attached this script to all the prefabs I used on the map.

 private void OnBecameInvisible()
 {
    Destroy(this.gameObject);
 }

This is the end of the second part of this development journey!

Recent Posts

See All