unity script herencia con commands c# inheritance unity3d polymorphism

script - unity c# commands



Clase heredada con métodos que toman el tipo Child como parámetro: se llama un método incorrecto (2)

Debe reflejar la jerarquía en sus tipos: una forma es crear una interfaz y agregarle una restricción en su método Create :

public interface ICopyableFrom<T> { void CopyAttributes(T src); } public void createCard<T>(GameObject whereToPut, T objectToCopy, Player player, CardStatus cardStatus) where T : BasicCardModel, ICopyableFrom<T> { GameObject new_card = Instantiate(basicCard); new_card.transform.SetParent(whereToPut.transform, false); Destroy(new_card.GetComponent<BasicCardModel>()); new_card.AddComponent<T>(); new_card.GetComponent<T>().CopyAttributes(objectToCopy); new_card.GetComponent<T>().linkModelToCardObject(new_card); new_card.GetComponent<T>().setUpCard<T>(player, cardStatus); }

que luego debes implementar en tus clases:

public class AttackCardModel : BasicCardModel, ICopyableFrom<AttackCardModel> { public void CopyAttributes(AttackCardModel src) { } }

Estoy haciendo un juego de cartas, y tengo varias secuencias de comandos que controlan el comportamiento de la tarjeta.

public class BasicCardModel : Draggable { public int hitPoints; public GameObject cardObject; public static string cardName = "Basic Card"; public CardStatus cardStatus = CardStatus.None; public void copyAttributes(BasicCardModel bcm) { Debug.Log("Calling basic copy attributes"); hitPoints = bcm.hitPoints; } ... }

Tengo varias tarjetas especializadas similares a la siguiente:

public class AttackCardModel : BasicCardModel { public int attackStrength; public AttackType attackType; public void copyAttributes(AttackCardModel acm) { base.copyAttributes(acm); attackType = acm.attackType; Debug.Log("Attack strength = " + acm.attackStrength); attackStrength = acm.attackStrength; } }

Tengo un objeto controlador que genera estas tarjetas:

public class GameController : MonoBehaviour { public GameObject basicCard, attackCard, defenseCard, eventCard, masterCard; public GameObject topPlayerDeck, topPlayerHand, topPlayerField; public GameObject bottomPlayerDeck, bottomPlayerHand, bottomPlayerField; public GameObject eventDeck; // Use this for initialization void Start () { // Link controller to game objects topPlayerDeck = GameObject.Find("TopPlayerDeck"); topPlayerHand = GameObject.Find("TopPlayerHand"); topPlayerField = GameObject.Find("TopPlayerField"); bottomPlayerDeck = GameObject.Find("BottomPlayerDeck"); bottomPlayerHand = GameObject.Find("BottomPlayerHand"); bottomPlayerField = GameObject.Find("BottomPlayerField"); eventDeck = GameObject.Find("EventDeck"); CardCollection cards = generateCards(); foreach (BasicCardModel card in cards.cards) { if(card is AttackCardModel) { createCard<AttackCardModel>(topPlayerHand, card as AttackCardModel, Player.Top, CardStatus.Hand); createCard<AttackCardModel>(bottomPlayerHand, card as AttackCardModel, Player.Bottom, CardStatus.Hand); } else if(card is DefenseCardModel) { createCard<DefenseCardModel>(topPlayerHand, card as DefenseCardModel, Player.Top, CardStatus.Hand); createCard<DefenseCardModel>(bottomPlayerHand, card as DefenseCardModel, Player.Bottom, CardStatus.Hand); } else { createCard<BasicCardModel>(topPlayerHand, card as BasicCardModel, Player.Top, CardStatus.Hand); createCard<BasicCardModel>(bottomPlayerHand, card as BasicCardModel, Player.Bottom, CardStatus.Hand); } } /* for(int i = 0; i < 2; i++) { createCard<AttackCardModel>(topPlayerHand, Player.Top, CardStatus.Hand); createCard<AttackCardModel>(bottomPlayerHand, Player.Bottom, CardStatus.Hand); } for (int i = 0; i < 2; i++) { createCard<DefenseCardModel>(topPlayerHand, Player.Top, CardStatus.Hand); createCard<DefenseCardModel>(bottomPlayerHand, Player.Bottom, CardStatus.Hand); } */ } // Update is called once per frame void Update () { } // For testing, have a CardCollection passed in later public CardCollection generateCards() { CardCollection cards = new CardCollection(); //AttackCardModel testcard = new AttackCardModel(4, AttackType.SQLInjection, 3); cards.cards.Add(new AttackCardModel(4, AttackType.SQLInjection, 3)); cards.cards.Add(new DefenseCardModel(5, AttackType.SQLInjection, 1)); //Debug.Log(testcard.attackStrength + "is attack strength"); return cards; } public void createCard<T>(GameObject whereToPut, T objectToCopy, Player player, CardStatus cardStatus) where T : BasicCardModel { GameObject new_card = Instantiate(basicCard); new_card.transform.SetParent(whereToPut.transform, false); Destroy(new_card.GetComponent<BasicCardModel>()); new_card.AddComponent<T>(); --->new_card.GetComponent<T>().copyAttributes(objectToCopy); <--- new_card.GetComponent<T>().linkModelToCardObject(new_card); new_card.GetComponent<T>().setUpCard<T>(player, cardStatus); } }

Estoy teniendo problemas con esta línea (cerca del final del objeto del controlador): new_card.GetComponent<T>().copyAttributes(objectToCopy);

En lugar de llamar al método hijo para copyAttributes , llama al método principal y, por lo tanto, no copia los atributos que yo quiero.

En mi pregunta anterior sobre esto, una persona sugirió usar el tipado dinámico como una solución. Sin embargo, aunque GetComponent<ParentClass> debería obtener los tipos secundarios, no funciona por alguna razón, así que necesito usar genéricos.

¿Cómo puedo forzarlo a llamar al método secundario en lugar del método principal?


Haga que el BasicCardModel su BasicCardModel copyAttributes virtual.

public class BasicCardModel : Draggable { // ... public virtual void copyAttributes(BasicCardModel bcm) { // ... } // ... }

A continuación, anule el AttackCardModel y AttackCardModel el modelo de tarjeta en el tipo derivado antes de copiar atributos adicionales:

public override void copyAttributes(BasicCardModel bcm) { base.copyAttributes(acm); var acm = bcm as AttackCardModel; if (acm != null) { attackType = acm.attackType; Debug.Log("Attack strength = " + acm.attackStrength); attackStrength = acm.attackStrength; } }