Skip to main content

"Angry Ball" - my exdended version of Unity3d tutorial game


Hello guys, in this article I am going to tell you about my experince in Unity3d and show you my game, created while learning this game development engine.

Let's start. If you have not heard about Unity3d, it would be interesting for you to know, that it is game development engine, due to which you can create your own game. It provides you tools for development, modelling, compiling to different platforms and more and more usefull things. For more information you can visit Unity3d website: https://unity3d.com/

When I started learning Unity3d, I ran into one interesting tutorial. It was game, where you are running as a ball and your goal is to eat all the cubes, which are on a map. Sure, it was very simlpified, because it is only learning example, so that all parts (player, cubes and map) of this game consisted of simple geometrical shapes. Here is the link to this tutorial: https://unity3d.com/learn/tutorials/projects/roll-ball-tutorial In this tuorial you can see, how to create scene, add game objects and scripts, run and build the game. After completing this I had an idea to extend this game. This extension I called "Angry Ball". The goal of this article is to describe this extension. What about original game from tutorial, which I used as a baseline, I suggest you to look through this tutorial. There is good description of it, also you can learn more how to create your own game using Unity3d. In my article I am going to show, what I did to extend this game, and explain functionality I added. That's why I recommend you to read the original tutorial. One nuance is that this tutorial is for Unity3d 5 version and I used earlier tutorial for Unity3d 4 version, so that some parts of Unity project or source codes may be different, but the core is similar.

As I mentioned, in original game you are running as a ball and your goal is to eat all the cubes, which are on a map. You can move using arrows or "WASD" buttons. There are 12 cubes. When you run into the cube - it disappears. It means you ate this cube. When you eat all the cubes you will win and the game is over. As you see, you cannot lose in this game. It is quite boring. Because of it I extended the gameplay. 


In my game your ball has it's own colour - red, green or blue, which can change pressing buttons. At first, you are red. To become a green one you have to press "X" button. To become a blue one you have to press "C" button. To become a red one again you have to press "Z" button. You can switch colours in different combinations. Each cube also has it's own colour. The main complexity of this game is that you only can eat cubes colored as you, so that you have to switch colour several times to win the game. Also, your ball has mass, so that you cannot stop immidiately after you stop pressing button because of inertia. That's why you cannot change your direction immidiately pressing another button. When you run into cube, which is not coloured as your ball, you lose. One more functionality I added is jumping. Your ball jumps after pressing "Space" button. However, it is quite useless addition for this game =) Nevertheless, you can lose, when you jump out of the map, so be careful, while jumping! 



As you can see, we have jumped on the border.

Let's change colour of the ball:


So, let's walk through the code. In our project we have one scene with objects on it, as ball, cubes, floor and walls. Also we have 3 scripts, which manage our gaming process. This strucure is the same in original game as well as in my extension. The difference is that I added some methods to scripts and modified existing. Let's review our scripts.

CameraController.cs: I had no need to modify it.

Rotator.cs: In this file I added Start() method. I used it for initialization. Unity engine recognizes Start() method and runs it after the script component was enabled. In this method I put logic for random setting initial colour for cubes, as we can see:

 private void Start()  
 {  
      int rand = Random.Range (1, 4);  
      switch (rand)  
      {  
           case 1:  
                gameObject.GetComponent<Renderer>().material.color = Color.red;  
                break;  
           case 2:  
                gameObject.GetComponent<Renderer>().material.color = Color.green;  
                break;  
           case 3:  
                gameObject.GetComponent<Renderer>().material.color = Color.blue;  
                break;  
      }  
 }

PlayerController.cs: There are the most valuable and interesting changes. Next we have class members:

 public float speed;  
 private int count;  
 private int result;  
 private int eaten;  
 private int eatenRed;  
 private int eatenGreen;  
 private int eatenBlue;  
 public Color newColour;  
 public GUIText countText;  
 public GUIText winText;  
 public Text EatenText;  
 public Text EatenRedText;  
 public Text EatenGreenText;  
 public Text EatenBlueText;  

As you can see, I added several variables, which are used to count how much cubes of what colour and all in general you have eaten. Also there are their Text type equivalents, which are necessary for displaying these values on UI. You probably noticed, that there are GUIText and Text types used. It is because basic game was written on Unity 4, then I updated environment to Unity 5 version and added my modifications, so that I couldn't use GUIText, which is currently obsolete, that's why I used Text. Maybe I will fix it in later versions and rewtrite obsolete code to new version, but it can take some efforts, because simply removing "GUI" prefix won't fix it =) Text objects are located in Canvas and GUIText objects are located in GameObject, added previosly for this specially for this issue. Let's look on the Start() method:

 private void Start()  
 {  
      count = 0;  
      SetCountText();  
      gameObject.GetComponent<Renderer>().material.color = Color.red;  
      newColour = Color.red;      
      winText.text = String.Empty;  
 }  

The difference between GUIText and Text:



Here I added call of SetCountText() method, about which we will talk later, and initial setting colour of ball to red.

 private void Update()  
 {  
      countText.text = String.Format("Count: {0}/12", count);  
      EatenText.text = String.Format("Eaten: {0}", eaten);  
      EatenRedText.text = String.Format("Eaten red: {0}", eatenRed);  
      EatenGreenText.text = String.Format("Eaten green: {0}", eatenGreen);  
      EatenBlueText.text = String.Format("Eaten blue: {0}", eatenBlue);  
 }

In Update() method we have only setting text values. Information about results always changes, so that we must by up to date with it, which is guaranteed by Update() method.

 private void Jump()  
 {  
      GetComponent<Rigidbody>().AddForce(Vector3.up*10, ForceMode.Impulse);  
 }  

Here is my jump feature. To perform jumping we only have to add up impulse to ball.

 private void FixedUpdate()  
 {  
      float moveHorizontal = Input.GetAxis("Horizontal");  
      float moveVertical = Input.GetAxis("Vertical");  
      Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);  
      GetComponent<Rigidbody>().AddForce(movement*speed*Time.deltaTime);  
      if (Input.GetKeyDown(KeyCode.Space) && !(GetComponent<Rigidbody>().position.y > 0.5f))  
      {  
           Jump();  
      }  
      if (GetComponent<Rigidbody>().position.y < -0.5f)  
      {  
           result = count;  
           gameObject.SetActive(false);  
           count = -1;  
           SetCountText();  
      }  
      ColourChanging();  
 }  

This method had several additions. Let's analyze them separately:

 if (Input.GetKeyDown(KeyCode.Space) && !(GetComponent<Rigidbody>().position.y > 0.5f))  
 {  
      Jump();  
 }  

First part of this condition simply means, that after pressing "Space" ball has to jump. Second part I added, because I had bug with multiple jumping while the ball is in the air yet. Now it can jump only if it is on the ground. 0.5f is hardcoded value, which means half height of the ball.

 if (GetComponent<Rigidbody>().position.y < -0.5f)  
 {  
      result = count;  
      gameObject.SetActive(false);  
      count = -1;  
      SetCountText();  
 }  

This is also addition for jumping feature. If you play with jumping too much, you can jump out of playground. In this case you will infinitely fall down. To fix it, I added this condition, which checks ball location on y-axis as in previous code block, and gives a message, that you lost. About SetCountText() we will talk a bit later. Now let's look on ColourChanging() method, which is called in the end of FixedUpdate():

 private void ColourChanging()  
 {  
      Color r = Color.red;  
      Color g = Color.green;  
      Color b = Color.blue;  
      if (Input.GetKeyDown(KeyCode.Z))  
      {  
           newColour = r;  
      }  
      if (Input.GetKeyDown(KeyCode.X))  
      {  
           newColour = g;  
      }  
      if (Input.GetKeyDown(KeyCode.C))  
      {  
           newColour = b;  
      }  
      gameObject.GetComponent<Renderer>().material.color = newColour;  
 }  

This awful code changes colour of the ball depending on input key. This method needs some refactoring, isn't it? As well as all my code =) So, let's move to the OnTriggerEnter(Collider other) method.

 private void OnTriggerEnter(Collider other)  
 {  
      if (other.gameObject.tag == "PickUp")  
      {  
           if (other.gameObject.GetComponent<Renderer>().material.color ==  
                gameObject.GetComponent<Renderer>().material.color)  
           {  
                other.gameObject.SetActive(false);  
                count++;  
                eaten++;  
                if (gameObject.GetComponent<Renderer>().material.color == Color.red)  
                {  
                     eatenRed++;  
                }  
                if (gameObject.GetComponent<Renderer>().material.color == Color.green)  
                {  
                     eatenGreen++;  
                }  
                if (gameObject.GetComponent<Renderer>().material.color == Color.blue)  
                {  
                     eatenBlue++;  
                }  
                SetCountText();  
           }  
           else  
           {  
                result = count;  
                gameObject.SetActive(false);  
                count = -1;  
                SetCountText();  
           }  
      }  
 }  

This is also modified method. Originally, it only checked if we collide the cube, and if yes, eat it, making inactive. I checked if colours of ball and cube are similar. If yes, I incremented general counter and counter of specific colour and deactivated the cube. If colours are different, I deactivated ball and showed a message, that you had lost. And the last method is SetCountText():

 private void SetCountText()  
 {  
      if (count >= 12)  
      {  
           winText.text += "You win!";  
      }  
      if (count == -1)  
      {  
           countText.text = "";  
           winText.text = "You lost!\n" + "Your result is " + result.ToString();  
      }  
 }  

Here I added only handling of losing game. Also, I used quite primitive way to track losing scenario. I set count variable to -1 when deactiveted the ball and now I check it in condition. If so, I understand, that player lost and I tell him about it. Also I show how many cubes he has eaten before he lost.

That's all about this script and my code in this project in general. In the original tutorial you can see scripts of original game. Here is link to my game on GitHub: https://github.com/Taras-Romanchuk/Unity3d-Angry-Ball

This is my very simple example, what can be done with Unity3d. I hope, if you have no experience with Unity3d, it will encourage you to explore this gamedev engine by yourself. After I created this extension, I almost forgot about it, but one day I get some tasks with Unity3d. There was quite big project and I had to connect it with database and integrate it with VKontakte social network. I had no idea, how to do this. Also, deployment of big project was too long, so that I remembered Angry Ball and started learning how to connect it with database and integrate it with VK using it as project for experiments. I succeeded with this task, it was quite interesting experince, that's why I want to share my knowledge, because I researched lots of information, tried thousand times, until finally found the solution. This article is the first part of my knowledge sharing. I am going to write one or maybe two more articles about this. I think, these articles might be more interesting and valuable than this one, but this is both my debut in software development articles and baseline for next articles about Angry Ball. I hope, I will manage to write them and share with you. I will try as soon as I can, but there are lots of work to do with it.

Thank you for reading this article, if you have some questions or feedback, feel free to comment, and I will try to reply.

P. S. I have pasted code to the article using this service: http://codeformatter.blogspot.com/

Comments

Post a Comment