Learn C# Inheritance With Interfaces, Abstract Classes, & Virtual Methods

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everybody Darren here with Renaissance coders thanks for joining us for another c-sharp tutorial series today we're going to be talking about inheritance well inheritance is actually pretty easy to understand conceptually if you think about a family structure we have a parent with some children and their children can have children and we find the same relationship with inheritance programming so simply put programmatically speaking inheritance is a pattern it's a way of organizing your code and it doesn't necessarily make your program run faster but it does organize instructions and requirements it abstracts the complexities of classes it enables method and member sharing between classes it allows method overriding between classes and finally but not least it allows for the substitution of logic and functionality in classes where we may not exactly understand what's going on within the details of that class but we're still able to write processing logic into it so at first glance it may still be unclear as to why any of this is important but we're going to dive into an example in unity3d to understand the power of inheritance and why it is so useful so we're going to be using unity3d since my background is in that engine so if you're not coming from a games background that's okay you can still certainly benefit from understanding what inheritances so let's go ahead and get into the details of this project so we have two classes in front of us we have ogre on the left and undead on the right and the truth about these two classes is that they do the exact same thing you'll notice at the top of the right in our class definition we have enemy on the right hand side of the colon instead of monobehaviour this indicates that enemy probably has a lot of the same logic that ogre does and since I'm inheriting with Undead I don't need to write nearly as much code to implement the same thing that ogre does so I'd like to go back to unity and show you that these two classes are going to implement the same exact behavior so in unity we have Undead which has the undead component and we have ogre which has the ogre component and when I run this they're going to Patrol and when they see each other they're going to run to each other and start attacking they both have slightly different attack speeds with slightly different damage outputs so one of them is going to kill the other first and when the when the last one standing kills the opponent he'll start patrolling around well now that we've shown that we should take a look at what is actually happening with the enemy class so we can see that enemy is actually almost a direct copy of ocher now the reason I did this was because I just wanted to show how easy it would be to modify the specialization aspect of various types of enemies by using a base class and this class is simply on its own and imagine if I wanted to create another type of enemy from this class if I didn't use inheritance I would have to copy the entire class and copy the contents into another class called wizard or some other type of enemy and then we just end up with a bunch of redundant code and it's even a bigger problem because what if I later decide to modify some enemy code and that needs to be true for all enemies then I would have to go inside every enemy script and modify the same thing so with this sort of centralized approach we only need to modify the base class to modify all of the general all of the generalized functionality and logic of the subclasses now I want to talk about some generalization a little bit more if we look at our enemy class we have the eye enemy behavior implemented we can see that after the comma after monobehaviour so what this means and how this class definition reads is that we have an abstract class called enemy we'll talk about abstract a little bit later and enemy inherits mana behavior which is a unity3d engine base class or parent class an enemy also implements the eye enemy behavior interface so let's look at the eye enemy behavior interface and all it is is a list of functions and we can think of this as just a set of roles or requirements and as such anything that borrows these instructions must implement all of them in other words if my enemy class doesn't implement attack enemy as you can see down here if it doesn't implement that method the compiler is going to throw an error to show this I'm going to add a new method to my rules or my requirement list I'll call it method test method and if we go back to unity will see the error that gets thrown so back in unity we can see enemy does not implement interface member eye enemy behavior test method and this is what I was talking about unless we add that test method method to enemy that compiler is going to keep screaming at us another interesting fact about that is if I add test method in this way I'll still have an error the compiler is going to tell me that the best compatible match for test method needs to be marked as public which indicates that this needs to be a public void test method and that's the only way it'll work so this is one of the disadvantages of using interfaces but just like all design patterns in programming languages some of you might be aware of is that they come with advantages and they also come with disadvantages the advantages here are that we have a centralized approach to defining requirements for all of the classes that implement a enemy behavior and if we want to change those rules all we have to do is change them right here and none of our classes will be able to disobey those rules the downside being that we have to make the method public and that leaves it open to access from outside classes so it's up to you if you want to use this method but I thought it was worth to mention I'm going to get rid of test method in my enemy class and in my interface so earlier I mentioned that inheritance abstract the complexities of classes and you can see that here this is what I was talking about our subclass our child class is only 12 lines long and we only care about overriding one method so that's the abstraction aspect undead doesn't need to know the details of enemy and it can still implement everything that enemy does so that's the abstraction aspect and that's why inheritance is such an attractive design pattern now inheritance also enables us to share method and member variables between classes so what does that mean well if we take a look at our enemy class we have some public members and we have some protected members and then we have some private members and the public members are accessible outside of our class and of course also within our subclasses the protected variables are only accessible within our child classes okay so that's where we're sharing member variables and where we share remember where we share the functions is start update and basically all of these functions are shared except for the private ones and that's exactly how the undead component was able to work and the first part of this video when I was demoing the sort of basic AI is is because it's actually borrowing these functions now the interesting thing is that we can override these functions if we mark them with virtual or abstract and I'll show you an abstract method in just a moment now you can see over here in our undead class we are overriding find new position so let's look at what that's actually doing in our base class our base class we have that marked as virtual which again gives us the opportunity to override that in our subclasses so if you mark a method as virtual you're expecting the ability to be able to override that functionality and subclasses and so all this means is at first glance is that all of our enemies should have different movement patterns or they should have different ways of finding new positions so as a base our enemies find positions by finding a random value on the X and Z from negative 5 to 5 now that's actually direct copy of my subclass but I have the ability to change it so if I change that to say that they can only move within 4 units instead of 10 then we can go back to unity and see that my undead object only patrols within a smaller region so I'm actually going to get rid of the ogre for now so that they don't actually initiate attacks and we can see the small patrol zone of our undead guy and you won't see him go much further out than he already has so just like that we've created an enemy that has a different patrolling pattern now this gets even more interesting we have the ability to insert logic into different parts within our class our subclasses have control over that I'll show you exactly what I mean it's of course up to the way that we design our our base class which at times can be pretty tricky but let's create an example of a method that's going to be shared between all of our enemies that we create I came up with one that I thought was interesting which was a method that provided functionality for whenever an enemy got to low health so we could say public void I'm sorry public abstract void run low health behavior now if our health is low it indicates that we already have found an enemy because he's attacking us and with that we don't need to run any of this code so what I can say is if health and I remind you this is in my my base class will say if health is less than 20 I'll say it less than or equal to 20 then I want to run low health behavior and return now one thing I forgot was that abstract methods can't have contents we can't add functionality to this and if this method isn't overridden we'll get an error so as we can see in our subclass we aren't overriding run low health behavior let's go to unity and see the error that we get so we can see we get undead does not implement inherited abstract member enemy dot run low health behavior and we actually don't get that with virtual methods that's because virtual methods have potential to have logic in them while abstract methods don't and if we go back to unity or if we go back to our editor we can see that we're calling the abstract member but what if that actually wasn't if run if run low health behavior didn't have any code within it then the compiler wouldn't really know what to do and that's why we get that error because the definition of abstract functions are used with a semicolon we can't actually add direct functionality in there which is why our subclasses must add functionality to them now the other interesting thing to keep in mind here is that we're literally inserting code into our base class from our subclass which is unusual behavior and it's also very neat but again it makes designing our base classes fairly tricky so let's go ahead and go to our undead class and say public override void run low health behavior now have some ideas for this what I want to do is create a regenerate method that's going to regenerate our health over time and I also want to have a run away method this is going to give our AI completely different behavior from our ogre and I'm not even adding that much code to the subclass but it still gives us a wide range of flexibility to add different personalities to our characters so the first thing I want to do is create regenerate and then I'll create run away and these are methods that I'm not expecting to have in any of my other enemies which is why I'm keeping them localized within my undead class so regenerate is going to regenerate health over time so I need to create a health timer I also should create a float for say regen amount so how much health am I going to regenerate each time I'll set that to 5 and then we want to say how how often are we going to reach in so I'll say float regen speed we'll say that's equal 2.5 seconds so every point 5 seconds when I have low health and I'm running away my undead characters are going to regen 5 health so an regenerate what we'll say is regions region or I'm sorry health timer health timer plus equals time Delta time and I'll say if health timer is greater than region speed then health timer should be set to 0 and I'll increase my health I'll say health plus equals regen amount now I also have an image which you may have seen already above my enemy's health bar and I have that in my base class since its public I can access it I didn't want this to be protected because I needed to actually drag that image component onto this from the inspector view but I can still say over here health bar dot fill amount health bar dot fill amount equals health / Mac self so this will be a value from 0 to 1 and that's going to set my health bar so regenerate is done now run away well run away is pretty easy we can actually just come down to travel to position this method is similar and what this does is it rotates my enemy or my character to a certain position or certain orientation and then I just move my character forward on his local forward by speed and I actually want to increase the speed when he's running away by 2 now the only difference here is that I'm saying goal position minus target or transformed out position now if you know anything about vector math you'll know that getting the direction vector is attained by going from the target minus the current so target minus current position will get you a vector pointing from your current position to your target so really all I want to do is reverse this math and say to run away from my enemy I want to say transformed opposition - goal position goal position when we actually have a target when we actually have an enemy goal position is being set to the enemy's position and that's all being done within this logic that I haven't really described the logic is pretty simple in this video is mostly about inheritance but that's the way this is going to work so this will actually turn the character directly away from the enemy and this will actually move the enemy forward and he'll be moving at speed times - the reason I did speed times - is because now we can assume that since he has low health he has a bit of an adrenaline rush and he's trying to run away another run low health behavior that we might have is something like a rage behavior where his damage increases and maybe he also regenerates I don't know just an idea of the flexibility you could have with this type of inheritance setup okay now what I did as a reminder is I conducted an override on an abstract member which is literally inserting my subclass code into my base class code which is really cool it's really neat but again it is a bit of a design challenge but let's go back to unity and see how this actually works okay so here we are back in unity I wanted to make sure that I reactivate my augur and let's see how this looks so what we expect to see is gray which is the undead when his health gets certain to a certain point he's going to start running away but you'll notice that whenever his health regenerates he'll actually be able to turn around and start attacking again okay let's start this and see if it works so remember gray is Undead so he'll hopefully get to a point where he starts running away so you can see him running away stopping and attacking again so he basically has invincibility mode right now all right so that's the end of the inheritance tutorial we learned about organizing instructions with interfaces abstracting complexities we also talked about member and Method sharing between classes we talked about overriding between classes and also substituting logic and functionality from our subclass into our base class I hope you guys learned what you came here to learn I thought that this might be a cool little experiment to understand inheritance if you have any questions go ahead and leave a comment leave a like if you liked the video and I'll see you guys in the next tutorial
Info
Channel: Renaissance Coders
Views: 21,145
Rating: undefined out of 5
Keywords: learn c#, inheritance, c# protected, c# abstract, c# interface, c# virtual, c# programmer, c sharp development, c# developer, c#, unity3d, tutorial, unity engine, c# game programming, unity3d developer, unity c# programming, how to use inheritance, what is inheritance
Id: Tt8XUXAfjo8
Channel Id: undefined
Length: 19min 29sec (1169 seconds)
Published: Sun May 21 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.