It's been a month or so since I started learning C++ by myself online on youtube.
This is my first ever "game". I call it "game", because you don't do anything other than choose which attack you do, and there are just three enemies. You fight first a goblin, then a crocodile, then the boss. If you beat them, you win!
This is the latest version I made. In my first version, I made a class for each character, and I used rand() %
, and other things that I found out later to be bad.
I'd like to know how my code is, if there are any bad habits forming, or any error.
#include <iostream>
#include <random>
#include <string>
class Random {
private:
std::mt19937 gen;
public:
Random(unsigned int seed);
int number(int min, int max);
};
class Model {
private:
std::string name;
int health;
int attack;
int spattack1;
int spattack2;
public:
Model(std::string a, int b, int c, int d, int e);
friend void fight(int advType, int &spaCounter, Model &player, Model &enemy,
Random &rnd);
friend int getDamage(Random &rnd, Model &a, int advType, int &spaCounter);
friend bool isDead(Model &adv);
};
void fight(int advType, int &spaCounter, Model &player, Model &enemy,
Random &rnd);
int getDamage(Random &rnd, Model &a, int advType, int &spaCounter);
bool isDead(Model &a);
//--------------------------------------------------//
int main() {
std::random_device seed;
Random rnd(seed());
Model adv("Daniele", 30, 3, 7, 0);
Model goblin("Goblin", 4, 2, 0, 0);
Model crocodile("Crocodile", 9, 4, 7, 0);
Model boss("BigBoss", 25, 8, 11, 15);
int advType;
int spaCounter = 5;
std::cout << "THE FIGHT BEAGIN!" << '\n';
while (!isDead(adv)) {
do {
std::cout << '\n'
<< "1 Normal Attack - 2 Special Attack(" << spaCounter
<< ") : ";
std::cin >> advType;
} while (advType < 1 || advType > 2);
if (isDead(boss)) {
std::cout << "You Win!" << '\n';
return 0;
} else if (isDead(crocodile))
fight(advType, spaCounter, adv, boss, rnd);
else if (isDead(goblin))
fight(advType, spaCounter, adv, crocodile, rnd);
else
fight(advType, spaCounter, adv, goblin, rnd);
}
std::cout << "You are DEAD!" << '\n';
return 0;
}
//--------------------------------------------------//
Random::Random(unsigned int seed) : gen(seed) {}
int Random::number(int min, int max) {
std::uniform_int_distribution<int> dist(min, max);
return (dist(gen));
}
Model::Model(std::string a, int b, int c, int d, int e)
: name(a), health(b), attack(c), spattack1(d), spattack2(e) {}
void fight(int advType, int &spaCounter, Model &player, Model &enemy,
Random &rnd) {
// player attack
int damage = getDamage(rnd, player, advType, spaCounter);
enemy.health -= damage;
std::cout << player.name << " deals : " << damage << " to " << enemy.name
<< " -- health left : " << enemy.health << '\n';
if (isDead(enemy))
return;
// enemy attack
damage = getDamage(rnd, enemy, 0, spaCounter);
player.health -= damage;
std::cout << enemy.name << " deals : " << damage << " to " << player.name
<< " -- health left : " << player.health << '\n';
}
int getDamage(Random &rnd, Model &a, int advType, int &spaCounter) {
// crit
int crit = 1;
if (rnd.number(0, 99) == 99)
crit = 2;
// adv damage
if (advType == 1 && spaCounter == 0)
return (a.attack * crit);
else if (advType == 2 && spaCounter > 0) {
spaCounter--;
return (a.spattack1 * crit);
}
// enemy damage
int enemyType = rnd.number(0, 99);
if (enemyType > 94 && enemyType <= 99 && a.name == "BigBoss")
return (a.spattack2 * crit);
else if (enemyType > 79 && enemyType <= 99 &&
(a.name == "Crocodile" || a.name == "BigBoss"))
return (a.spattack1 * crit);
else
return (a.attack * crit);
}
bool isDead(Model &a) { return (a.health <= 0 ? true : false); }
-
1\$\begingroup\$ What you may and may not do after receiving answers. \$\endgroup\$Zeta– Zeta2017年09月09日 13:22:35 +00:00Commented Sep 9, 2017 at 13:22
1 Answer 1
I have looked over code and here are some notes
Item 1. Member vars - use some prefix of postfix to uniquely distinguish them
for example
std::string m_name;
or
int health_;
Use same coding conventions for all member vars for all your classes
Item 2.
Function parameters - give meaningful names. It is especially important when arguments have same type. a
, b
, c
, d
are horrible.
Item 3. Instead of friend functions use member functions
Item 4. Use const specifier as much as possible. For example isDead function will not modify the object - declare it as
bool isDead() const; //member function
Item 5.
Declare variables in the smallest scope possible as close to the usage as possible
For example advType
variable should be declared inside while
loop
while (!isDead(adv)) {
int advType;
do {
std::cout << '\n'
<< "1 Normal Attack - 2 Special Attack(" << spaCounter
<< ") : ";
std::cin >> advType;
} while (advType < 1 || advType > 2);
Item 6.
your fight function does 2 similar things enemy attack and player attack.
So it looks like you have to write function attacked
which will calculate the health of the object as a result of the attack from other object
fight
function will look like (it should not be friend - since it will use only public members of the Model
)
void fight(int advType, int &spaCounter, Model &player, Model &enemy,
Random &rnd) {
// player attack
enemy.attacked(rnd, player, advType, spaCounter);
if (enemy.isDead())
return;
// enemy attack
player.attacked(rnd, enemy, 0, spaCounter);
}
-
3\$\begingroup\$ 1. Decorating variables is a controversial choice. Most times, it just adds clutter. 2. Naming is for readability. Use the least you need to convey any relevant info. Yes, that specific example is bad. 3. The relevant gotw, monoliths unstrung. Take heed that it is only prefer, not use. \$\endgroup\$Deduplicator– Deduplicator2017年09月09日 12:46:14 +00:00Commented Sep 9, 2017 at 12:46
-
\$\begingroup\$ About point 2: if i decide to keep the member vars names unchanged, is this bad:
Model::Model(std::string name, int health, int attack, int spAttack1, int spAttack2) : name(name), health(health) ...
? \$\endgroup\$DiDi– DiDi2017年09月10日 13:16:19 +00:00Commented Sep 10, 2017 at 13:16 -
\$\begingroup\$ Compiler will understand it. I as programmer prefer to see slightly different names for parameters and members \$\endgroup\$Artemy Vysotsky– Artemy Vysotsky2017年09月10日 14:23:52 +00:00Commented Sep 10, 2017 at 14:23