Developing the Sonic Roll-a-Ball VR Game
By: Jolie Li
Tags: Virtual Reality, Science, Technology, Coding, Game Development

The original Sonic the Hedgehog video game.

We’ve all probably heard of the dark blue hedgehog that has the ability to run at the speed of sound (I know, pretty crazy). This guy is Sonic, a character in the Japanese video game series created by Sega called Sonic the Hedgehog. The game is simple, you control parts of Sonic’s movements and collect as many rings in the obstacle-full virtual world in the shortest amount of time as you can. The character and concept were a success, and its popularity increased through TV series adaptations, short animations, fan art, and movies. There have also been fangames on it, so trying to learn more about virtual reality (VR), a 3D environment generated by computers that allow users to interact with a simulated reality, I replicated one.

A video demo of Sonic Roll-A-Ball

The experience is simple, the player has to navigate through the virtual environment’s obstacle courses like skates, rocks, bushes, and platforms to collect all the rings. Once all 20 rings are collected, they win the game.

Components of the Game

The two main parts to creating this game are using the Unity VR game engine and writing C# coding scripts for the game mechanics to function properly.

Virtual Landscape and Obstacles

The virtual landscape

The game environment is low-poly with spread out lights, rocks, skates, and bushes. I started off with a plane and created three 3D cube objects that I scaled into walls. To apply the digital background and floor color pattern, I dragged color-patterned images to the base map of materials and put the materials on the 3D objects.

An inspector view of the mesh collider component applied to a rock mesh

For the obstacles, I imported downloads of mesh, a bundle of connected shapes, from free online 3D model databases. I then added a mesh collider component to all of them to make sure the player can later collide with obstacles, otherwise, it would travel straight through the objects. Once the obstacles were scaled and placed on the plane, I applied materials to them to give them coloring.

Floating light bulbs indicate the directional lights placed.

Lastly, to finish off the environment, I had to make sure the user can actually see what is around them when they run the game, so I placed floating directional lights around the game map.

Playing the Sonic Character

Sonic ball player

I created a rigidbody sphere to act as the roll-a-ball Sonic character and attached a dark blue material to it (a rigidbody is when an object’s motion follows Unity’s physics system). The character had to be able to move based on inputs (right now it is the keyboard arrows) and collide with its surroundings. Building the player in the game was one of the most difficult parts because to do this I had to code a C# script for Unity to understand what exactly I want the player to do.

An OnMove function declaration

I imported an input package to Unity and then attached a player input component to the sphere. Here, void means the code doesn’t need to return any values, and the InputValue and movementValue let Unity know the type of values being referenced, in this case: the user inputs keyboard arrows to move the player around the map. The variables movementX and movementY is the force applied to the player when an arrow key is pressed.

Listed variables used

Applying force to the player object (Sonic)

Forces are then applied to the rigidbody player object to allow it to move under the physics system using rb.AddForce. I also made a speed variable and multiplied it to movement in order for me to edit how fast Sonic goes in the Unity inspector.

Creating the Main Camera

The main camera facing the player

Placing the camera was a simple task, it comes by default with newly created Unity projects so all I had to do is position it via the inspector to make sure the user can view the player environment well. However, I need to make it so that the camera remains at one height and a certain distance away from the player.

A part of the CameraController script

To do this I had to create a CameraController script and had the offset of the camera position and player game object position calculated from the start function by finding the difference between the two. By adding offset to the player transform position under the LateUpdate, I can make sure that the camera object moves forward or backwards depending on the player game object’s movement. The player rigidbody object is then attached to the CameraController script in the Unity inspector so it can reference the player game object.

Creating Organized Rings

The rings

The rings are simply rotated small cube game objects with a ring image base map material applied to them. The tricky part was getting them to rotate and stand out. I also made all the rings a prefab to keep them organized and coherent.

A part of the Rotator script

To rotate the rings I created a Rotator script and used a transform.Rotate function to refer to the transforming rotation component. Attaching deltaTime to Time also makes sure the motion happens smoothly because it is a float that represents the difference in seconds since the former frame update.

All hierarchy objects in blue are prefabs

Next, to place multiple rings around the map, I made it into a prefab and duplicated the original ring to 19 others (a prefab is a blueprint of a game object’s family). This means if I make a change to a prefab ring, it will update those changes on all other rings under the prefab.

Collisions and Making Rings Collectable

Sonic and a collectible ring

As a part of the game, Sonic had to collect the rings, and I needed to make sure he doesn’t go off collecting walls or the ground plane. I used Unity’s built-in tagging system and tagged the original ring’s prefab (PickUp), which also applies this change to all the other rings in the prefab.

Code for deactivating an object if Sonic collides with a ring (PickUp)

In the script, I used a conditional statement so a game object only deactivates if it is tagged “PickUp” and collides with the player game object.

Notice that under the box collider component, “Is Trigger” is checked. The script rotator script is also attached to the collectible ring.

I also had to adjust the ring prefab components so that it is a trigger so objects can overlap it and it will disappear when the player game object collides with it. Additionally, I added a rigidbody component to the PickUp ring prefab and made it kinematic (an object that doesn’t react to the Unity physic forces but can be animated and moved by transform). The rings are now collectible! But there is no point in collecting them if the user doesn’t score some points.

Showing Score and Text

Storing the count of collected rings in the PlayerController script

After creating a private count variable and setting the count to 0 in the PlayerController script, I added a few lines of code shown above to increase the count as the player collides with more rings. I then added a Canvas user interface and TextMeshPro (required for the Canvas) to the hierarchy which allows me to display the count of collected rings to the user.

Displaying the count of collected rings in the PlayerController script

The code above directs Unity to show the text “Rings: ” along with the number of rings the player has collected. I then added another TextMeshPro under Canvas that displays “Congrats! You win!” when the player has collected all 20 rings!

End-of-game display

Changing Things Up

It’s my first VR game and I have to say, Unity really appeared very complicated in the beginning, but I couldn’t conclude building a VR game is hard when I haven’t even tried. Next time I’ll probably try out first-person VR and I might switch it around so that the player remains still but they can move their point of view through the main camera. Augmented reality games are on the radar too! A lot about virtual and augmented reality still seems so unfamiliar to me, so I’ll change how things are right now and continue hands-on projects to learn the skills in the industry.