Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

kingos

c++ class design questions

This topic is 6053 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hi everyone. i am writing a "magic the gathering game", and as i am an object oriented convert am having a bit of trouble deciding what should go where in terms of classes. More specifically, this game has a Game class to initialise the game and hold important info and stuff, Player class for each player (eg. Player has a Hand and a Deck, each of which are lists of Cards). I am stuck with regard to how I should do each players Turns. I started off with a Turnstate class, which I would initialise everytime I called Player p.newTurn(), which would remember which part of the turn the player was in. (oh yeah, every turn in magic the gathering has a bunch of different phases). I worked out this sucked, since the other player couldn''t find out what part of the turn it was up to, when he needed to do things. So i decided just to have an enumerated type TurnState, and put it in game, so typedef enum {UntapPhase,...,HealCreaturesPhase } TurnState; and have an instance of it in the game class. but then where do the functions that affect that go? like setCurrentPhase() or something? hmmmm. should I go back to having a Turnstate class with a variable called state inside that or something, and have an instance of that class in game? or just add the functions to the game class? or what? any good articles on knowing what to put in each class, and how to divide it up?

Share this post


Link to post
Share on other sites
Advertisement
From what I''m reading, I understand that you''re creating a 2 player game.

The most object-oriented way to do this is to have each state as an object.

You''ll need to have a abstract State class:
  
class State
{
public:
virtual void Process(Player* player) = 0;
virtual void EndPhase() = 0;

int StateID; //for run-time identification

};


Then for each phase you''ll need to have a concrete State class:
  
class Upkeep : public State
{
public:
virtual void Process(Player* player) ;
virtual void EndPhase();
};
class DrawPhase : public State
{
public:
virtual void Process(Player* player);
virtual void EndPhase();
};

//and so on...



Your player class will look like this:
  
class Player
{
public:
void Process();

State* CurrentState;
};


Process():
  
void Player::Process()
{
CurrentState->Process(this);
}




With this technique, you do not have a single Process Function but from a client programmer''s point of view, it will seem so.

Instead all your processing will be different; there will be a Draw Phase process function as well a Upkeep one.

For example:
  
//Same clas from the above source:

void DrawPhase::Process(Player* player)
{
player->DrawCard(Library->GetCard());
this->EndPhase();
}



Of course, many details are missing but if you get the architecture correct, everything will fall into place nicely (this doesn''t happen in real-life though).

Share this post


Link to post
Share on other sites
okay Darkor thanks, that looks really good.

a few more questions then:
so to change the state to a new one, I would do something like:
     
void Untap::EndPhase(Player *p) {
p->CurrentState = new Upkeep;
}

that kind of seems ugly, since you might do a lot of stuff inside the constructor of Upkeep that
you would normally want to do at the beginning of the next phase?

the other thing is, in phases like Main, both players get to do stuff, such as
the other player is allowed to play cards as well during the other players turn.
In the current situation, I guess I could have a function

int Player::GetCurrentState() {
return StateID;
}


in my game class at present i have

Player *Front, *Rear; // where Front is current player

when I initially tried this approach, I ended up having to store a pointer to the game class inside each player, and then doing something like

current_player_pointer->game_pointer->other_player_pointer->GetCurrentState();
[/source]
which looks shocking, and made my code separation or whatever it is called (keeping classes separate)
absolutely disastrous.
Have I misread that somewhere? or how can I get around this problem?


Edited by - kingos on February 25, 2002 4:01:52 AM

Edited by - kingos on February 25, 2002 4:04:32 AM

Share this post


Link to post
Share on other sites
You got the idea right but instead of handling the change of States within the state itself, you set a flag to the next state. So you give each state a pointer named NextState. You set it to NULL initially but when you call Untap::EndPhase(); it assigns the next state based on the conttext given during that phase.

During each time you process the player, you test if the NextState is NULL. If it isn't you cleanup the current state and create the new state. Hopefully, all your data is stored within the player class because the states are there just to manipulate data based on decisions made in different contexts.

What do you want to do in constructor of Upkeep that you might want to do in the next phase?

quote:


    
int Player::GetCurrentState() {
return StateID;
}



Right but instead you'll want it like that:

  
int Player::GetCurrentState() {
return CurrentState->GetStateID();
}



So you don't have to set the state manually each time. Since the state itself stores its own ID, you just return this value.


About the second player, there are a couple of issues you might want to address first. Firstly, why limit yourself to two players? Chaos magic was fun, though some matches didn't last long. =P Secondly, why do you have to store a pointer to the second player.

I propose having a list of players. And processing only goes to one player. I don't know how you want this game to be played: over a network or on one computer. I will assume that it is over a network (or internet).

On the current player's computer, you'll process the player normally. However, on the other players' computers, you process a NotMyTurnState. All this does is update what's on screen but he can cast instants. Also he will get a chance to react to other spells. He might want to cast a Counterspell or a Force Of Will.


Creating a game like this is far more difficult than I thought. You'll need far more than just player classes. But since you've understood what I've been saying thus far, I think that you'll have a fair chance at finishing it. =P

Okay, so maybe your server computer will have a game server instance class:

       
class GameServerInstance
{
public:
void Process();
private:
vector<Player> Players;
int CurrentPlayer;
};

GameServerInstance::Process
{
for (int i=0; i<Players.size(); i++)
{
Players[i]->Process();
}
}


This is made more complex since opponents get to cast instants during their turns. Okay, I think a way to solve this is to create an action dialog. Whenever a player wants to cast something, the other players will have to wait for him. The current player will get the priority though.

You won't need to check the state of other players because well, they'll be in the NotMyTurn State.

Oh yeah, remember to define virtual destructors for your abstract classes.

Edited by - Darkor on February 25, 2002 9:25:31 PM

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!