Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Confusion with how to use classes and interfaces

Discussion in 'General Discussion' started by MapuHoB, Feb 24, 2015.

  1. MapuHoB

    MapuHoB

    Joined:
    Aug 17, 2014
    Posts:
    50
    Okay guys, I've been used to XNA and in general totally OOP(Tiger:Cat:Reptile:Animal) way of programming. I came here to unity and got totally confused! First I started just adding scripts named "DoSomething" to the separate objects but at times I felt this wasn't the best solution, so I started getting a back to the OOP approach with much inheritance, overriding and so on. Then I realized again that at times it's much easier and not only just to attach a simple script to a gameObject and get done with it. Finally I realized that I'm scripting both of the ways.Then I got totally confused.

    Question: How should I combine these two approcahes? When should I use one of them and when the other? Should I totally avoid one of them(guess not)? Also how can I get the best out of interfaces?
     
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    The typical approach in Unity is component bases architecture. Google "composition over inheritance" for a general discussion on the topic.

    For example on each entity gameobject I might have a component for a Weapon, a Steering, an Engine and a AI.

    I then use inheritance to further differentiate the components. Say Cannon, Unarmed and MachineGun all inherit from weapon. UserInput, AgressiveNPC and AllyNPC all inherit from AI. And so on.

    This is not the only way to do it, but its generally the easiest I've found, both in terms of flexibility, and in working the way Unity is naturally designed.
     
  3. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    You can still use your own custom interfaces in Unity. In my current game project I have an IInteractive interface and some game objects implement that. For example, when a collision occurs I use GetComponent to get the IInteractive implementation of the other object as oInteractive. If oInteractive does not exist (not supported by the other game object) nothing more needs to be done. Otherwise I call oInteractive.Interact passing in information about this object/interaction. Standard stuff really just saying you can still do this kind of thing.

    Not sure of the overhead of Unity's GetComponent but it works fine for my needs and using interfaces greatly simplifies things so I will continue this pattern until I run into a problem. I don't add multiple scripts to my GameObjects. One class per object type. I am likely in the minority on that but it is what I prefer. That doesn't mean I won't embed individual behaviors inside that single script with a SomeBehavior oSomeBehavior = new SomeBehavior () style. Never did care for the Animal : Dog : Fido inheritance approach. I think it is one of those things that sounds good looks good on paper but can bite you in the arse in practice causing a need for additional refactoring. I am more concerned with behaviors of an object what it can do than classifying what it is and tracking genealogy.
     
    MapuHoB and Kiwasi like this.
  4. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    I used BoredMormon's method almost exactly. I put the basic architecture in a class, then any object needing that functionality I attach that component to the object. If it needs further customization I inherit the base class with a new thing. For example I have a BaseAI class that's totally usable on its own, but I also have another class called DroneAI that inherits from BaseAI, so it's the same component really, but with extra stuff.
     
  5. Samuel411

    Samuel411

    Joined:
    Dec 20, 2012
    Posts:
    646
    BoredMormon's approach is pretty much the same that I use. It allows you to keep your scripts/code nice and organized while also keeping it simple.
     
  6. R-Lindsay

    R-Lindsay

    Joined:
    Aug 9, 2014
    Posts:
    287
    To get the most out of a language feature (like interfaces) you need to understand them. This comes from reading about what they are and trying to apply them when appropriate. As you experiment when them the idea will start to solidify in your mind and it will become easier to spot when they are needed in future.

    Here is the MSDN tutorial on them.

    Also I suggest you work through Unitys Intermediate Scripting Tutorials. Here is the link for Interfaces. If it's too confusing, start at the beginning of the tutorial series. And watch it several times.
     
  7. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    That's good. They're different tools for different jobs, and should be used as such.

    An interface guarantees that a class provides some specific data or behavior, without caring how it is provided. A good use case for this is, for instance, if you've got a bunch of different classes that all need to be able to take damage, but deal with it in their own way. So you could have a Car, a Character and a Weapon all implement IDamageable. If an explosion happens it can look through nearby GameObjects for Components that implement IDamageable and call ApplyDamage(...) on them without having to know about every possible class that could take damage (Car, Character, and Weapon) individually.

    Inheritance specifies that one class is a more specialized version of another, and typically adds either data or behaviour that supports that specialization. @BoredMormon's example of a Weapon is great for this - Swords and Guns can both attack, but they probably have different functionality in their Attack(...) methods, and they probably need different data to do their things.

    Combining both examples, if Weapon implements IDamageable then all weapons provide an interface to get damaged.
     
    MapuHoB likes this.
  8. rakkarage

    rakkarage

    Joined:
    Feb 3, 2014
    Posts:
    683
  9. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    We have MANY different player abilities in our game, and multiple developers designing them. We use interfaces coupled with inheritance for abilities, and object abilities use to make sure that they'll always work together. The projectiles need information like damage, owner, direction, etc, and the abilities need methods to interface with those members. So, the interface enforces that each projectiles has all its members. This allows me to develop and ability that interacts with a projectile someone else developed without needing to worry about whether it will work or not. I know the projectile has to have the methods I'm calling due to the IProjectile interface we wrote.

    Hope that makes sense. The thing that really lost me on interfaces for a long time was that I expected them to do much more. Like, there must be a greater purpose. As soon as you think, "Nope, these are literally just contracts that won't let me compile unless whatever implementing this interface has declared the needed methods and members", you'll understand their purpose.
     
    MapuHoB, angrypenguin and Kiwasi like this.
  10. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    That and you can use them to store or operate on groups of otherwise disparate objects. And they can help with minimizing class dependencies.
     
    GarBenjamin likes this.
  11. MapuHoB

    MapuHoB

    Joined:
    Aug 17, 2014
    Posts:
    50
    Thanks guys! Btw in my current project things got very messy recently, from trying this and that. Finally I ended up using not a single interface(smth I'm disguisted of). I always read about how important they are, so as helpful. Still I can't seem to manage to include them in the project. I've done some of the basics, I know (roughly) how they work what they are used for but can't come up with any ideas of how to use them on a bigger scale. Any advices? I really, really want to change my approach, cause I already see that things are not as good as they used to be, when the project got a bit bigger(for me). So should I leave the projects for a copuple of days and start creating some simple, very small projects in order to get used to using more interfaces? If yes, what would you recommend me to do in the beginning(I mean smth that I can grasp the idea of interfaces more easily)?
     
  12. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    Honestly? Carry on as you are. When you run into problems look for ways to improve them. Sometimes, those improvements will involve interfaces.

    Don't use any tool just for the sake of using it. Use it where it solves a problem or helps you be more productive.

    Aside from that, you could give a few examples of where you were using them and how you're doing the same thing now, and we could give you feedback. Specifics can be good.
     
    Kiwasi likes this.
  13. MapuHoB

    MapuHoB

    Joined:
    Aug 17, 2014
    Posts:
    50
    I would liek to send you the whole project, so you give me more thorough examples of what I should change and what not good bad practices, but for now I can send you just the scripts that I've written for the project to run. Although this is going to be very confusing(not because they are just scripts but because I'm newbie and probably have written tons of useless code that woud not be much understandable even when having the whole project). Anyway I think I can send you the scripts here, so that you know better what I'm talking about?


    https://www.dropbox.com/s/3egrlp8q6wsufb9/Scripts.rar?dl=0 (please don't laugh :d)
     
    Last edited: Feb 25, 2015
  14. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    To expand on this... one of my biggest leaps forward in productivity was accepting that what I'm doing right now doesn't have to be perfect. It just has to work well enough that I can finish the project. After that, I can identify opportunities for improvement and/or "pain points", and work on doing better in those areas with my next project.

    In other words, I stopped fixing every perceived flaw and instead started getting things finished "well enough". Then I'd analyse it before starting my next thing, so that I can make decisions about what to do differently based on solving real problems, rather than chasing an ideal that doesn't really exist.

    Don't get hung up on being perfect now. Concentrate on being better tomorrow.
     
  15. minionnz

    minionnz

    Joined:
    Jan 29, 2013
    Posts:
    391
    You'll figure out why you need interfaces when you finally need them :) You don't always use interfaces, I've written plenty of apps without them.
    Be careful not to overthink/overengineer up front. You can always add interfaces/base classes in later if you need them - but adding them up front and then trying to take them out later could end up being a lot more work.

    Edit: Looks like angrypenguin got a comment in before me.. I agree 100%, pretty much sums up what I meant to say.
     
    GarBenjamin likes this.
  16. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    I'm surprised I did it, but took a look at some of your files. I think your major issue is really just file organisation. Like, you don't have too many scripts. That's the nature of C# and Java and the like. You just end up with a fricken tooooon of scripts. In fact, I'd say this is a good thing. The more modular you keep your logic the more re-usable it's going to be. Just reorganize you file hierarchy to be more manageable and carry on about your business. I see nothing wrong with what you've done.

    This is a great point too. Don't assume you NEED interfaces just because people say they're useful. It's a convenience tool. You're causing more stress and headache trying to use a tool than you likely would just not using it at all, haha. In our game we implement like... maybe 3 interfaces, and even then they're really basic stuff. Some projects might have a lot of interacting code that needs "contracts" ensuring they're used correctly, other won't. No worries man. Code your game, have fun. :) Someday you'll find yourself thinking, "Oh man, I could use an interface for this" at which point you should use an interface for that.

    EDIT: Turns out three of us are trying to say the exact same thing at the exact same time (and I'm clearly the slowest). I'm sure the point is made now, haha. Dead horse == flogged.
     
    MapuHoB and angrypenguin like this.
  17. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    ooooooh, I smell a quote!
     
  18. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    Do quotes smell nice?
     
  19. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    I'll be damned. They smell fantastic.
     
    angrypenguin likes this.
  20. andymads

    andymads

    Joined:
    Jun 16, 2011
    Posts:
    1,614
    Yes!
     
  21. MapuHoB

    MapuHoB

    Joined:
    Aug 17, 2014
    Posts:
    50
    Thanks, really, really thanks! I deep down knew that I just should carry on without worrying that much and that in the course of time I'll learn eventually how to structure the projects better and avoid some mistakes but obviously got into a loop where I just looped and looped through the same things over and over again until I stopped writing code and just started thinking too much. I really appreciate all your answers!

    I just think about one thing that might be more essential for now, although the code is still not very much but enough for me to get lost at times. Yesterday I started learning TDD with unity test tools(seems like a great extension, unless there's a better customized one for unity). Should I spend some time to learn it? Is it going to boost my productivity? Last few days I've spent only on debugging(by last few days I mean 6- 7). I have no problem with fixing bugs but of course like anybody else I'd like to spend a bit more time on the actual developement of the game. I read that some people say with TDD you can reduce up to 2 or 3 times your time spent on debugging and more on adding new features and so on.
     
    angrypenguin likes this.
  22. minionnz

    minionnz

    Joined:
    Jan 29, 2013
    Posts:
    391
    Testing your code in general is a great idea. It not only ensures that code functions as expected, it also gives you the confidence to change things without breaking something else. If a test fails, there's a reason.

    I don't use TDD, though tried it for a while. I stopped because it doesn't really mix with my general development habits and team. It's a great idea though, it encourages you to implement just enough to get the job done (and no more) and should definitely save time as long as you stick with it. There are people that swear by it, so you'll find a lot of support for any questions you have.

    That being said, you can write good code without TDD. Sure, it's not guaranteed like TDD is, but it's possible with the right amount of discipline and experience.
    Also be careful you don't get too caught up in patterns or methodologies. They're great guidelines, but they are definitely not rules - and they don't all apply to every project.
     
    angrypenguin and MapuHoB like this.
  23. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    TDD isn't guaranteed either. :p But I think people understand your point.

    TDD is something that should be saved for large teams, or teams with a lot of time. It's a super slow workflow, but the benefits outway the cons. For small projects though, and especially with Unity, TDD is difficult and generally not going to save you any time.

    That being said, I freaking love TDD, and wish Unity supported unit testing and such a little better. I read a unity blog that explained why it doesn't mix well and I totally get that, so all good. Just... do want.

    If I were you I would implement testing on a need basis. I've done this in the past with games. Lots of stuff can be visually tested over iterations and that's completely legit. Sometimes though you find a corner case that hard to get to in game and just makes more sent to write a test for it. For our current game we're working on we kept everything so modular that we can actually play individual segments from anywhere. So, I set up a blank scene and a game handler that let me click and drag my components/prefabs into a see and I can the toy with them during runtime without having to wade through the rest of my game. Like, balancing boss fights is as simple as clicking and dragging that boss component (which is a prefab with a script that handles that sequence of the level, as well as all assets needed that sequence like the boss) and playing the game. It just loads up that boss fight immediately and we can play it without wading through menues or playing through the entire level every time.

    Oh and we use zero TDD. :)
     
  24. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I scanned a couple of your scripts. This is by no means a proper critique, I didn't read enough to get a decent context.
    • I found a lot of static. Static is not always bad. But I stumbled across it a lot.
    • I found a lot of string comparisons. These are easy to get wrong and leave you with hard to spot bugs.
    • I found multiple functions with the exact same functionality. As in taking the same parameter, performing the same calculation and returning the same result. Just different names. This will give you problems with maintainability.
    • I found a lot of data had coded into the scripts. Generally for large clumps of data its better to load from an external file. This makes it easier to maintain the data, and to keep the data and code separate.
    My QC guy would be the first to tell me I didn't look at enough scripts to draw any meaningful conclusions. And my inner engineer cringes at commenting on a system without understanding how its meant to work or fit together. But hey, this is the internet. Make what you will of it.
     
    NotaNaN, jtsmith1287, Ryiah and 2 others like this.
  25. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    @jtsmith1287, some of the teams at work use TDD and I wouldn't say it's slower or necessarily best for larger teams. In fact, one project where it's in use currently only has a single coder, and it's working really well there. Yes, its a bit slower up front as the tests have to be made, but it forces the developer to think through more up front (a good thing!) and my gut feel is that it's saving far more time than it's costing, by virtue of more bugs showing up faster and more clearly. And when more developers move to that project there'll be benefits there, because they'll be able to see what is and isn't tested really easily on top of the other benefits.

    Plus, it looks like it's fun to see all the green ticks pop up from the testing system.

    Still, probably not something I'd recommend for early projects, solely because there's already plenty to learn and I assume you'd want to be super fluent in something before writing up-front tests in it.
     
  26. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    Right this was my point, whether I explained it well or not. I should have said small projects, not small teams. If it's a project that's supposed to take 6 months, TDD is going to cost more time than you'll save. But if you're coding for WoW, TDD is going to be an absolute must.

    Oh it so is though.
     
  27. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    My example of the one coder project at work is an under-six-month project.
     
  28. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    Well, since my point is really just saying to not use TDD, we'll chalk that one up as him just being good at what he does, and your point earlier about learning too many things at once can be the key element. :)
     
    angrypenguin likes this.
  29. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    There is no doubt that TDD using the formal routes of a Unit Test add on definitely adds a good amount of scope to any project. I don't think I'd agree with it being better for small projects or better for big projects. In my experience the additional time required and complexity added scales right along with the project size. In general, the smaller the project the less unit tests need to be written and the bigger and more involved the project is the greater the number of unit tests that need to be written.

    At one point our team was very interested in exploring formal TDD with Unit Tests and Ninject. We abandoned it within a month because it slowed down development to such a degree it was crazy. I went back to my "old way". I've always written little functions to test certain bits of code thoroughly. Often during developmental design and nearly always during debugging. I think we probably all do that to a degree. This approach provides a lot of value. But the movement to formalize it kind of broke it somehow. Seems to have taken it from a lean and mean practice and turned it into a bloated monster. Maybe it is just people becoming obsessed writing way more tests than are needed. Maybe it is the way the formalized testing systems approach it.

    TLDR: TDD itself is a completely natural way of working. Taking the formal approach that has become all the rage in recent years is not.
     
  30. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    It sounds like you're talking about standard unit testing, and TDD. They're different. Standard unit testing can be anything from writing methods and then testing later, or writing methods and writing the tests immediately after, or whatever. TDD is when you write the unit test first. And then you write the method to return the value described in the test. I suppose I should have made sure that clarification was vocalized as it is 100% what I was basing my opinions on.

    You're right that the extra time scales by the project, but regardless, it's a lot of extra time. Not to mention the fact that you can logically maintain a true TDD with Unity due to MonoBehaviour and all that blah blah. There's a Unity blog about it somewhere stating why it can't be unit tested. Anyway. :)
     
  31. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    Yes I am all for TDD but not for the Unit Testing at least not the way it is currently implemented. But to me TDD is more generic. I see that as simply writing test code first whether using unit tests or not. And by unit tests I mean formal Unit Testing frameworks. TDD is very useful and I think most of us (at least experienced devs) do it quite often just naturally. It is when people try to nail this stuff into such specifics that things kind of fall apart. Like I may have several differrnt methods to test something. I could even set up a test environment visually in Unity for example and observe the result of the test. I guess I prefer a more agile approach (there we go again another generic word turned into a buzzword). It sometimes make it difficult to communicate effectively about this stuff because some idiot continually takes common terminology and applies it to a specific method or approach! Lol
     
  32. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    From wikipedia: "Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: first the developer writes an (initially failing) automated test case that defines a desired improvement or new function, then produces the minimum amount of code to pass that test, and finally refactors the new code to acceptable standards. Kent Beck, who is credited with having developed or 'rediscovered'[1] the technique, stated in 2003 that TDD encourages simple designs and inspires confidence."

    I only post that to point out that when referring to TDD, you're referring to a very specific thing. Definitely test your code. That's a must. But do it in a way that works for you, I say. Avoid TDD with Unity.
     
  33. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    We agree on the latter. Actually of course I also agree on the former of what the term TDD has been officially defined to mean. Just saying personally to me that is not what it means. In the eyes of academia I would be wrong of course and I am fine with that because in my eyes they are wrong. Lol

    Bottom line is just as you stated: it adds a lot of extra time and avoid it in Unity.
     
    jtsmith1287 likes this.
  34. MapuHoB

    MapuHoB

    Joined:
    Aug 17, 2014
    Posts:
    50
    What do you use for testing, if you use anything specific? What would you suggest(good compatability with unity) to me to try if I want to check out what's like to write tests? Probably too abstract question but will give it a try. Is it worth it using any like Unity test tools? If yes what would you recommend me to try? Or if such extensions aren't, at least for now, very compatable with unity scriping, any good approaches towards testing?
     
  35. RichardKain

    RichardKain

    Joined:
    Oct 1, 2012
    Posts:
    1,261
    I ran into a similar quandary recently. I was faced with a situation where I needed to use a more classic inheritance approach as opposed to pure component architecture. Thankfully, Unity doesn't stop you from doing this, even if it isn't necessarily built around the approach.

    I attempted to use an interface initially. What I really needed was a means of identifying when a certain component was of a particular, common type. I had three or four components that needed to be identified via script as coming from the same group. I thought an interface would be a low-impact means of achieving this.

    In practice, I found that Unity doesn't really have much in the way of detecting interfaces. It's designed around components, and all of it's tools are meant for locating and sifting through components. And interfaces don't qualify as components. (since the MonoBehaviour script that is the core of Unity components is a class and not an interface) So instead I attempted a little basic inheritance with a base MonoBehavior instead. That did the trick.

    Of course, then I ran into another snag. While creating a base MonoBehavior, and extending it out into sub-classes worked great, I did not want the base class to actually be visible. I was able to bundle up some of the root functionality into the base class, but all of the user-facing settings were located in the sub-classes. I didn't want the user to actually be able to use or apply the base class itself. The solution turned out to be easier than I had anticipated.

    Code (csharp):
    1. [AddComponentMenu("")]
    If you tack this little gem on before your class definition, it will hide that particular class in the usual component selector menu. Oddly enough, you can't pass this function a "null" value or a string.Empty value, it will choke if you do. It has to be an empty set of double quotes. This same snippet can be used to customize how your scripts show up in the component script-selector menu, and is fantastic for cleaning up the presentation of custom tools. Very useful all around.
     
    Kiwasi likes this.
  36. tswalk

    tswalk

    Joined:
    Jul 27, 2013
    Posts:
    1,109
    I was going to say, use an Attribute... cause you can define your own and be able to easily identify child type from it's base pretty quickly.
     
  37. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    This is what I do not saying it is the best way but is best for me out of what I have tried. Basically I just do my own thing which may include borrowing a bit from here and a tad from over there to get what I want.

    I create a test scenario basically one or more use cases. When any work is done potential impact is identified and tracked. The desired outcome (expected behavior) is noted. The actual test case may be via a GUI, purely in code via method calls or whatever. At first run of course nothing happens. The update is made. The testing scenario is performed. Update iterations occur as needed until the testing scenario is passed. Then using the other areas of the system identified early in the potential impact analysis those test scenarios (which would have been created previously when those pieces of functionality were created) are also performed. This latter part is the regression testing. Very important. Again I like things informal and lean and mean. If possible the testing scenarios are automated into dedicated testing classes but not always. In Unity it simply a matter of using Debug.Log to document the results. Basically I do as little as is needed to check my updates. For a purely local update this can be as simple as hitting Play and observing the results.

    I am sure there are people here who use very formalized testing methods, writing Unit Tests and so forth. Just a matter of them finding your post so they can share what they use. You may want to check the Asset Store. It is possible there is some Unit Testing or other testing framework available.
     
    Last edited: Feb 26, 2015
    MapuHoB likes this.