问题
I am making a card game, and I have several scripts that control card behavior.
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;
}
...
}
I have several specialized cards similar to below:
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;
}
}
I have a controller object that generates these cards:
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);
}
}
I am having trouble with this line (near the end of the controller object):
new_card.GetComponent<T>().copyAttributes(objectToCopy);
Instead of calling the child method for copyAttributes
, it calls the parent method, and thus does not copy the attributes that I want.
In my previous question about this, one person suggested using dynamic typing as a solution. However, even though GetComponent<ParentClass>
should get the child types, it doesn't work for some reason, so I need to use generics.
How can I force it to call the child method instead of the parent method?
回答1:
Make your BasicCardModel
's copyAttributes
method virtual.
public class BasicCardModel : Draggable {
// ...
public virtual void copyAttributes(BasicCardModel bcm) {
// ...
}
// ...
}
Then override it AttackCardModel
, and cast the card model to the derived type before copying additional attributes:
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;
}
}
回答2:
You need to reflect the hierarchy in your types - one way is to create an interface and add a constraint for it in your Create
method:
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);
}
which you then need to implement in your classes:
public class AttackCardModel : BasicCardModel, ICopyableFrom<AttackCardModel>
{
public void CopyAttributes(AttackCardModel src)
{
}
}
来源:https://stackoverflow.com/questions/33768952/inherited-class-with-methods-taking-child-type-as-a-parameter-wrong-method-bein