Search Unity

Inheritcance with a local mutiplayer game

Discussion in 'Scripting' started by LED_Lightning, Oct 21, 2017.

  1. LED_Lightning

    LED_Lightning

    Joined:
    Oct 21, 2017
    Posts:
    4
    Hey Guys,

    I recently started developing games with Unity but I am not that new in programing itself. I have about a year experience in Java and C#.

    Now to my problem:
    I wanted to make a Local-Multiplayer game in which both player control a individual tank with
    WASD and UP DOWN LEFT RIGHT. I also created a "Tanks" class from which the two PlayerController derive.
    So far so good. The main problem is, that I want to make a Character selection in which the two player can decide what kind of tank they want to play. The then choosen tank should not have 2 scripts attached to it, one for the first player and one for the second. My problem here is that I cant find a efficient way to accomplish that task. I always end up attaching 2 scripts to each tank prefab in order to control them properly. Can you help me out? And please bare with me and my english, I´m from Germany ^-^
    forumPost.png

    Thanks :)
     
  2. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I'm not sure what's the exact problem, you could create two prefabs with a different controller setup - one that you instantiate for the first player, the other one for the second player.

    Btw, don't use the constructor of a MonoBehaviour. Behaviours (or components in general) are added by drag&drop or using AddComponent - both will invoke the parameterless contructor.
    The overloaded one will never be invoked by Unity, and invoking it yourself does not register the object properly to the internals of the engine.

    Instead, use the Awake function to initialize your behaviours. It'll get called during the instantiation of that script instance and serves as the primary self-initialization method.

    If you don't mind, I would not use inheritence for the controls. The controller is not an actual tank. Instead, I'd use more like a composition approach.
    That is, you'd have a controller class that references a controllable (for instance, a tank).

    The tank class wouldn't know anything about the Input, nor does any derived class. Instead, its methods will be called from something that issues commands.

    PS: Don't worry, your english is fine - or that's just me, as I'm German as well. :D
     
    Last edited: Oct 21, 2017
  3. LED_Lightning

    LED_Lightning

    Joined:
    Oct 21, 2017
    Posts:
    4
    If I get your point right, then you suggest me to keep my "Tanks" class which stores all the information needed for a tank in order to work(like speed, rotation and fireRate)and access the methods(move, fire etc.)from a "controller/inputs" class which then calls the methods + the parameters based on the stats the tank has.

    Because I wanted to give the player the opportunity to choose which kind of tank they want to play. For example a faster tank would´ve +5f speed but -2 mass and a heavier tank would´ve -5f but +2 mass. And if I then wanted to have a prefab for each kind of tank, I would just need to have a empty gameObject like "PlayerOne" and "PlayerTwo", attach the choosen prefab to the gameObject and control the player objects via my input class.

    I ask myself one question after all:
    How would I achieve it, that I can give the parameters (like speed and mass) to the gameObect? As I said, I´m new to the topic and aprreciate every kind of advise someone can give me.

    P.s.: Thanks for the quick response!
     
  4. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Seems like you wanna seperate this even more. Try to seperate data from the representation.
    So, when the players chooses a tank, he actually chooses a set of data (a configuration).

    Get an input configuration for the particular player and apply it to the corresponding input controller / tank controller.
    When the game starts, get a tank for that player and apply (or set) the configuration. The tank itself will always access that data object whenever commands are issued.

    So, you've got a tank class that handles incoming commands (issued by the controller) based on its given configuration like speed and so on. Of course these values could as well be part of the tank. But for each different tank, you'd then need a different prefab. That's why it's best do seperate this once more.

    The best thing about it: You can use ScriptableObjects (SOs) for that. That is, you can define as many instances of that data type as assets and exchange them simply by drag and drop. Whenever you feel like experimenting with values, there's no need to duplicate an entire prefab or remember the previous values when you change them - you'd just create another SO and throw it in via inspector and test it - once you get used to that, you'll love it. It's so neat and pretty much a must for everyone who's working on serious projects in Unity.

    Fun fact: that process of seperation can be done over and over again - of course you should stop at some point. But with a growing size and complexity of a class, you're more-likely to feel like the implementation need more flexibility and should be re-usable, so this does make a lot of sense.

    So the current idea would be:
    TankController - one class. This makes use of another type, which describes the Input - let it be TankController[Input]Configuration.

    Tank may be another type - only knows itself how it behaves, but does not know under which conditions (the controller will handle that and issue commands to the tank, for instance 'move').
    And finally - this is optional but I'd recommend it - a tank's base configuration as SO.
     
  5. LED_Lightning

    LED_Lightning

    Joined:
    Oct 21, 2017
    Posts:
    4
    First of all,
    I´m really glad that there are people who are so helpful. Thanks a lot!

    But there is still one thing that bothers me:

    Should I make a controller for each player, or should I control each player via one single controller script?

    My current setup is:
    - Tank class
    Stores information about the spawnPosition, his rigidBody and his spawnPosition. It also has some methods(move and fire, each called by my TankController class, which gets parameters like speed and rotation from the TankControllerConfiguration class(as you suggestes))
    - TankController class
    Tells the Tank class what to do (just calls methods and does the calculation stuff)
    - TankControllerConfiguration
    Tells the TankController with which "stats" he has to work. The "stats" are gained from the TankConfiguration, a SO, in which I store data for each individual prefab (should I store the prefab itself in this SO too?)
    - TankConfiguration
    Stores the data

    I hope you can help me out on that, too. And once again I´m so thankful ^-^
     
  6. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I sort of posted my idea about that earlier.
    If you handle that directly within a single script, it's already pretty much specialized to that particular situation - handling 2 players. Any change of that setup needs a change in that controller script.

    Instead, write a controller script that does its own thing based on a setup that gets injected through a setter or through the inspector. Pretty much like the SO approach for the tank's data.

    What's the benefit?
    You now have a controller that takes a configuraton - let's say the key bindings - and processes this every frame.
    Want to add a 3rd player? Just instantiate another controller - which is the same like the others, just set a different key-configuration and that's all - no code changes in these particular classes, because they're self-contained.

    Similar to that would be a single class that accepts multiple configurations and stores them in a list - one for each active player. It's mostly preference. The important idea to extract from it is, that the controller knows about a configuration it can query input information from, but does not exactly know the concrete input.

    It's a matter of preference which one you take, they'll be processed sequencially either way.
    I'd probably prefer the former, as the latter implies that you'll need arrays/lists for different entities where element X in array1 belongs to element with index X in array2...
    That's bad, so every controller should handle its own config and a controllable.

    I'd rather have the tank know about its values and wouldn't let the controller pass the values . Simple reason is that the speed is actually a property of a specific tank (a tank in this simplified scenario is specialized only by its configuration).

    Analogy to that: I cannot simply tell a car to go 250 miles / hour if it doesn't support it. That input would need proper evaluation before further execution and processing will be done.

    Instead, I'd tell it to accelerate and it handles accelerations and limits itself - which could be part of the configuration again (some kind of reference values / specs).
    The controller would tell the tank to move into a certain direction, e.g. forward, and the tank itself handles the actual movement, based on its current speed, movement, mass, whatsoever.

    Another analogy: I can't tell a ship to instant-rotate 90 degrees. Instead I'd tell it i wanna change the direction, and it'll take some time to change it based on various factors that I simply shouldn't have influence on (from the perspective of the caller, so "I" = the caller).
     
    Last edited: Oct 21, 2017
    LED_Lightning likes this.