Hi, I'm rather new to C++ programming and I've ran into a problem.
In the following the user is promted to enter the number of enemies he is to face.
I now need to create enemy objects equal to the user input, but my original idea doesn't work.
#include <iostream>
#include <cstdlib>
#include <ctime>
usingnamespace std;
//game variables
unsignedint nTraps;
unsignedint nEnemies;
const string enemyName [] = { "enemy01", "enemy02", "enemy03", "enemy04", "enemy05", "enemy06", "enemy07", "enemy08", "enemy09", "enemy10"};
//some functions and classes excluded at the moment
void seedRandom () {
srand((unsigned)time(0));
}
class Enemy
{
public:
Enemy(string n);
~Enemy();
void showStats ();
protected:
int coordX;
int coordY;
int health;
int attack;
int defence;
int damage;
string name;
};
Enemy::Enemy(string n) {
health=90+(rand()%21);
attack=10+(rand()%5);
defence=10+(rand()%5);
damage=10;
name=n;
}
Enemy::~Enemy() {}
void Enemy::showStats() {
cout<<"Health is: "<<health;
cout<<"\nAttack is: "<<attack;
cout<<"\nDefence is: "<<defence;
cout<<"\nDamage is: "<<damage;
cout<<"\nName is: "<<name<<endl;
}
int main ()
{
seedRandom();
unsignedint userInput = 0;
bool enemiesSet = false;
do {
cout<<endl<<"Please enter number of enemies (min. 3, max. 10)";
cin>>userInput;
if (userInput<3 or userInput>10) { cout<<"Bad input!"; }
else {
nEnemies = userInput;
enemiesSet = true;
}
} while (!enemiesSet);
for (unsignedint x=0; x<nEnemies; x++) {
Enemy enemyName[x] (enemyName[x]); //Enemy constructor looks like this: Enemy(string n);
enemyName[x].showStats();
}
}
I'm getting this compile error (using code::blocks): error: variable-sized object 'enemyName' may not be initialized
c::b states the compile error is in line 68.
Any good suggestions on how to name the objects would be highly appreciated.
You're not really using the whole [x] notation right there.
A problem I can see is that your Enemy objects will only be declared locally within the for loop and will then be destroyed when it finishes. Perhaps create a vector of pointers to enemies and store them in there.
1 2 3 4 5 6 7
std::vector<Enemy*> enemies;
for (unsignedint x=0; x<nEnemies; x++) {
Enemy *enemy = new Enemy(enemyName[x]);
enemies.push_back(enemy);
enemy->showStats();
}
To create an array at run-time, you'll have to do some manual labour; that is, DMA (Dynamic Memory Allocation). For you, you'll need something like this:
1 2 3 4 5
int RequestedNoOfEnemies(5);
Enemy *ArrayOfEnemies(new Enemy[RequestedNoOfEnemies]);
//...
delete [] ArrayOfEnemies;
Instead of pointing at the class objects, you assign them to a vector of class objects?
Is it possible to access the objects simply using Enemy[x].classfunction?
No offense, but I can't figure out what I need the last part for.
Yea, if Enemy is an array of some objects that have the classfunction that's exactly what you do. Note that pushing the objects (not pointers) into the vector is better (for this program), then you don't need to delete the pointers later.
"Instead of pointing at the class objects, you assign them to a vector of class objects?"
Yes, as Mathhead200 said. Internally, the std::vector allocates 1 big chunk of memory where it will store its objects in a consecutive manner.
AbR wrote:
"Is it possible to access the objects simply using Enemy[x].classfunction?"
That's one way, but it's no safe. The safe way to access a std::vector is through std::vector::at(): A function that validates the given offset. If the offset exceeds the number of objects in the vector, it'll throw an exception. However, the sub-script operator ([]) doesn't perform these checks; thus, allows you to write past the last object.
AbR wrote:
"No offense, but I can't figure out what I need the last part for."
It creates an array dynamically. Commonly used to create an array, whose length is determined at run-time, which cannot be done with static arrays. Consider it a less superior alternative to the std::vector.
It creates an array dynamically. Commonly used to create an array, whose length is determined at run-time, which cannot be done with static arrays. Consider it a less superior alternative to the std::vector.
Lucky punch - this is exactly what I need to create the game map based on user input during runtime.
@Framework
Thanks for the input, but this is beyond my skills at the moment.
I have work-around-method that I'll use, and then focus on the classes, which was my primary goal for writing this small game, which now also includes a vector of objets. If I top it with more code I'm unfamiliar with, I might get lost in my own code :-)
I'll keep a link to your example for when I get a better understanding of it.
---
A separate question regarding the vector of objects:
Let say that vector Enemies holds 4 object of type Enemy like this:
Enemies[0] = enemy01
Enemies[1] = enemy02
Enemies[2] = enemy03
Enemies[3] = enemy04
... and enemy02 is killed by the player. I was thinking I should destroy the object with the destructor (~Enemies.at(1)).
After the object is gone, is Enemies.at(1) now empty or will it hold enemy03 (and Enemies.at(2) holding enemy04) or will I need to use Enemies.erase(1) to remove the empty space?
"I was thinking I should destroy the object with the destructor "
Never call the destructor unless you're using placement new. You can call it, but the std::vector would invoke it again which leads to erratic behaviour.
When you erase an object from a std::vector, all objects on the right-hand side are moved 1 place to the left; thus fill the gap.