Right… Since each GuiFactory will need to work on a ship, but not the same ship, they need to have something in common. In this case, I choose the word “Ship” to represent a base class that all types of ships would inherit from. Of course, you could just as easily forgo the base class since all classes implicitly inherit from object…
So to your question…
public GUIElement CreateHitPointView(Ship ship)
{
return CreateHitPointView(ship as TerranDestroyer);
}
When the GUI Manager receives a GuiFactory, it doesn’t know what kind of factory it is and we want to make sure the same code can be used regardless what factory and what ship we happen to have. We need to make things quite generic: we know we will have a GuiFactory and we know we will have a Ship but that’s it.
So let’s take the TerranDestroyer as an example. At runtime, we will have a TerranDestroyer and a TerranDestroyerGuiFactory. Unfortunately, we didn’t know that at code time, so we just said “call a method named CreateHitPointView and pass in the ship”. In order for the TerranDestroyerGuiFactory to correctly implement this pattern, it has to accept any kind of ship. When the TerranDestroyerGuiFactory receives this message call, it will try to decide which of the two methods named CreateHitPointView should be called. Since we don’t know what type of ship we have, we end up in the generic method, the one above.
In this generic method, I now cast the generic ship into a specific type - namely TerranDestroyer. I then call CreateHitPointView again but with a different kind of ship - the specific one. After this call I will always end up in the specific version of CreateHitPointView expecting a TerranDestroyer. If the cast was successful, then I will have a TerranDestroyer. If it was unsuccessful, then I end up with null, which is why I call Assert before doing anything.
Now that I’m reviewing this, it doesn’t do a great job of following Unity’s component architecture. Unity likes all GameObjects to be fundamentally the same but with different components attached. I really like this pattern but it’s easy to mix it up - like I just did. Here’s another approach that I think will work better with Unity:
Let’s take all the different things that make up a ship which I was trying to stuff into a class hierarchy based on Ship and make them MonoBehaviours which we will simply drop onto GameObjects.
interface ShieldSystem
{
void TakeDamage(int damage);
bool IsActive();
string Name { get; };
string Percent { get; };
}
class KineticShields : MonoBehaviour, ShieldSystem
{
// Some public fields to show up in the editor
public readonly int maxShields;
public readonly string name;
int power = maxShields;
public void TakeDamage(int damage)
{
power -= damage;
}
public bool IsActive()
{
return power > 0;
}
public string Name
{ get { return name; } }
public string Percent
{ get { return (power / maxShields).ToString(); } }
}
Now our GUI code can be quite a bit simpler because we don’t need different factories for each type of ship, though we may still want to use that design pattern for different reasons - maybe a different GUI when multiple ships are selected.
When a ship is selected, we should just pass the whole GameObject to the GuiFactory. Each method can grab the components it is interested in.
class GuiFactory
{
GUIElement CreateHitPointView(GameObject ship)
{
var uiElement = UnityEngine.Object.Instantiate<GUIText>(TextPrefab);
foreach (var shield in ship.GetComponentsInChildren<ShieldSystem>())
uiElement.text += string.Format("Shield System {0} at {1}%", shield.Name, shield.Percent);
return uiElement;
}
}