Archived

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

Is this better?

This topic is 5149 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

I kept running into problems earlier with inheritance and some people suggested that I use only one class. Is this any better than the previous. I will list them both. NEW ONE:
#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
class CCharacter{
private:
	int health;
	int mhealth;
	int mana;
	int mmana;
	int defense;
	int level;
	int skill_level;
	int speed;
	int strength;
	bool isdefending;
	string name;
	string char_class;
public:
	CCharacter(){
		health = 100;
		mhealth = 100;
		mana = 100;
		mmana = 100;
		defense = 100;
		level = 1;
		skill_level = 1;
		speed = 100;
		strength = 100;
		isdefending = false;
		char_class = "Unknown";
		name = char_class;
	}
	CCharacter(string setname, string setcharclass){
		name = setname;
		char_class = setcharclass;
		health = 100;
		mhealth = 100;
		level = 1;
		skill_level = 1;
		isdefending = false;
		if(char_class == "Barbarian"){
			mana = 30;
			mmana = 30;
			defense = 60;
			strength = 60;
			speed = 50;
		}
		if(char_class == "Necromancer"){
			mana = 60;
			mmana = 60;
			defense = 40;
			strength = 30;
			speed = 60;
		}
	}

	int get_health(){
		return health;
	}
	int get_mhealth(){
		return mhealth;
	}
	int get_mana(){
		return mana;
	}
	int get_mmana(){
		return mmana;
	}
	int get_defense(){
		return defense;
	}
	int get_level(){
		return level;
	}
	int get_skill_level(){
		return skill_level;
	}
	int get_speed(){
		return speed;
	}
	string get_name(){
		return name;
	}
	string get_class(){
		return char_class;
	}
	void printinfo(){
		cout<<"Name: "<<name<<endl;
		cout<<"Class: "<<char_class<<endl;
		cout<<"Level: "<<level<<endl;
		cout<<"Health: "<<health<<"/"<<mhealth<<endl;
		cout<<"Mana: "<<mana<<"/"<<mmana<<endl;
		cout<<"Strength: "<<strength<<endl;
		cout<<"Defense: "<<defense<<endl;
		cout<<"Speed: "<<speed<<endl;
	}
	void set_health(int newhealth){
		health = newhealth;
	}
	void set_mhealth(int newhealth){
		mhealth = newhealth;
	}
	void set_mana(int newmana){
		mana = newmana;
	}
	void set_mmana(int newmana){
		mmana = newmana;
	}
	void set_defense(int newdef){
		defense = newdef;
	}
	void set_level(int newlevel){
		level = newlevel;
	}
	void set_speed(int newspeed){
		speed = newspeed;
	}
	void set_name(string newname){
		name = newname;
	}
	void set_class(string newclass){
		char_class = newclass;
	}
	void defend(){
		isdefending = true;
		cout<<name<<" is defending!"<<endl;
	}
	void undefend(){
		isdefending = false;
	}
	void attack(CCharacter *target){
		if(target->isdefending){
			target->set_defense(target->get_defense() * 2);
		}
		if(target->get_health() > (target->get_health() + target->get_defense())-strength){
			target->set_health((target->get_health() + target->get_defense())-strength);
		}
		if(target->get_health() < (target->get_health() + target->get_defense())-strength){
			cout<<name<<" is too weak to inflict damage!"<<endl;
		}
		target->undefend();
	}

};
void main(){
	CCharacter player("Cory", "Barbarian");
	CCharacter player2("Alex", "Necromancer");
	player.printinfo();
	player2.printinfo();
	player2.defend();
	player.attack(&player2);
	player2.printinfo();
}
OLD CODE:
//Copyright 2003 Cory Fisher

#include<iostream>								//For cin,cout

#include<string>								//For string use

#include<stdio.h>								//For standard io

using namespace std;							//Dont know why just everyone says you should

string nameSet();								//Forward declaration of nameSet()

class CMonster;
class CPlayer;
class Barbarian;
class Necromancer;
class CPlayer{									//Base Player Class

private:
	int playerHealth;							//Begin of self explanatory section

	int playerMaxHealth;						
	int playerMana;								
	int playerMaxMana;							
	int playerLevel;							
	int playerStrength;			
	int playerSpeed;
	int playerDefense;
	int playerSkill;
	string playerName;
	string playerClass;							//End of self explanatory section

public:
	string skill[10];
	CPlayer():									
		playerHealth(0),						
		playerMaxHealth(0),
		playerMana(0),
		playerMaxMana(0),
		playerLevel(1),
		playerStrength(0),
		playerSpeed(0),
		playerDefense(0),
		playerSkill(1),
		playerName(""),
		playerClass("")
	{
	}
	int getHealth(){							//Begin Self Explanatory

		return playerHealth;
	}
	int getMaxHealth(){
		return playerMaxHealth;
	}
	int getMana(){
		return playerMana;
	}
	int getMaxMana(){
		return playerMaxMana;
	}
	int getLevel(){
		return playerLevel;
	}
	int getStrength(){
		return playerStrength;
	}
	int getSpeed(){
		return playerSpeed;
	}
	int getDefense(){
		return playerDefense;
	}
	int getSkill(){
		return playerSkill;
	}
	string getName(){
		return playerName;
	}
	string getClass(){
		return playerClass;
	}
	void setHealth(int newhealth){
		playerHealth = newhealth;
	}
	void setMaxHealth(int newmaxhealth){
		playerMaxHealth = newmaxhealth;
	}
	void setMana(int newmana){
		playerMana = newmana;
	}
	void setMaxMana(int newmaxmana){
		playerMaxMana = newmaxmana;
	}
	void setLevel(int newlevel){
		playerLevel = newlevel;
	}
	void setStrength(int newstrength){
		playerStrength = newstrength;
	}
	void setSpeed(int newspeed){
		playerSpeed = newspeed;
	}
	void setDefense(int newdefense){
		playerDefense = newdefense;
	}
	void setSkill(int newskill){
		playerSkill = newskill;
	}
	void setName(string newname){
		playerName = newname;
	}
	void setClass(string newclass){
		playerClass = newclass;
	}												//End of Self Explanatory

	void printBaseInfo(){							//Prints the things that are common to all characters

		cout<<"Name: "<<playerName<<endl;
		cout<<"	Level: "<<playerLevel<<endl;
	}
	void printSkills(){								//Prints all skills known

		cout<<"Skills Learned: ";
		for(int i = 1; i < 11; i++){
			if(playerSkill < i){
				break;
			}
			if(playerSkill > i){
					cout<<skill[i]<<", ";
			}
			if(playerSkill == i){
				cout<<skill[i]<<endl;
			}

		}
	}
	void attack(CMonster *monster);

};
class Barbarian : public CPlayer{					//Derived barbarian class

public:
	Barbarian(){									//Default constructor set to what i like for a Barbarian

		setHealth(100);
		setMaxHealth(100);
		setMana(20);
		setMaxMana(20);
		setStrength(60);
		setSpeed(40);
		setDefense(60);
		setName(nameSet());
		setClass("Barbarian");
		initSkills();
	}
	void printInfo(){							   //Prints not always same stuff as other characters.

		system("cls");
		cout<<"Class: "<<getClass()<<endl;
		printBaseInfo();
		cout<<"	Health: "<<getHealth()<<"/"<<getMaxHealth()<<endl;
		cout<<"	Mana: "<<getMana()<<"/"<<getMaxMana()<<endl;
		cout<<"	Strength: "<<getStrength()<<endl;
		cout<<"	Speed: "<<getSpeed()<<endl;
		cout<<"	Defense: "<<getDefense()<<endl;
		printSkills();
	}
	void initSkills(){							//Initialize barbarians skills

		skill[0] = "Bruise";
		skill[1] = "Bash";
		skill[2] = "Crush";
		skill[3] = "Bang";
		skill[4] = "Break";
		skill[5] = "Boom";
		skill[6] = "Crack";
		skill[7] = "Shatter";
		skill[8] = "Destroy";
		skill[9] = "Annihilate";
	}

};
class Necromancer : public CPlayer{				//Derived necromancer class

public:								
	Necromancer(){								//Default constructor stats i want for a necromancer

		setHealth(100);
		setMaxHealth(100);
		setMana(60);
		setMaxMana(60);
		setStrength(20);
		setSpeed(60);
		setDefense(40);
		setName(nameSet());
		setClass("Necromancer");
		initSkills();
	}
	void printInfo(){							//Same as above

		system("cls");
		cout<<"Class: "<<getClass()<<endl;
		printBaseInfo();
		cout<<"	Health: "<<getHealth()<<"/"<<getMaxHealth()<<endl;
		cout<<"	Mana: "<<getMana()<<"/"<<getMaxMana()<<endl;
		cout<<"	Strength: "<<getStrength()<<endl;
		cout<<"	Speed: "<<getSpeed()<<endl;
		cout<<"	Defense: "<<getDefense()<<endl;
		printSkills();
	}
	void initSkills(){							//Same as above cept its for necromancer

		skill[0] = "Fire";
		skill[1] = "Flame";
		skill[2] = "Burn";
		skill[3] = "Big Burn";
		skill[4] = "Blaze";
		skill[5] = "Firestorm";
		skill[6] = "Forest Fire";
		skill[7] = "Flame of Demon";
		skill[8] = "Smoke Rings";
		skill[9] = "Hell Fire";
	}
};
class CMonster{
private:
	int health;
	int maxhealth;
	int defense;
	int speed;
	int strength;
public:
	CMonster(){
		health = 100;
		maxhealth = 100;
		defense = 100;
		speed = 100;
		strength = 100;
	}
	int getMonsterHealth(){
		return health;
	}
	void setMonsterHealth(int newhealth){
		health = newhealth;
	}
	int getMonsterDefense(){
		return defense;
	}
}big;
int chartype;
void getCharacterType(){									
	cout<<"1) Barbarian\n";
	cout<<"2) Necromancer\n";
	cout<<"What kind of character would you like to be?";
	cin>>chartype;
}

void main(){									//Main Does nothing haven''t started actual game coding yet

	getCharacterType();
	if(chartype == 1){
		Barbarian player;
	}
	else{
		Necromancer player;
	}
	cout<<player.getStrength();
}
string nameSet(){								//It gets the name from the user when the constructor for 

	string charname;							//the class is called;

	cout<<"Enter a name:";
	cin>>charname;
	return charname;
}		
void CPlayer::attack(CMonster *monster){
	monster->setMonsterHealth((monster->getMonsterHealth() + (.050 * monster->getMonsterDefense())) - (getStrength()));
}
Thanks for your friendly input.
Favorite Quotes:Gandalf: You shall not pass!|Smeagol: We don''t need you!|Sloth: Hey you guys!|

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Since your using inhertance simply for naming conventions, ie. so you have a class named barbarian, etc.. I would recommend using the newer method.

If however your barbarian possessed certian attributes another character wouldn''t have then it would be appropriate to use inheritance so that the derived barbarian class had extra methods and variables to describe those attrbiuted unique only to the barbarian.

Thats my opinion anyway.

Share this post


Link to post
Share on other sites
I like the new one better.

However, I''d probably bundle the attributes into structs, and define different structs for the different classes. Something like:



struct CharacterData {
int health;
int intelligence;
int mana;
};

class CPlayer : private CharacterData {
std::string playerName_;
public:
CPlayer( char const * playerName, CharacterData const & classData ) : CharacterData( classData ), playerName_( playerName ) {}
};

static CharacterData const BarbarianInit = {
100, 20, 50
};
static CharacterData const WizardInit = {
20, 100, 70
};

static struct MultiInit {
CharacterInit const & cInit;
char const * cName;
}
const multiInit[] = {
// these could be made better with macros
{ BarbarianInit, "Barbarian" },
{ WizardInit, "Wizard" },
};

CPlayer * NewPlayer( char const * name, char const * className )
{
for( int ix = 0; ix < sizeof( multiInit )/sizeof( multiInit[0] ); ++ix ) {
if( !strcmp( multiInit[ ix ].cName, className ) ) {
return new CPlayer( name, multiInit[ ix ].cInit );
}
}
return 0;
}



Think "table driven" as much as possible. At some point, you''ll want to load the tables from some scripting language or XML file, rather than hard-code them, but as long as you go table driven in the code, the transition will be easier.

Share this post


Link to post
Share on other sites
Oh, and in general, inheritance of functionality usually breaks down.

For example, you may have an Entity, and then derive a LiveEntity and a DeadEntity, and then derive Door from DeadEntity and TalkingEntity from LiveEntity (to use for NPCs).

Somewhere down the line, you''ll want a door that''s also enchanted and asks for a password; i e it talks. Oops! Copy-and-paste time between TalkingEntity and TalkingDoor.

It''s much better, in my opinion, to use an interface-and-composition paradigm, where you derive from IWorldEntity, ITalker, IPathBlocker etc, and use some form of QueryInterface() on your base entity to find out whether you can talk to it.

Given fully known requirements up-front, you may be able to design a hierarchy that accounts for talking doors, but in game development, you don''t know the requirements up front, and you need to be flexible. If you go deep-inheritance, you''ll end up pushing functionality up towards the root, and in the end, you have CSwissArmyObject. Not good.

Share this post


Link to post
Share on other sites
I feel that in a good object oriented design you should always favor composition over inheritance. Inheritance leads to weak encapsulations while composition does not.

Only use inhetitance when your subclass "is a special kind of" your superclass. I don't feel that Barbarian is a special kind of Player.

Composition on the other hand covers the "is a role played by a"-situation. Barbarian is a role played by your Player object. Hence I feel it would be a much better design to use compostion in this case.

Further, with composition your player object can transmute from Barbarian to, for instance, Nercomancer. Again, you should NEVER use inheritance if your object needs to transmute to be an object in some other class.

As a closing remark, let me iterate: favor compositon over inheritance.


Of course, that's just me....



"Yeah, I would've killed you, but I'm glad I didn't - the paperwork is a bitch"

[edited by - rohde on November 7, 2003 9:05:03 PM]

Share this post


Link to post
Share on other sites