Book Image

Mastering Unity Scripting

By : Alan Thorn
Book Image

Mastering Unity Scripting

By: Alan Thorn

Overview of this book

Table of Contents (17 chapters)
Mastering Unity Scripting
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Classes and polymorphism


To illustrate polymorphism in C#, let's start by considering the following code sample 1-12. This sample doesn't demonstrate polymorphism immediately but represents the start of a scenario where polymorphism will be useful, as we'll see. Here, a basic skeleton class is defined for a potential non-player character (NPC) in a generic RPG game. The class is intentionally not comprehensive and features basic variables that only mark the starting point for a character. The most important thing here is that the class features a SayGreeting function, which should be invoked when the player engages the NPC in conversation. It displays a generic welcome message to Console as follows:

01 using UnityEngine;
02 using System.Collections;
03 
04 public class MyCharacter
05 {
06 public string CharName = "";
07 public int Health = 100;
08 public int Strength = 100;
09 public float Speed = 10.0f;
10 public bool isAwake = true;
11 
12     //Offer greeting to the player when entering conversation
13     public virtual void SayGreeting()
14     {
15         Debug.Log ("Hello, my friend");
16     }
17 }

The first problem to arise relates to the diversity and believability of the MyCharacter class if we try imagining how it'd really work in a game. Specifically, every character instantiated from MyCharacter will offer exactly the same greeting when SayGreeting is invoked: men, women, orcs, and everybody. They'll all say the same thing, namely, "Hello, my friend". This is neither believable nor desirable. Perhaps, the most elegant solution would be to just add a public string variable to the class, thus allowing customization over the message printed. However, to illustrate polymorphism clearly, let's try a different solution. We could create several additional classes instead, all derived from MyCharacter, one for each new NPC type and each offering a unique greeting from a SayGreeting function. This is possible with MyCharacter, because SayGreeting has been declared using the virtual keyword (line 13). This allows derived classes to override the behavior of SayGreeting in the MyCharacter class. This means the SayGreeting function in derived classes will replace the behavior of the original function in the base class. Such a solution might look similar to the code sample 1-13:

01 using UnityEngine;
02 using System.Collections;
03 //-------------------------------------------
04 public class MyCharacter
05    {
06    public string CharName = "";
07    public int Health = 100;
08 public int Strength = 100;
09 public float Speed = 10.0f;
10 public bool isAwake = true;
11 
12 //Offer greeting to the player when entering conversation
13 public virtual void SayGreeting()
14 {
15        Debug.Log ("Hello, my friend");
16 	}
17 }
18 //-------------------------------------------
19 public class ManCharacter: MyCharacter
20 {
21 public override void SayGreeting()
22 {
23        Debug.Log ("Hello, I'm a man");
24 }
25 }
26 //-------------------------------------------
27 public class WomanCharacter: MyCharacter
28 {
29 public override void SayGreeting()
30 {
31        Debug.Log ("Hello, I'm a woman");
32 }
33 }
34 //-------------------------------------------
35 public class OrcCharacter: MyCharacter
36 {
37 public override void SayGreeting()
38 {
39        Debug.Log ("Hello, I'm an Orc");
40 }
41 }
42 //-------------------------------------------

With this code, some improvement is made, that is, different classes are created for each NPC type, namely, ManCharacter, WomanCharacter, and OrcCharacter. Each offers a different greeting in the SayGreeting function. Further, each NPC inherits all the common behaviors from the shared base class MyCharacter. However, a technical problem regarding type specificity arises. Now, imagine creating a tavern location inside which there are many NPCs of the different types defined, so far, all enjoying a tankard of grog. As the player enters the tavern, all NPCs should offer their unique greeting. To achieve this functionality, it'd be great if we could have a single array of all NPCs and simply call their SayGreeting function from a loop, each offering their own greeting. However, it seems, initially, that we cannot do this. This is because all elements in a single array must be of the same data type, such as MyCharacter[] or OrcCharacter[]. We cannot mix types for the same array. We could, of course, declare multiple arrays for each NPC type, but this feels awkward and doesn't easily allow for the seamless creation of more NPC types after the array code has been written. To solve this problem, we'll need a specific and dedicated solution. This is where polymorphism comes to the rescue. Refer to the following sample 1-14, which defines a new Tavern class in a completely separate script file:

01 using UnityEngine;
02 using System.Collections;
03 
04 public class Tavern : MonoBehaviour 
05 {
06 //Array of NPCs in tavern
07 public MyCharacter[] Characters = null;
08 //-------------------------------------------------------
09 // Use this for initialization
10 void Start () {
11 
12       //New array - 5 NPCs in tavern
13       Characters = new MyCharacter[5];
14 
15        //Add characters of different types to array MyCharacter
16        Characters[0] = new ManCharacter();
17        Characters[1] = new WomanCharacter();
18        Characters[2] = new OrcCharacter();
19        Characters[3] = new ManCharacter();
20        Characters[4] = new WomanCharacter();
21 
22        //Now run enter tavern functionality
23        EnterTavern();
24 }
25 //-------------------------------------------------------
26 //Function when player enters Tavern
27 public void EnterTavern()
28 {
29       //Everybody say greeting
30       foreach(MyCharacter C in Characters)
31       {
32              //call SayGreeting in derived class
33              //Derived class is accessible via base class
34             C.SayGreeting();
35       }
36 }
37 //-------------------------------------------------------
38 }

The following are the comments for code sample 1-14:

  • Line 07: To keep track of all NPCs in the tavern, regardless of the NPC type, a single array (Characters) of type MyCharacter is declared.

  • Lines 16-20: The Characters array is populated with multiple NPCs of different types. This works because, though they are of different types, each NPC derives from the same base class.

  • Line 27: The EnterTavern function is called at level startup.

  • Line 34: A foreach loop cycles through all NPCs in the Characters array, calling the SayGreeting function. The result is shown in the following screenshot. The unique messages for each NPC are printed instead of the generic message defined in the base class. Polymorphism allows the overridden method in the derived classes to be called instead.

    Polymorphism produces a backwards transparency between data types that share a common lineage

Tip

More information on polymorphism in C# can be found at http://msdn.microsoft.com/en-GB/library/ms173152.aspx.