So I'm trying to make a CCG type of game using javafx (similar to Hearthstone), and I was wondering if it's a very bad idea to have one class for each card, because I've done some research and most fan made card games of Hearthstone use JSON to get the card objects. For example if the game only had 4 cards with the names:
DragonMaster
Vulcan
Pirate
Chuck Norris
I'd have 4 classes, with the names respectively. Now I though this was necessary since every card would have its own behaviour, meaning one card might do something when summoned, and in this case I have a method that gets called for that action, while others might have other methods or none at all.
Now as you can probably tell, if you have 100 cards in the game, the number of classes also gets big (and that's just for the cards package, since I'm using the MVC model, the project got really big without me realizing it).
Some other information:
All concrete card classes (e.g. Vulcan) extend an abstract Card class that contains fields such as name and cost.
Inside the cards package in the model, I have two other packages before having the actual classes, one for minions and another one for spells.
Also, If I don't have a class for each card, how can I instantiate a new specific card to add to the player's hand? Is there a different solution to this "class abundance" problem, and does this actually affect performance when the game is running or even space in the jar file?
If someone could anwser my question or any kind of help I'd be very appreciated.
Having thousands of classes will not impact performance in any noticeable way. You can even pre-compile them ahead of time or cache them.
That said, many game engines are using a entity-component approach to represent game entities and keep things like effects as different functions.
This way you can combine different effects cards have in ways that can't be done with single-inheritance.
Below is a link that describes the approach.
https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system
You could adapt this gradually.
For example, your cards could be just one type of entity.
class Card {
int mana;
String name;
Effect[] effects;
Trigger[] triggers;
}
Effects could be pieces of code that act on the playfield and the current card.
interface Effect {
void affect(Playfield pf);
}
Triggers could be event listeners relevant to the card.
I.e. there could be a trigger that fires when the opponent plays a card.
etc.
I am no expert in this field, but I think while your approach would work, it could make maintainability and scaling more difficult.
Another alternative you can try is to store the characteristics of your cards in a database (or some kind of properties file). In this case, you just need a common Card class, and it loads its values from database.
class Card {
int id;
String name;
int cost;
int speed;
OnSummonEffect summonEffect;
}
interface OnSummonEffect { ... }
abstract class StatBoostEffect implements OnSummonEffect { ... }
class AttackBoostEffect extends StatBoostEffect { ... }
Card Table
CardID Name Cost Speed SummonEffect
1 DragonMaster 5 10 com.foo.bar.AttackBoostEffect
2 Vulcan 3 12 com.foo.bar.SomeSummonEffect
Although saving the class name may not sound elegant (and it probably has its own side effects), but this approach makes it easy to add new things.
Adding a new card type is simply adding a new entry to the database table, and potentially adding new "effect" class to the project. If you decide to change some attributes (or add new attributes) to the card, you just need to add/change column in database table and then that single Card class. If you made one class for each card type, you would have to change the base card, then change every single card class.
Related
I'm making a game with different types of mobs in it. There is also a list of interfaces, each representing an ability that a mob can have. Let's say I have 100 objects extending the mob class, each one containing a different list of mob-applicable abilities (swing, explode, jump, etc.). All implementing these interfaces would do is to add blank methods to the class. If the usage of the ability is constant between all mobs, how would I make it so the ability is
pre-written so that I wouldn't need to write it again for every mob that implements it?
I do know of default methods, but they are static and don't have access to any of the mob's variables unless I pass "this" as a parameter which is something I don't want to do.
I am also aware that were there to be a solution to the problem using interfaces, those interfaces could only ever be implemented by a mob.
Thanks.
If I understand it correctly, a possible solution is to compose abilities instead of inheriting them.
interface Ability {
void doAbility();
}
class Firebending implements Ability {
private Mob mob;
public Firebending(Mob mob) {
this.mob = mob;
}
void doAbility() {
// mutate mob's state to spit fire, and attack the world
}
} // repeat this for each ability you have, flying, x-ray vision, doing taxes etc
class Mob {
private Ability[] abilities;
public Mob(Ability[] abilities) {
this.abilities = abilities;
}
}
With something like this, you can build different mobs on the fly each with a different set of abilities, suitable for when the mob varieties outnumber the number of abilities. And yes, this would involve designing your Mob class(es) to be flexible to be mutated this way.
Cool question and one I fought back and forth with. It turns out that you probably will end up in a code trap , mostly due to a strictly object oriented design approach. Having written a number of game engines I might propose an alternative thought process.
Image if you had a skeleton that needs a shield and a sword, but can at any time not have a shield, maybe you drop it, or conversely drop the sword (or both). To code this using Object Oriented design only, we would attempt to subclass from the skeleton and extend the class to have the skeleton with sword instance, but what about with shield, or with sword and shield, or both, or neither. To accomplish you could bang on it and force OOP design but as with all things, eventually the game designer will ask you to change the skeleton in some way that will cause a significant code change and you can forget about loosely coupled object sharing (say the skeleton drops the sword and the knight picks it up).
Having dealt with this and understating where you are right now, I'd suggest researching an Entity Component System.
Here the Game assets are split into Entities, Components, and Systems.
Entities: Is a simple list of integers where each integer is a component id. This allows components such as the SwordComponent to be shared across any other component. Think of an entity as a collection of components that a system can use to do some game action.
Components: A component is a simple class that ONLY contains data fields, never implementation. Each component gets a unique ID and the specific fields needed to define the component. Here I find it okay to use OOP to subclass the Component class so I really use a mix of both worlds.
System: Systems are where things get interesting. While entities are just list that combine components, and components are just data and state info, systems act on the component data to make entities work. Here you may pass in an entity and have some game logic act on the data. Systems are where you would put the code that makes each entity tick.
Here is an outline of our skeleton example:
Component[0]: Skeleton Mesh
Component[1]: Idle Animation
Component[2]: Walk Animation
Component[3]: Run Animation
Component[4]: Collision
Component[5]: Sound
Component[6]: Sword
Component[7]: Shield
Component[8]: Clown Suit
Skeleton Entity:
Entity[0] = new int {0,1,2,3,4,5,6,7,8} // Defines all the components above into one character
Possible Systems:
System[0] = Collision system handles polygon collisions, using all entities collision components.
System[1] = Animation system uses idle, walk, and run animation components and can be shared across entities.
System[2] = Render system is used to render the mesh using your render engine.
System[3] = Sound system is used to handle sound start, end, tween...
System[4] = ...
Now if the designer wants the skeleton to be able to sprout wings and fly, I don't worry about changing any previous code, I just create a new WingsComponent, add it to my entities component list, and code the new system to make the skeleton fly. Now I can freely extend my component and system pool without worrying about breaking changes.
So basically my question is the same as this one:
Card game with huge amount of cards and complex actions
But I don't "speak or understand a word" of C++.
It's my very first big java project and I want to implement a Trading Card Game component.
My problem is: I plan on using 100+ different cards, with different actions. There'll be 4 main types. Within those types, the card's actions are similar but still different.
I thought about making an extra class like
public class CardActionDatabase {
public void card1Action(){}
public void card2Action(){}
....
}
But the problem is, I can't invoke/call them within the actual code like
(playedcard.getName())Action()
since that's impossible in a compiled language.
So basically I'd have to "if" the recent played card with all existing ones, which would be inefficient.
How can I accomplish this?
I've been messing around with card games myself, and there are a few options here. A simple way to do it (though perhaps not the most efficient) is thusly:
First, create an abstract class Card that contains common variables and methods, such as String name and public void onPlay(). Then you might make another abstract subclass for each of your four types.
Then, create subclasses of Card for each unique card in your game. These subclasses define onPlay() in their own way. Then in your player turn logic, when a player chooses a card, that card's onPlay method is called. You can even add stuff like onDiscard, onDestroy, or onTurnStart.
You might also consider creating controller classes between the "Cards" and the "Field/Play Area". For example, you might have a HandController class that has public methods DiscardRandom(), Discard(int index) and Draw() which the Cards can use to manipulate the gameplay as they should.
It can become troublesome and complex to manage the chain of calls needed to perform actions appropriately, but strong documentation goes a long way.
I am creating a game in which you can either play against computers or humans with multiple (advanced) settings for each, the variety of possible games get large quickly when adding new settings.
I want to write clean code and I face the problem that I need to write a lot of "unnecessary" checks for all possible optional/mutual exclusive options. Unnecessary because when the game was created with specific settings it could already know its options and thus which checks are redundant. I see little reasons for continuously checking for e.g. if the game has only computers, humans or a mix of both.
I know of the Builder-pattern which can solve the problem of having many parameters to pass into a constructor of which many are optional. I can use this when I create a game. This solves the problem of having a hard time constructing the game. However this still requires a lot of checks during the time the game is run to see which settings are set and which not.
Any leads for me to look into?
Code Example (Only illustration)
Mode mode;
Vocabulary mVocabulary;
Player[] mPlayers;
GameLog mGameLog;
String mCurrentString;
int mMinimalWordLength = 3;
int mIndexActivePlayer;
int mNumberOfActivePlayers;
boolean mComputers; //[Optional]
int mNumberOfComputers; //[Required if mComputer is true]
Difficulty mDifficulty; //[Required if mComputer is true]
//One of these optionals are required
boolean mBlueTooth; //[Optional]
boolean online; //[Optional]
boolean sameDevice; //[Optional]
//Here I could use the builder pattern to set all the options
public Game(Vocabulary vocabulary, int numberOfPlayers, int minimalWordLength, Player[] players) {
this.mVocabulary = vocabulary;
this.mMinimalWordLength = minimalWordLength;
this.numberOfActivePlayers = numberOfPlayers;
this.mPlayers = players;
}
}
I am creating a game which requires a mVocabulary of words, with a list of players mPlayers and a couple of optional settings. Each game is either created for computers or humans or a mix of both. Each game either is online, via blue-toot or on the sameDevice.
Based on these options different things happen throughout the code, so you could write a couple of if else if statements in each method that follows this code. However I want to prevent this.
If you see your program as a decision tree in which you are at a particular time at a specific point in your program, then you know that once a game is created in a specific way where you should look and where not to look. Since you're in a specific branch of the tree. For example, you create a game with only humans, a weird thing to do would to keep checking each turn if a player is human if you know that there are only human player, since that is the way you created the game in the first place.
I hope this make my point more clear. Although not a full code example is written.
Not sure if it's the best approach, but I avoid too many checks by subclassing and implementing 'hook' methods (an idea I borrowed from Rails hooks, actually).
For instance, imagine you have a ParentGame class and BlueToothGame, OnlineGame and SameDeviceGame children. You'd implement all common logic in ParentGame, such as.-
public void mainLoop() {
startOfMainLoop();
// Some stuff
checkWinLoseCondition();
}
Where startOfMainLoop and checkWinLoseCondition() could be abstract methods to be implemented on children classes. This way, you encapsulate common logic, and implement specific behavior for each 'kind/configuration of game', without messing your code with lots of checks along your main game logic.
Just an idea, though, of course the best approach depends on your current scenario :)
I am having a bit of issues with design. Maybe I am thinking about this all wrong, but it seems that what I am designing only works well in a procedural manner.
The Game
I am working on a game, this game has about 10-20 players inside of it, and consists of 3 rounds. When players start up the game, the server loads their data from a database, stores it in a java class, and sends data that is requested to the client. Lets call this Player.java. This class is persistent in between the rounds of the game.
Every player in the game also has a role. This role changes in-between each round and I need this role to be linked with Player.java in some way. Right now I have 3 roles: Hunter, Seeker, and Spectator. Each role has the same basic things: onDeath(), onRespawn(), onKill(KillEvent event). I also need to be able to easily check what role a player is. (For example linking the roles with a enum).
The Problem
The problem I am running into now is how do I implement this in a OOP way? Originally, I had each role as a class that implements Role.java, and every time a role is created, it takes a Player in the constructor. This is all fine and dandy until I start changing people's roles in the middle of the rounds and after the end of each round. It seems like bad practice to me if I am consistently setting the players role to a new object.
Summary
To sum this up (since I am terrible at describing things), it seems like all of this would work perfectly in a procedural manner, but I can't figure out for the life of me a good way to implement this concept using OOP. The way I have it implemented now, each Player has a enum stating what role they are, and to change that role I simply change the enum in Player. With that being said though, once I get to the game logic, I end up with a TON of nested if statements, something that I feel could be greatly reduced with some polymorphism.
So to end with a question, what would be a good plan of attack to implement this (or a slightly modified version of this system) in a object oriented way without having to consistently create new objects that take in data from old objects? (I don't have a ton of experience with OOP, but to me this just seems like a bad idea)
I think I would go for this solution:
Make Player an Interface
Create a Proxy-Class for it (a class that has only one property, which is of type Player, and redirects all methods to this object). Lets call it ConcretePlayer
Add a setRole method, taking a Role to ConcretePlayer.
Make Role implement Player
Create Subclasses of Role like you did, each takes a ConcretePlayer in their constructor.
Store the stats that are shared among all Roles in the ConcretePlayer
Externally use Player or ConcretePlayer to access everything.
It's not fleshed out perfectly, but I think you get the idea. You may find that Role and Player shouldn't share the same interface, or that you want to create an own interface for the callbacks, but that depends on the rest of your code and usecases.
As a project over summer while I have some downtime from Uni I am going to build a monopoly game. This question is more about the general idea of the problem however, rather than the specific task I'm trying to carry out.
I decided to build this with a bottom up approach, creating just movement around a forty space board and then moving on to interaction with spaces. I realised that I was quite unsure of the best way of proceeding with this and I am torn between two design ideas:
Giving every space its own object, all sub-classes of a Space object so the interaction can be defined by the space object itself. I could do this by implementing different land() methods for each type of space.
Only giving the Properties and Utilities (as each property has unique features) objects and creating methods for dealing with the buying/renting etc in the main class of the program (or Board as I'm calling it). Spaces like go and super tax could be implemented by a small set of conditionals checking to see if player is on a special space.
Option 1 is obviously the OO (and I feel the correct) way of doing things but I'd like to only have to handle user interaction from the programs main class. In other words, I don't want the space objects to be interacting with the player.
Why? Errr. A lot of the coding I've done thus far has had this simplicity but I'm not sure if this is a pipe dream or not for larger projects. Should I really be handling user interaction in an entirely separate class?
As you can see I am quite confused about this situation. Is there some way round this? And, does anyone have any advice on practical OO design that could help in general?
EDIT: Just like to note that I feel I lost a little focus on this question. I am interested in the general methodology of combining OO and any external action(command line, networking, GUI, file management etc) really.
In the end, it is up to you. That is the beauty of OO, in that it is subject to interpretation. There are some patterns that should usually be adhered to, but in general it is your decision how to approach it.
However, you should carefully consider what each actor in the system should know about the rest of it. Should a property really know about the player, his account balance, and the other players? Probably not. A property should know what it costs, how much its rent is, etc.
On the other hand, should the main playing thread be concerned about trivial matters such as paying rent? Probably not. Its main concern should be the state of the game itself, such as dice rolling, whether each player wants to trade or buy or unmortgage/mortgage, things like that.
Think for a moment about the action of landing on a square. Once landed, the player has 3 options:
Buy the property
Ignore the property
Pay rent
Now, which actor in the system knows all the information required to complete that. We have the Game class, which isn't concerned with such tedium. We have the Property, which doesn't really care about the players. But the Player object knows all this information. It keeps a record of what each player owns, and can easily access the proper data.
So, if it were me, I would make a Player.performMove(Die d) method. It has easy access to the accounts. This also allows for the least coupling among classes.
But in the end, it's up to you. I'm sure people have created Monopoly clones in perfect OO, as well as Functional or Procedural languages too. In the end, use what you know and keep refactoring until you're happy with the end design.
I agree option #1 seems better.
As for "user interaction" - it all depends. You could leave some of your code in another class. For example,
// in main class
user.landOn(space);
if (space.containsProperties()) doSomething(); // Option #1 for some user-interaction code
// in User.java
public void landOn(Space s) {
// do some checks
s.land(this);
if (s.containsProperties()) {...} // Option #2
// something else?
}
// in GetMoneySpace.java
#Override
public void land(User u) {
u.awardCash(200);
// Option #3 - no properties so nothing here
}
This is far more OOP-y (and better, in my opinion) than something like
if (space.isCashAwardSpace()) {
user.awardCash(space.getAward());
}
if (user.something()) doSomething(); // Some user-interaction code
I am not entirely sure if I understand it correctly. You have always such choice when designing software. I would personally go for the first choice. One argument is personal experience with small games (Scrabble), which prooved to me that good design matters for smaller projects as well. The point of OOP is that you can think differently about your design and you get some design benefits. For example imagine how hard it will be to add new field, change existing one, reuse behaviour of one field in multiple fields.
Your first approach is the one I'd go for. It encapsulates the behaviour where it's needed. So, you'd have Space subclasses for Utilities, Properties, GotoJail, FreeParking - basically all the different cateogires of spaces. What groups a category is it's common behaviour.
Your properties spaces may themselves have a group object as a member, e.g. to group all the dark blue properties together.
As to interaction with the user, you pass a Board (or better a GameController) instance to each space, so it knows which Game it is part of and can influence the game. The Space can then invoke specific actions on the board, such as, moving a piece, asking the user a question etc. The main point is that there is separation - the user interaction is not happening inside each Space - but the space is allowed to request that some interaction happens, or that a piece is moved. It's up to your GameController to actually do the interaction or move pieces etc. This separation makes it easy to test, and also provide alternative implementations as the need may arise (E.g. different game rules in different editions/countries?)
Go with the first design. You'd have a Property class, and subclass the special properties, overriding the default behavior.
As far as interaction, you could have a Token class, and move an instance of that around the board. You have to give the user some options, but yes, from the responses, you should be calling methods on objects, not putting complex logic in the user events.
Sample classes:
Property
name
price
baseRent
houseCount
hotelCount
mortgaged
getCurrentRent()
RailRoad extends Property
Utility extends Property
Board
properties
User
token
playerName
currentProperty
ownedProperties
buyProperty()
payRentOnProperty()
mortgageProperty()
move()
Option 2 doesn't make much sense, or at least it's not as clear to me as option 1. With option 1 you don't need to handle user interaction inside your space object. You could have in your main class or a separate class dedicated to handle user interaction:
public void move(Player p, int spaces){
Space landingSpace = board.getLandingSpace(p,spaces);
landingSpace.land(p); //apply your logic here
}
As you can see, the Space class is responsible for checking the Player p that intends to land on that space. It applies any custom logic, checks if it has enough money, if it's something that the player owns, etc. Each subclass of Space will have its own set of rules, as you described in option 1.
Part of the point of object-oriented design is to simplify the representation of the problem within the solution space (i.e., modeling the system in the computer). In this case, consider the relationships between objects. Is there enough functionality in a Space to warrant abstracting that into a class, or does it make more sense for there to be discrete Property and Utility classes unrelated to Space because of the unique features of both? Is a Property a special kind of Space, or merely a field within Space? These are the kinds of problems you probably will need to grapple with in designing the game.
As far as interaction, it's generally bad news for a design when you have a 'god class' that does all the work and merely asks the other classes for information. There are plenty of ways to fall into this trap; one way to determine whether you are dealing with a god class is to look for a class name including Manager or System. Thus, it's probably not the best idea to have some sort of "game manager" that asks all the other objects for data, makes all the changes, and keeps track of everything. Eliminate these as much as possible.
God classes violate the concept of encapsulation, which involves more than data hiding (though that's certainly a big part of it). Good encapsulation means that related methods and data are part of a single object. For example, a Property doesn't need to make requests of its owner, so a field containing a reference to the Player could violate encapsulation. Some of these encapsulation violations aren't obvious at all, and can be hard to spot. When designing the object, try to determine the smallest amount of information about the object that needs to be shared with external objects. Trim out anything unnecessary.
You can obviously go about this in a lot of ways, but my design would be something like this (iteration could certainly prove it wrong):
Space class that contains basic data and methods that are common to all spaces (such as their position on the board, occupied or not, etc.).
Subclasses moving from most common (Property and Utility) to most unique (Go, Jail, FreeParking, and so on; probably singletons) with fields and methods related to each.
Player class to contain player information.
GameState class that is concerned with game state; whose turn it is, how many houses are left in the bank, and so on.
Good luck with the game and your continued studies.
Naturally, Google is your friend, but here's a sampling of things I would recommend reading:
ATM simulation (this idea is
also discussed in Rebecca
Wirfs-Brock's book below)
Object-Oriented Design Heuristics - Arthur Riel
How Designs Differ (PDF), Designing Object-Oriented Software - Rebecca Wirfs-Brock