Reputation: 637
so I'm working on a game in Java, and I'm a little confussed on how I should go about something. It's a Trading Card Game, kinda like Magic, and so for classes so far I have
It is my hope that I'll be able to have atleast 50 different types of card, each of which in their own class, so a little side question is, is this the best way? As for my problem:
I have the following code inside my GameDriver class:
ArrayList<Cards> playerHand = new ArrayList<Cards>();
playerHand.add(new WolfCard());
playerHand.add(new TheLarionCard());
System.out.println(((Cards)playerHand.get(1)));
Each card extends Cards, and Cards extend GameDriver, The code above will print out something like:
TheLarionCard[panel0,0,0,0x0,invalid,layout=java.awt.FlowLayout]
But now, if I want to grab the health of say TheLarionCard, I thought I could just add .health to the last line like:
System.out.println(((Cards)playerHand.get(1).health));
But obviously I can't, what am I doing wrong here?
Any help is great! Thank you!
Upvotes: 2
Views: 15936
Reputation: 1519
I think you have three options:
You want each different type of card to have a health
property. In this case, you can put that property into the parent class Cards
and then it will be valid to ask for the property for any class that extends Cards
. If the Cards
class has a health
data field, the code in your question will work.
You want only TheLarionCard
to have a health property. In that case, your cast would have be:
System.out.println(((TheLarionCard)playerHand.get(1).health));
This way, the compiler has knows to look in the TheLarionCard
class for the health property, not the Cards
class.
You don't actually need the individual card classes to be subclasses of Cards
. If there's no really compelling reason you've done it that way, you could have all cards be part of the Cards
class and their different types (TheLarionCard, WolfCard, etc) could be designated by a data field. For example:
public class Card {
String type;
public Card(String inType) {
this.type = inType;
}
public String toString() {
return "This is a " + type;
}
}
This way if you want the different cards to behave differently, you can check their type
value and assign different behaviors based on its value, e.g.
public void awesomeMethod() {
if ("TheLarionCard".equals(type)) {
// execute TheLarionCard code
} else if ("WolfCard".equals(type)) {
// execute WolfCard code
}
}
This is a simplified version of the Abstract Factory Pattern design that some of the other answers were talking about, so if you're new to interfaces you could try it this way to see if the structure works, then add interfaces later.
Upvotes: 3
Reputation: 15219
You don't really need interfaces or even such a complex variety of classes. I'm guessing all of your Cards have generally similar behavior. They are of a certain type, can do a specific action, can have actions and/or effects happen onto them etc. So you only need one Cards class for this, and in it have all the fields and methods that manage those generic states/actions.
Then you can make separate classes that inherit from Cards class (which btw, it's better to rename to just "Card"), like if you have effect type cards (such as a MTG Mana Flare or Hideous Visage equivalents) and then you also have creature cards (like MTG's Shivan Dragon or Dragon Whelp) you can make classes such as EffectCard which might have it's own fields like "duration" and "affectedTypes" and then use it to make ManFlare instances, Hideous Visage instances, etc. Also make a CreatureCard with stuff like hitpoints, firstStrike, etc. and make ShivanDragon instances and DragonWhelp instances from it.
Also don't be afraid of composition. Instead of subclassing/making extra classes for each card, make a simpler hierarchy like the one above and pass it "command" or "action" classes which dictates the more specific details. Like the FirstStrike instance of the EffectCard class could be initialized with an "action" instance that tells it specifically how to affect a CreatureCard instance, the ShivanDragon instance of the CreatureCard class would have an action telling it how it's attack can be increased by utilizing Red Lands cards, etc.
Upvotes: 0
Reputation: 91299
Define an interface or abstract method getHealth()
method in Cards
, that must be implemented by WolfCard
and TheLarionCard
. Then, you can do playerHand.get(1).getHealth()
.
For instance:
public abstract class BaseCard {
protected int health;
public abstract int getHealth();
}
public class WolfCard extends BaseCard {
private int wolfHealthBoost;
public int getHealth() {
return health + wolfHealthBoost;
}
}
public class TheLarionCard extends BaseCard {
public int getHealth() {
return health;
}
}
Upvotes: 1
Reputation: 1
You should check if you have the getter for the health attribute in those classes, private attributes can't be accessed from outside the class.
Just make a new method, getHealth(), that returns the health attribute, and then append it after the dot at the last line.
BTW, you don't have to cast the Cards class if you already defined the ArrayList with that stereotype.
Upvotes: 0