1
\$\begingroup\$

So I'm planning to try making a card game (in Java) but I'm not sure what the best way to design it is. I understand the engine stuff but not how the cards should be coded an how they should interact with the engine. The scope is like so:

We have an engine that understands the flow of the game. It knows you draw at the start, play cards at some point, have a combat step, and end the turn (switching players). This much is fine, but the concern is the cards themselves.

I want to have cards be their own entities. I'm not sure if it would be better to:

a) Have each card be their own class b) Have each card be programmed as an external script (say in Python)

I want the game engine to know as little as possible about a card. When you play a card, I want the game engine to go:

You're playing a card. Do you have resources? Ask the card how much it takes, then confirm you have it. When a card has an interaction, I want it to do as much as it can. For example, if the card says draw a card, I want it to forceably tell the engine to draw a card, or better yet, hook into the game, draw a card, and then force the engine to update itself.

Extreme cases would probably provide a better description, so if there was a card that said "players do not draw at the beginning of their turn", the engine would normally automatically draw, so we'd have to stop that. I could reasonably program something where the engine would check if anything special happens before each interaction and it would see "skip draw". Even still, how would I program that? Would I write a method in the engine to skip draw and then have the card add it as a special trigger? Would I actually have the card (perhaps programmed in Python) hook into the engine and end the draw method?

What would be the best way to go about this?

\$\endgroup\$
1
\$\begingroup\$

It sounds like what you want is to construct some kind of high level scripting language for the game logic interactions that cards actually perform. I think your idea to keep this sort of logic separated from the engine itself, is laudable (obviously this also implies that you could reuse the underlying engine for different resource-based card games, which I assume is your goal). But instead of focusing on this separation of engine and game logic early on, first write the entire thing in Java, maintaining separation of different sorts of logic (engine vs game) at class and package boundaries. That means starting out by writing your high-level game logic in Java, such as methods for different known card actions, perhaps in a separate package "gamelogic". Once you have something working, I guarantee you that it will be far easier to see the development patterns involved in migrating the necessary logic to instead be driven by your (runtime parsed) scripting language.

It would not be difficult to write some kind of token / expression parser for the sorts of interactions which your cards would perform. You could write that parser in Java and have it parse text files describing each card type, then have your engine call play() on the card which kicks off all the pre-parsed rules. An example card might be described by:

burn opponent 3 //burns the opponent for 3 damage
discard opponent [1 random hand] //force opponent to discard one card at random from hand
playagain

You may have more complex situations where rule resolutions need to occur in very particular order (MTG comes to mind). I guess you will figure out ways to describe these situations, as you go along.

There are different levels of abstraction that can be supported in a scripting language. You need to decide where the boundaries lie / how much effort you are willing to put in, in that regard, and then proceed from there. More general = more difficult. That's why I suggest writing it all in Java first. You may well find that you wish to retain a lot of the card rules functionality at the Java level (whether part of your engine app or separate) and then simply wrap those individual rule-application methods as keywords in a very basic, "thin" scripting language of your own devising, as above.

Your concept of having cards be "their own entities" is fine, e.g. creating them as a Card class. The concept of a card has to exist at the engine level, yes? So that means you encapsulate it as such. Then, every card may tie into this custom scripting through some methods which they all share as part of that class. You could even create a separate class which the Card has a reference to, which handles interactions with scripts; this would be good OO practice.

You're quite right about skipping cards. Ultimately, whatever script-level functionality can affect the engine, has to become engine-level functionality. You may find yourself occasionally having to add in new features to the engine code this way, as you come up with new cards that change the flow of play (hopefully there won't be too many of these). You'd also need hooks for things like "player x won the game", since the engine will have no concept of what creates a win or lose condition.

The key point is that it is very difficult to abstract a system when you do not yet have a working system to abstract from! Get started by architecting your system to less restrictive requirements, while bearing in mind your ultimate goal of abstraction. You will make faster progress this way.

\$\endgroup\$
  • \$\begingroup\$ Yeah this sounds pretty good. Mulling it over with a friend it does seem like just writing it all in Java is better. The suggestion was to place everything on a queue/stack and then allow cards to interact with it. For example, drawing a card would place that onto the stack and have the engine do that. Even if it got to a case "skip your draw step" the game would put that on the stack, the card would remove it from the stack. \$\endgroup\$ – Michael Yousef Dec 5 '13 at 20:53
  • \$\begingroup\$ The way I see some kind of solution here is to have class for the card, a class to manage the cards, a singleton class to manage the game and your engine delegates everything to the game manager. This way, you abstract the logic of the engine from the one in the game, the cards maintain in sync with the manager and it can be reused for any card game you come up to. \$\endgroup\$ – nosmirck Dec 6 '13 at 13:16
  • \$\begingroup\$ Oh, I forgot to mention that you will need a class for the player, a manager for player and they will stay in sync with the singleton game manager. \$\endgroup\$ – nosmirck Dec 6 '13 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.