• Create Account

Need scary sound effects or creepy audio loops for your next horror-themed game? Check out Highscore Vol.3 - The Horror Edition in our marketplace. 50 sounds and 10 loops for only \$9.99!

### #Actualdmatter

Posted 13 November 2012 - 05:57 PM

As far as I know there is no case where a goto in C++ is the best tool for the job. I have never had cause to use it in C++ and I would not be overly happy to read or maintain code that uses it either.

Goto has a couple of uses, chiefly amongst them is making loops and exiting out of nested code. Instead it's better to prefer explicit loops and factoring nested code into functions which can be exited using return.

I combination of these alternatives can be applied to your function, including some minor restructuring that makes it a little cleaner:


void Combat::combatChoice(Character&amp;amp; C) {

if (C.health <= 0) {

cout << "----------------- You died... ------------------" << endl;

cout << "Oh dear, it seems you have died... Game Over." << endl;

return;

}

for (;;) {

cout << "----------------- Battle Options ------------------" << endl;

C.Display();

cout << "What do you want to do? \n"

<< "Type the number of the action and press enter. \n"

<< "[1] Melee Attack \n"

<< "[2] Gun Attack \n"

<< "[3] Health Potion" << endl;

short choice;

cin >> choice;

cout << "\n----------------- Battle Results ------------------" << endl;

switch (choice) {

case 1:

C.meleeAttack(M);

return;

case 2:

if(C.ammo > 0) {

C.gunAttack(M);

return;

}

cout << "You're out of ammo! \n" << endl;

break;

case 3:

if(C.potions > 0) {

C.useHP();

return;

}

cout << "You're out of potions! \n" << endl;

break;

default:

cout << "Whoops you choose an incorrect battle option, try again!\n\n";

}

}

}

So we've used an infinite loop which is basically saying "keep going till the user provides us with a workable option" (and such a thing would make a good code comment above the loop). Once a valid option has succeeded it exits from the function entirely using mid-function returns.

I find mid-function/early returns are often easier and clearer than using control variables to guide execution out of loops toward the end of a function. There are cases to be made either way.

I think rip-off's second example is better factored, more extensible and offers a superior experience for the user. An observation off the back of it is that having battle actions as member functions on a Character is slightly awkward as it involves a second abstraction for unifying the interface to them: f(C, M)
It may make sense to separate the action concept out as a first-class citizen, e.g. MeleeAttack::apply(Character & C, Monster & M);
Then just register all your Attack actions into the menu vector. You could add other member functions, such as one that predicates whether the action is even valid on the current menu (otherwise the menu code has to know something about what each attack requires).

### #4dmatter

Posted 13 November 2012 - 05:56 PM

As far as I know there is no case where a goto in C++ is the best tool for the job. I have never had cause to use it in C++ and I would not be overly happy to read or maintain code that uses it either.

Goto has a couple of uses, chiefly amongst them is making loops and exiting out of nested code. Instead it's better to prefer explicit loops and factoring nested code into functions which can be exited using return.

I combination of these alternatives can be applied to your function, including some minor restructuring that makes it a little cleaner:


void Combat::combatChoice(Character&amp; C) {

if (C.health <= 0) {

cout << "----------------- You died... ------------------" << endl;

cout << "Oh dear, it seems you have died... Game Over." << endl;

return;

}

for (;;) {

cout << "----------------- Battle Options ------------------" << endl;

C.Display();

cout << "What do you want to do? \n"

<< "Type the number of the action and press enter. \n"

<< "[1] Melee Attack \n"

<< "[2] Gun Attack \n"

<< "[3] Health Potion" << endl;

short choice;

cin >> choice;

cout << "\n----------------- Battle Results ------------------" << endl;

switch (choice) {

case 1:

C.meleeAttack(M);

return;

case 2:

if(C.ammo > 0) {

C.gunAttack(M);

return;

}

cout << "You're out of ammo! \n" << endl;

break;

case 3:

if(C.potions > 0) {

C.useHP();

return;

}

cout << "You're out of potions! \n" << endl;

break;

default:

cout << "Whoops you choose an incorrect battle option, try again!\n\n";

}

}

}

So we've used an infinite loop which is basically saying "keep going till the user provides us with a workable option" (and such a thing would make a good code comment above the loop). Once a valid option has succeeded it exits from the function entirely using mid-function returns.

I find mid-function/early returns are often easier and clearer than using control variables to guide execution out of loops toward the end of a function. There are cases to be made either way.

I think rip-off's second example is better factored, more extensible and offers a superior experience for the user. An observation off the back of it is that having battle actions as member functions on a Character is slightly awkward as it involves a second abstraction for unifying the interface to them: f(C, M)
It may make sense to separate the action concept out as a first-class citizen, e.g. MeleeAttack::apply(Character &amp; C, Monster &amp; M);
Then just register all your Attack actions into the menu vector. You could add other member functions, such as one that predicates whether the action is even valid on the current menu (otherwise the menu code has to know something about what each attack requires).

### #3dmatter

Posted 13 November 2012 - 05:56 PM

As far as I know there is no case where a goto in C++ is the best tool for the job. I have never had cause to use it in C++ and I would not be overly happy to read or maintain code that uses it either.

Goto has a couple of uses, chiefly amongst them is making loops and exiting out of nested code. Instead it's better to prefer explicit loops and factoring nested code into functions which can be exited using return.

I combination of these alternatives can be applied to your function, including some minor restructuring that makes it a little cleaner:


void Combat::combatChoice(Character&amp; C) {

if (C.health <= 0) {

cout << "----------------- You died... ------------------" << endl;

cout << "Oh dear, it seems you have died... Game Over." << endl;

return;

}

for (;;) {

cout << "----------------- Battle Options ------------------" << endl;

C.Display();

cout << "What do you want to do? \n"

<< "Type the number of the action and press enter. \n"

<< "[1] Melee Attack \n"

<< "[2] Gun Attack \n"

<< "[3] Health Potion" << endl;

short choice;

cin >> choice;

cout << "\n----------------- Battle Results ------------------" << endl;

switch (choice) {

case 1:

C.meleeAttack(M);

return;

case 2:

if(C.ammo > 0) {

C.gunAttack(M);

return;

}

cout << "You're out of ammo! \n" << endl;

break;

case 3:

if(C.potions > 0) {

C.useHP();

return;

}

cout << "You're out of potions! \n" << endl;

break;

default:

cout << "Whoops you choose an incorrect battle option, try again!\n\n";

}

}

}

So we've used an infinite loop which is basically saying "keep going till the user provides us with a workable option" (and such a thing would make a good code comment above the loop). Once a valid option has succeeded it exits from the function entirely using mid-function returns.

I find mid-function/early returns are often easier and clearer than using control variables to guide execution out of loops toward the end of a function. There are cases to be made either way.

I think rip-off's second example is better factored, more extensible and offers a superior experience for the user. An observation off the back of it is that having battle actions as member functions on a Character is slightly awkward as it involves a second abstraction for unifying the interface to them: f(C, M)
It may make sense to separate the action concept out as a first-class citizen, e.g. MeleeAttack::apply(Character &amp; C, Monster &amp; M);
Then just register all your Attack actions into the menu vector. You could add other member functions, such as one that predicates whether the action is even valid on the current menu (otherwise the menu code has to know something about what each attack requires).

### #2dmatter

Posted 13 November 2012 - 05:55 PM

As far as I know there is no case where a goto in C++ is the best tool for the job. I have never had cause to use it in C++ and I would not be overly happy to read or maintain code that uses it either.

Goto has a couple of uses, chiefly amongst them is making loops and exiting out of nested code. Instead it's better to prefer explicit loops and factoring nested code into functions which can be exited using return.

I combination of these alternatives can be applied to your function, including some minor restructuring that makes it a little cleaner:


void Combat::combatChoice(Character&amp; C) {

if (C.health <= 0) {

cout << "----------------- You died... ------------------" << endl;

cout << "Oh dear, it seems you have died... Game Over." << endl;

return;

}

for (;;) {

cout << "----------------- Battle Options ------------------" << endl;

C.Display();

cout << "What do you want to do? \n"

<< "Type the number of the action and press enter. \n"

<< "[1] Melee Attack \n"

<< "[2] Gun Attack \n"

<< "[3] Health Potion" << endl;

short choice;

cin >> choice;

cout << "\n----------------- Battle Results ------------------" << endl;

switch (choice) {

case 1:

C.meleeAttack(M);

return;

case 2:

if(C.ammo > 0) {

C.gunAttack(M);

return;

}

cout << "You're out of ammo! \n" << endl;

break;

case 3:

if(C.potions > 0) {

C.useHP();

return;

}

cout << "You're out of potions! \n" << endl;

break;

default:

cout << "Whoops you choose an incorrect battle option, try again!\n\n";

}

}

}

So we've used an infinite loop which is basically saying "keep going till the user provides us with a workable option" (and such a thing would make a good code comment above the loop). Once a valid option has succeeded it exits from the function entirely using mid-function returns.

I find mid-function/early returns are often easier and clearer than using control variables to guide execution out of loops toward the end of a function. There are cases to be made either way.

I think rip-off's second example is better factored, more extensible and offers a superior experience for the user. An observation off the back of it is that having battle actions as member functions on a Character is slightly awkward as it involves a second abstraction for unifying the interface to them: f(C, M)
It may make sense to separate the action concept out as a first-class citizen, e.g. MeleeAttack::apply(Character &amp; C, Monster &amp; M);
Then just register all your Attack actions into the menu vector. You could add other member functions, such as one that predicates whether the action is even valid on the current menu (otherwise the menu code has to know something about what each attack requires).

### #1dmatter

Posted 13 November 2012 - 05:52 PM

As far as I know there is no case where a goto in C++ is the best tool for the job. I have never had cause to use it in C++ and I would not be overly happy to read or maintain code that uses it either.

Goto has a couple of uses, chiefly amongst them is making loops and exiting out of nested code. Instead it's better to prefer explicit loops and factoring nested code into functions which can be exited using return.

I combination of these alternatives can be applied to your function, including some minor restructuring that makes it a little cleaner:


void Combat::combatChoice(Character& C) {

if (C.health <= 0) {

cout << "----------------- You died... ------------------" << endl;

cout << "Oh dear, it seems you have died... Game Over." << endl;

return;

}

for (;;) {

cout << "----------------- Battle Options ------------------" << endl;

C.Display();

cout << "What do you want to do? \n"

<< "Type the number of the action and press enter. \n"

<< "[1] Melee Attack \n"

<< "[2] Gun Attack \n"

<< "[3] Health Potion" << endl;

short choice;

cin >> choice;

cout << "\n----------------- Battle Results ------------------" << endl;

switch (choice) {

case 1:

C.meleeAttack(M);

return;

case 2:

if(C.ammo > 0) {

C.gunAttack(M);

return;

}

cout << "You're out of ammo! \n" << endl;

break;

case 3:

if(C.potions > 0) {

C.useHP();

return;

}

cout << "You're out of potions! \n" << endl;

break;

default:

cout << "Whoops you choose an incorrect battle option, try again!\n\n";

}

}

}

So we've used an infinite loop which is basically saying "keep going till the user provides us with a workable option" (and such a thing would make a good code comment above the loop). Once a valid option has succeeded it exits from the function entirely using mid-function returns.

I find mid-function/early returns are often easier and clearer than using control variables to guide execution out of loops toward the end of a function. There are cases to be made either way.

I think rip-off's second example is better factored, more extensible and offers a superior experience for the user. An observation off the back of it is that having battle actions as member functions on a character option is slightly awkward as it involves a second abstraction to unify a the interface to them: f(C, M)
It may make sense to separate the action concept out as a first-class citizen, e.g. MeleeAttack::apply(Character & C, Monster & M);
Then just register all your Attack actions into the menu vector. You could add other member functions, such as one that predicates whether the action is even valid on the current menu (otherwise the menu code has to know something about what each attack requires).

PARTNERS