Search code examples
c#unity-game-enginesubclass

Unity C# - Calling subclass dynamically from the base class


I'm pretty new to C# and Unity and I've trying to figure out how to handle subclasses through the base class.

I am making a card game. I've made a baseclass PlayerCard, which has subclasses such as Minion : PlayerCard.

My current structure is that PlayerCard class is instantiated like this from the deck at the start

public class PlayerDeck : MonoBehaviour{

[SerializeField] PlayerCard[] playerCardArray;

private int xPos = 2;


public void DrawCards()
{
    var cardIndex = Random.Range(0, playerCardArray.Length);
    AddCardToPlayer(playerCardArray[cardIndex]);
}

private void AddCardToPlayer(PlayerCard myCard)
{

    Vector3 cardPos = new Vector3(transform.position.x + xPos, transform.position.y, transform.position.z);
    PlayerCard newCard = Instantiate(myCard, cardPos, transform.rotation) as PlayerCard;
    xPos = xPos + 2;
}

I want my baseclass (PlayerCard) handle all mundane things such as dragging and moving the card as they will be the same for all the cards.

    private void OnMouseDown()
{
    ToggleDrag();
}

void Update()
{
    if (DraggingON) { Drag(); }
}

private void ToggleDrag()
{
    Debug.Log(playerCard);
    mouseOffset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, mouseScreenPoint.z));

    if (DraggingON)
    {
        DraggingON = false;
        SnapCardToPosition();
    }
    else
    {
        DraggingON = true;

        SnapPositionX = transform.position.x;   //Return to same x position if user has not hovered other available slot
        SnapPositionY = transform.position.y;   //Return to same y position if user has not hovered other available slot

        //Variables above will be reset to default position x/y when user has hovered a slot but then moved object away from the slot, so reset to default
        defaultPositionX = transform.position.x;
        defaultPositionY = transform.position.y;
    }
}

private void Drag()
{
    Vector3 currentMouseScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, mouseScreenPoint.z);
    Vector3 currentMousePosition = Camera.main.ScreenToWorldPoint(currentMouseScreenPoint) + mouseOffset;
    transform.position = currentMousePosition;
}

My problem lies, when SnapCardToPosition is called, which is when I want the subclass (whatever it is) to take over and handle interactions with position they were dragged into.

    private void SnapCardToPosition()
{
    Vector2 NewCardPosition = new Vector2(SnapPositionX, SnapPositionY);
    transform.position = NewCardPosition;

    //Dynamically call the subclass here?
}

So the subclass would look something like this

public class Minion : PlayerCard{
[SerializeField] int Damage = 1;


public void HandleCardPlacement()
{
    //Do something
}

I haven't figured out how this could be achieved using my structure or is it fundamentally wrong?


Solution

    • Make your method not private (= only this class can see this) but rather protected (= this and any derived class can see this)
    • And make your method either virtual (if there is a common base behavior) or abstract (if every card has to implement it from scratch) and override it in the subclass

    In your base class e.g.

    protected virtual void SnapCardToPosition()
    {
        Vector2 NewCardPosition = new Vector2(SnapPositionX, SnapPositionY);
        transform.position = NewCardPosition;
    }
    

    and then in the subclass

    protected override void SnapCardToPosition()
    {
        // make sure that the base implementation is executed first
        base.SnapCardToPosition();
    
        // do additional stuff
    }
    

    so here each subclass can decide

    • whether to override the method or simply keep he default one of the base class
    • if it overrides it can decide if and when to call the default behavior via the base.SnapCardToPosition();