Polymorphism on member attribute
This issue has been difficult for me to search, largely because the keywords bring up similar, but not exactly the same scenarios.
.
Basically what I'm trying to do is have a single GameManager
class with a list of Player objects, but each class that inherits from GameManager
will have some child of Player
as well. How can I construct an array in GameManager
to reduce or eliminate the amount of casting necessary on the list in a GameManager
child.
.
Here's an example. The scene containing GameManagerChild
is guaranteed to only contain PlayerChild objects.
.
public class GameManager : MonoBehavior
{
protected Player[] _players;
protected void Start()
{
InitializePlayers();
}
protected void InitializePlayers()
{
_players = FindObjectsOfType(typeof(Player)) as Player[];
}
}
public class GameManagerChild : GameManager
{
void Update()
{
DoSomethingWithPlayers();
}
void DoSomethingWithPlayers()
{
foreach (PlayerChild player in _players)
{
player.SomeMethodSpecificToPlayerChild();
}
}
}
.
One solution could be to make InitializePlayers
abstract and each child of GameManager
would need to populate the list with appropriate children of Player
, but this would still require casting each time we want to act on an item in _player from a GameManager
child.
.
Any better design suggestions?
I don't quite understand the usage of your classes here. Isn't a Game$$anonymous$$anager meant to be a singleton? Why do you derive other classes from this class?
@Bunny83, the game is actually a series of $$anonymous$$igames, so each game will have entirely different mechanics, but contain similar actions at their core. e.g. each game has a set of players, a win condition, the ability to exit to the game selection screen, etc
The only singleton currently is a GameControls$$anonymous$$anager singleton which keep controls for each player universal between the scenes.
Answer by Bunny83 · Mar 22, 2018 at 02:40 AM
I'm not sure what's the point of all this. Maybe you should choose a better / more descriptive name of your class. Does your class really "mangage the game"? If not you should use a different name.
However from your description you may want to do something like this:
public class GameManager<TItemType> : MonoBehavior where TItemType : Player
{
protected TItemType[] _players;
protected void Start()
{
InitializePlayers();
}
protected void InitializePlayers()
{
_players = FindObjectsOfType<TItemType>();
}
}
public class GameManagerChild : GameManager<PlayerChild>
{
void Update()
{
DoSomethingWithPlayers();
}
void DoSomethingWithPlayers()
{
foreach (PlayerChild player in _players)
{
player.SomeMethodSpecificToPlayerChild();
}
}
}
Note that you can't attach a "GameManager" to a gameobject as generic classes are not supported. However derived concrete classes do work just fine. So "GameManagerChild" can be attached to a gameobject.
I believe the Game$$anonymous$$anager is appropriately named. The classes I included in the example are stripped-down versions to focus entirely on the question, so its understandable that the intention isn't clear.
The Game$$anonymous$$anagers be made to manage the scene, players, and win conditions of each $$anonymous$$igame. Basically the whole flow of the game and high-level interactions between the objects.
I think the construction above would work. I'm still picking up C#, so I'll need to read up on Generic vs. Derived Concrete Classes, since at first glance this just looks like a Generic class to me, but I think I see the distinction.
I guess TItemType is just a common na$$anonymous$$g convention for these constructs? Still trying to find a clear answer through google.
This worked for what we needed. Appreciate the comments on the design. I'll keep thinking this over.