Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by generic_user_101 · Aug 30, 2018 at 09:12 PM · inheritancemethodsabstract

Multiple Methods with different logic

Hello,

I am creating a roguelike where monsters are spawned, all from a Monster class. Monsters essentially all have the same attributes and methods. However, I would like to change the logic inside the methods themselves to be tailored for specific species: for example, a troll might have a strong preference for melee attacks, while an imp would prefer ranged abilities. Both monsters would call an Attack method, which take the same arguments and also return the same outputs, however their internal logic would be different.

Ex:

 class Monster
 {
      AttackType Attack(Character targetChar)
     {
             // Troll will do one thing, while Imp will do another
             // Different logic to determine what each monster species will choose as an attack
            // Two examples of what might be returned:
             return meleeAttack(targetChar, damage);
           //or
            return rangedAttack(targetChar, damage);
     }
 
 
 }

I have been considering just inheriting from the Monster class (which would be abstract in this case) and overriding the methods which I would define as abstract. However, I was wondering if there is a better way to maybe approach this kind of problem, since I would probably have a few methods inside of Monster that I would like to keep private, i.e. inaccessible to other . I have also been looking at using the delegate function parameter, it seems to be sort of what I am looking for.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by JVene · Aug 31, 2018 at 08:31 PM

The classic example is the abstract class with overrides for unique behaviors. Yet, the situation presented in Unity doesn't fit 100%. In the classic example there is a common, neutral base class from which derived classes provide unique behaviors. The storage of these objects is the base class, which is to say that code using this class does not know (and shouldn't have to know) what the derived type actually is. Code using such objects rely upon the virtual behavior defined by abstract functions to handle mutation of the behavior.


In Unity, however, these classes are usually components attached to a GameObject. For those to instantiate correctly, the framework creates them, and therefore must know the derived type. It doesn't work easily to limit Unity's framework to only knowledge of the base type. If I assumed 'monster' is the base, while 'troll' and 'imp' are derived from 'monster', the objects you attach these scripts to must select an 'imp' or a 'troll'. They can't instantiate a 'monster' because it is an abstract class, and there is no factory easily accessible (that I've seen) for the framework to instantiate.


This isn't a problem, you can instantiate trolls and imps without issue. My point is that the design does not 100% fit into the entire model of abstract base classes, and my summary message by detailing this observation is that, as your post hints, it may be that an abstract base class, the classic design example, has a better alternative for the situation presented in Unity.


Your thought about delegates is exactly on point in this line of thinking. Delegates have lots of potential uses, but among them is to mutate the behavior of a class similar to that of abstract base classes, but it can work better in the kind of scenario presented by Unity, where the class is applied as a component from the viewpoint of the derived object, not the base object.


Put another way, virtual functions (a C++ term) or abstract functions (the C# name for the same thing) are, under the hood, implemented as pointers to functions (or methods as C# names them). Virtual (or abstract) base classes are fashioned with an "internal" or "invisible" table of function pointers which are assigned when the derived object is configured. You can do nearly the same thing with delegates, without having to create abstract classes (in a system like Unity where they are not as easily or natively supported).


When using delegates for this design, you'd write your code to call methods using variables declared as delegates which are configured during initialization so that the class behaves in a fashion fairly identical to that expected of a virtual descendent (the derived class that overrides abstract methods in C#). The missing part, however, is the fact that a derived class can introduce new and unique member variables and methods applicable only to that derivative, so the result isn't quite as organized and clean when those differences are complex.


Therein comes a determining factor. If the differences between your monsters are not large, and do not involve significant unique member variables, the delegate oriented approach may do quite well and offer some net gain because Unity's design doesn't quite lend itself to abstract base components perfectly. On the other hand, if the differences between monsters is vast, and there are a considerable number of methods and member variables applicable only to certain types of monsters, you may need to consider a different design, possibly including the abstract base.


Another alternative, however, is to consider Unity's own use of components, and mimic that. You could establish a central monster class which is configured by attaching behavioral component classes which ultimately configure the unique behaviors defining each character. This can be quite flexible, bypasses those issue about abstract bases and does organize code well. It is also a bit more complicated, and you'll end up with a puzzle about where methods do work (the components may often have to operate by method calls from the owning Update function, but are operating in a scope that doesn't have access to the underlying MonoBehaviour class, and thus need a reference to it, or will be calling back to the MonoBehviour class for some certain work (like access to the gameObject or transform members).

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by LeeJBaxter · Aug 31, 2018 at 07:32 AM

I think your best bet would be to use an abstract class as you've considered. You can still have private methods in your abstract class, but you can also have protected methods that are accessible to the derived class but inaccessible to other classes.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by generic_user_101 · Sep 01, 2018 at 07:40 PM

Thank you very much for the well thought out answer, I didn't expect to get something like that!

I think I will initially try to approach this problem with abstract classes, the reason being that it seems easier to implement initially (I would describe myself as an intermediate coder) The other reason is that because my game is turn based and using TileMaps, I am not asking for real-time performance, my key goal is to write well organized component managers that provide a solid interface for each system in my game to communicate with each other, ex: Dungeon Map Manager, Monster Manager, Player Manager). I am teaching myself how to set up event systems for that very reason, and I think a lot of my child classes will be inheriting a lot of boiler plate code.

I will be reading up more about delegates, they seem incredibly useful, and I might still change my mind, since right now the actual player/monster system is still being planned out on paper, and not code :).

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

92 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How should I structure my unit class relationships? 1 Answer

C# unity custom editor multiple different components but same base class 2 Answers

Abstract Class - Monobehaviour Functions 0 Answers

Differentiating between inherited methods with inherited classes 2 Answers

List of Inherited abstract Objects assigned via Inspector 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges