• Advertisement
Sign in to follow this  

Need help with vectors and class structure...

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

Ok, here is my dilemma. I am attempting, slowly, to create a very simple 2D game. I currently have several classes set up. My problem is with when to create "players", and how to store them. I had everything working fine with arrays and structures, but now I want classes, for inheritence and methods, etc, and I also want to use vectors. Here is an example of a couple classes: This is all from memory, so some things may be slightly off.
Class BaseObject{
  BaseObject();
Public:
    GLfloat x;
    GLfloat y;..etc etc...
}

Class Player : BaseObect{
   Player();
  Public:
    GLfloat dx;
    // A few more attributes here...
    void init(){
       player.x = float(rand().....);
       // more stuff here
    }
}

Hang with me here, its been over a year since I did much C++ class stuff in school. My question is, where should I declare my vector? I want a vector to hold the players, so do I put vector<Player> myVector as a private variable in Player? I did this, but when i was in my main code, i couldn't do a for loop with myVector.size(). Also, how exactly do i go about initiating a new player? I want to add a new Player when i hit a keyboard button. So in my code for the 'm' button, should I do Player player;player.init(), then do a push_back in the init function to add it to myVector? Or should I just do all of that initiation stuff in the constructor, and pass the needed stuff in as variables? I hope this isn't too confusing. It's monday morning and my brain isn't all the way on yet. Jeff Edit: How do I get my code in a box, with the scrollbars on the side? [Edited by - geo2004 on June 25, 2007 10:09:11 AM]

Share this post


Link to post
Share on other sites
Advertisement
Quote:

Hang with me here, its been over a year since I did much C++ class stuff in school.
My question is, where should I declare my vector? I want a vector to hold the players, so do I put vector<Player> myVector as a private variable in Player? I did this, but when i was in my main code, i couldn't do a for loop with myVector.size().


The vector containing a list of players or other game obejcts should not go in the player class, it should go outside the player class. Common practice is to have some kind of class that represents the current state of the game; that's where the list of active players would be.

Quote:

Also, how exactly do i go about initiating a new player? I want to add a new Player when i hit a keyboard button. So in my code for the 'm' button, should I do Player player;player.init(), then do a push_back in the init function to add it to myVector? Or should I just do all of that initiation stuff in the constructor, and pass the needed stuff in as variables?

It is preferable to perform your initialization in the constructor and avoid "init" functions; it's more idiomatic C++. The constructor is supposed to bring the object into a known, usable state. The presence of "init" functions implies this isn't the case, so they should, in general, be discouraged. You should become comfortable with them before you explore the few potential reasons to consider abandoning them.

Share this post


Link to post
Share on other sites
You don't have to store the vector in your player class you can store it in another class.

When m is hit you can create a player and push_back it to the vector.

vector<Player> myVector;
if(keyPressed('m')){
Player newPlayer;
myVector.push_back(newPlayer); //this will create a copy of newPlayer
// and add it to vector.
}

If you don't want to store actual player objects in the vector you can store pointers to them.Which has some benefits later on when using polymorphism etc.


vector<Player*> myVector;

if(keyPressed('m')){
myVector.push_back(new Player());
}

If you store pointers have a look at shared and smart pointers to avoid dangling pointer problems in the future.


Share this post


Link to post
Share on other sites
Ok, so putting your suggestions together, i should create another class, to hold information for the game...like so..?


Class cGame{
cGame();
Public:
vector<*Player> myVector;
vector<*Item> myItems;
// etc.....

}



And when I initiate a player, it should be done like...


// This...?
// 'm' key hit...
myVector.push_back(new Player(put in needed attributes here));



And then change the constructor to initialize the needed attributes?

Thanks for the replies so far guys!

Jeff

[Edited by - geo2004 on June 25, 2007 10:47:55 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by geo2004
Ok, so putting your suggestions together, i should create another class, to hold information for the game...like so..?

*** Source Snippet Removed ***


'class' and 'public' should be in lowercase, and *'s in type names go *after* the name of the thing being pointed to.

Quote:
And when I initiate a player


When you *instantiate* it, yes.

Share this post


Link to post
Share on other sites
OK, I took home these ideas last night and added the necesarry code. However, I can't access my new vectors at all. Heres how it looks:

BaseObject and Player class same as before, just added constructor for Player.
Player(GLfloat X,GLfloat Y, GLuint TEX){assign necesary stuff here}

Then I added a Game class. it looks like this.

class cGame
{
public:
cGame(void);
vector<Player*> player;
vector<Item> item;
public:
~cGame(void);
};




however, when I try to instantiate a new Player, I can't do this:
Player temp(1.0f, 1.0f,1);
player.push_back(temp);

When I type player., it won't recognize that as a vector and won't pop up all the methods.

I'm including Player.h in my cGame class, and including cGame.h and Player.h in my main .cpp, as well as <vector> in all the .h files and cpp's. Any one see why this isn't working?

Thanks for the help so far!

Jeff

Share this post


Link to post
Share on other sites
Quote:

however, when I try to instantiate a new Player, I can't do this:
Player temp(1.0f, 1.0f,1);
player.push_back(temp);

player is a vector of Player*, but temp is a Player. The types are not compatible. You can change player to a std::vector<Player> and that will work, or you can change temp to: Player *temp = new Player(1.0f,1.0f,1); and that will work.

I would tend to recommend the former option, since otherwise you either have to manually free all the memory you new (by iterating the players container in the destructor of cGame and calling delete on every element), or use smart pointers (such as Boost's shared_ptr). Both involve more work than just correcting the type of the players container, and I'm not sure there is a need for you to store pointers in the list yet.

Quote:

When I type player., it won't recognize that as a vector and won't pop up all the methods.

Intellisense is not perfect. Deleting the .ncb files in your project folder will force a reparse of the Intellisense database which sometimes helps fix the problem. Which IDE are you using? Hopefully not VC++6...

Share this post


Link to post
Share on other sites
I'm using Visual Studio 2005 Express, C++.

I changed <Player*> to <Player>, and deleted the .ncb.

when I do player., it still doesn't pop anything up. So I went ahead and did player.push_back(temp), compiled it, and it says that its missing a specifier on that line - int assumed. It also has an error in my cGame.cpp, it says std::vector - no appropriate default constructor...?

This is a mess.....

Jeff

Share this post


Link to post
Share on other sites
It sounds like you don't actually have #include <vector> where you need it. You may also have missing brackets someplace. Can you post your code (actual code) and the exact error message?

Share this post


Link to post
Share on other sites
cGame.h code:

#pragma once
#include <windows.h>
#include "stdafx.h"
#include <stdlib.h>
#include <vector>
#include "BaseObject.h"
#include "Player.h"


using namespace std;

class cGame
{
public:
cGame(void);
vector<Player> player;
vector<Item> item;
public:
~cGame(void);
};



and my Player.h code:

#pragma once
#include <glut.h>
#include <math.h>
#include <ilut.h>
#include <il.h>
#include <vector>
#include "BaseObject.h"

using namespace std;

class Player :public BaseObject
{
public:
Player(GLfloat X,GLfloat Y, GLuint TEX){
x=X;
y=Y;
dx=X;
dy=Y;
alive=true;
selected=false;
tex=TEX;
}
GLfloat dx;
GLfloat dy;
public:
~Player(void);
int getX()
{
return x;
}
};



Then in my main .cpp, i do this:
Player temp(1.0f,1.0f,2);
player.push_back(temp);

Errors:
c:\...\thegame\cgame.cpp(7) : error C2512: 'std::vector' : no appropriate default constructor available
c:\...\thegame.cpp(21) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

Share this post


Link to post
Share on other sites
I still need to see the cGame.cpp code. And you might as well toss the player.cpp code up while you're at it. Here are some things I've noticed (most likely unrelated to the problem, but are issues worth pointing out):

1) #pragma once is not neccessarily the best way to do include guards, as it only works on some compilers. It should be fine for now, but you should be aware of its shortcomings. I suggest you read this article.

2) Remove all references to #include "stdafx.h" and remove stdafx.h and stdafx.cpp from your project. Go to the project settings, under C/C++, Precompiled Headers, and set "Use Precompiled Headers" to "Not Using Precompiled Headers.h" Precompiled headers should not be enabled by default; they can cause a lot of trouble for people who don't know how to use them, and unless you use them properly anyway, they give you no benefit.

3) It's <cstdlib> in C++, not <stdlib.h>.

4) Do not put "using namespace std;" in headers, as it effectively pollutes the global namespace and destroys the point of namespaces. You can explicitly qualify the namespaces as you need to (e.g., std::vector<whatever> instead of vector<whatever>).

5) I think the "c" prefix on your class is a waste of space and looks ugly.

6) You have "public:" multiple times in cGame, this is unnecessary.

7) Like with <stdlib.h>, the proper C++ include for the C math header is <cmath>.

8) Again: avoid using directives in headers, and you have a redundant public specifier.

9) Where is Item defined? In BaseObject.h? You use it in player.h but you have not seemed to declare/define it yet; the compiler will eventually complain about this.

Alas, none of this is a cause of your actual compiler error. I will need to see the rest of the code for that.

Share this post


Link to post
Share on other sites
Alright, I fixed your list:
1. Wasn't even sure what that did. It was there when i created the classes, so i left it. I'll read up on it.

2-4. Done.

5. Habit from school, although you can see I didn't do it for all my classes, lol, i need to change it.

6. Again, these double public:'s were there when i created the classes, just didn't remove them.

7-8.ok.

Item is a derived class of BaseObject. It will be used for things like weapons, etc.

I have a few questions, and I'll ask them as I show you the new code...
cGame.cpp code:

#include "cGame.h"
#include <vector>

cGame::cGame(void)
{
//Now that you've made me look at these, I know i need to declare my vectors, but is it the same as in my .h? isn't that redundant?
}

cGame::~cGame(void)
{
}



Player.cpp code (problems here)

// I had all this commented out. Since i'm defining my functions in my .h, I //don't have to do it here...do I? I remember back from one of my first C++ //courses (2 years ago in college), and we didn't have any .cpp files for our //classes.
/*#include "Player.h"

Player::Player(void)
{
}

Player::~Player(void)
{
}
*/




Thanks so much for your help so far jpetrie, i owe you one.
Bash my code all you want (i know its ugly,havn't done this in a couple years), it won't hurt my feelings, :).

Share this post


Link to post
Share on other sites
That's not all of cGame.cpp, is it? The lines that cause your compiler error are not there...

Quote:

Now that you've made me look at these, I know i need to declare my vectors, but is it the same as in my .h? isn't that redundant?

No. The vectors are declared in the class definition. Since they are non-static members, you don't need to do anything else to them in the constructors or anywhere else.

You also don't need to #include <vector> again in cGame.cpp. Remember that in C++, the compiler compiles translation units (in isolation). A translation unit is essentially a .cpp file after it's been fed through the preprocessor, so all #includes and #defines are resolved. Since cGame.cpp includes cGame.h, and cGame.h includes vector, the translation unit formed from cGame.cpp already has vector included.

IDEs pass files with expected C and C++ extensions (.c, .cpp, .cxx, .C, etc) to the compiler automatically, one at a time (you can actually control which extensions are considered source files in many IDEs). Header files are never directly seen by the compiler.

Share this post


Link to post
Share on other sites
Well, I'm not getting that constructor error about the vector anymore...but i still can't do a .push_back on it? I also can't use the method getX(one i just put in there to see if it worked) after i declare a new Player.

Yep, thats all of cGame.cpp.

K, so they way I see it. the .cpp files are pretty much only used to define methods, to make the .h files easier to read? i.e., you could have your function prototype: void eat(bla bla bla); in your .h.
Then in your .cpp, you would actually define the function.
Player::eat(bla bla bla){//Not exactly sure if thats correct syntax.
// do necessary stuff here...
}

correct? or no?

Jeff

Share this post


Link to post
Share on other sites
Quote:

Well, I'm not getting that constructor error about the vector anymore...but i still can't do a .push_back on it? I also can't use the method getX(one i just put in there to see if it worked) after i declare a new Player.

Yep, thats all of cGame.cpp.


There's no code anywhere there that is attempting to call push_back. There's hardly any code there at all. You've got to post the code for the file that has the error, the line that the error occurs on, and the exact error message. Otherwise I can only guess at potential problems. And there are a lot of options.

What do you mean when you say you can't "do a push_back on it?" What error do you get? Just because the Intellisense won't pop up anything doesn't mean you can't do it. Intellisense is not particularly 100% reliable.

Quote:

K, so they way I see it. the .cpp files are pretty much only used to define methods, to make the .h files easier to read? i.e., you could have your function prototype: void eat(bla bla bla); in your .h.
Then in your .cpp, you would actually define the function.
Player::eat(bla bla bla){//Not exactly sure if thats correct syntax.
// do necessary stuff here...
}

correct? or no?

Basically.

Share this post


Link to post
Share on other sites
My error is in my main .cpp code. When i created this project, i called it "TheGame", just cuz i was too lazy to think of a cool name. when i try to do player.push_back, it is in TheGame.cpp. Here is what some of that code looks like...

#include <windows.h>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <glut.h>
#include <cmath>
#include <ilut.h>
#include <il.h>
#include "cGame.h"
#include "BaseObject.h"
#include "Player.h"
#include "Item.h"
// Here is where i was doing my Player instantiation, just to see if it would work
// I put the errors after the line that they correspond to.
Player temp(1.0f,1.0f,2);
player.push_back(temp);// thegame.cpp(20) : error C2143: syntax error : missing ';' before '.' and...... error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

...
// A lot more random code here that I have to move to different places.
// Stuff like initializing players, etc, from when i was using structures and arrays.



Sorry i didn't put that up earlier. I guess i wasn't clear on the names of the .cpp files and the errors i was getting.

Share this post


Link to post
Share on other sites
I need you to post ALL of the code in that file. Every line.

The first error suggests you are missing a brace or semicolon somewhere above that first error. Or that those lines exist outside of any scope (they have to be in a function somewhere, they can't just be sitting there at global scope directly after your include statements. That's not legal.

Share this post


Link to post
Share on other sites
K, that may have been one problem, I didn't instantiate my player in a function, i was just trying to do it globally, just to see if it worked.

I moved it down into where I would have it, when the 'm' key is pressed, and i get these errors on that line:
error C2065: 'player' : undeclared identifier
error C2228: left of '.push_back' must have class/struct/union
see declaration of 'temp'

here is the code for TheGame.cpp. I'll omit most of the functions that are for drawing etc, for space reasons.


#include <windows.h>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <glut.h>
#include <cmath>
#include <ilut.h>
#include <il.h>
#include "cGame.h"
#include "BaseObject.h"
#include "Player.h"
#include "Item.h"

GLuint texture[8];
bool sound = true;
int i,j; // Generic loop variable
int k=0;
bool init = false;
GLdouble xm;
GLdouble ym;
#define PART 750
float slowdown=1.0f;
void initExplosion(); // forward declaration

typedef struct
{
...
}particles;

particles particle[PART];
void drawBots()
{
.....
}
void explosion()
{
.....
}
void drawItem()
{
....
}
void selection()
{
.....
}

void draw()
{
....
}


void initExplosion()
{
.....
}

void changeSize(int w, int h) {

....
}

void loadTextures()
{
....
}

void initScene()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
ilInit ();
ilutRenderer(ILUT_OPENGL);
ilEnable (IL_CONV_PAL);
ilutEnable (ILUT_OPENGL_CONV);

glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
//glShadeModel(GL_SMOOTH);
glEnable(GL_TEXTURE_2D);
loadTextures();
srand(time(0));
init = true;
}

void renderScene(void)
{
....
}
void mouse(int but,int state,int x,int y)
{
....
}
void normal(unsigned char key, int, int)
{
switch (key) {
case 'm' : Player temp(1.0f,1.0f,2);player.push_back(temp);break; //Got errors on this line....
}
glutPostRedisplay();
}

void main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(640,480);
glutCreateWindow("The Game");

if(!init)
initScene();
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutReshapeFunc(changeSize);

glutKeyboardFunc(normal);
glutSpecialFunc(pressKey);
glutSpecialUpFunc(releaseKey);
glutMouseFunc(mouse);

glutMainLoop();
}



Share this post


Link to post
Share on other sites
0) Your include order seems a little random and disorganized. No big deal, just commenting.

1) All of these globals are probably entirely unnecessary, and could be scoped more locally. i and j at global scope is particularly silly. You know you can declare variables within the for construct, right? for(int i = 0; i < X; ++i) ...

2) const int PART = 750; is preferred over #define PART 750 for constants. They're typesafe.

3) typedef struct is unnecessary in C++. struct particles { ... }; will work fine.

4) The function normal() does not declare "player," nor do you declare it at global scope. You have a player member in cGame, but that requires that you either access player via an instance of cGame (cGame game; game.player...) or that the function you are accessing player with is a member of cGame (void cGame::normal()...}).

Share this post


Link to post
Share on other sites
Thanks for the info on the #defines and whatnot.

I understand what you mean now that I have to go through an instance of game to get to player, (I did cGame game; game.player[0].blablabla, all worked fine).

This means I really need to sit down and think about the organization of my classes. Because even my GL and GLUT functions (which is where the normal() function comes in) need to be in some class, well, normal() anyways, not the GLUT functions themselves.

Would a way of doing this be structured kinda like this...
Base class Game.
Derived classes:
MouseInput
KeyboardInput

Then in my KeyboardInput class, i would have my normal function, which in turn could then instantiate my player correctly, and add it to the player vector?

Is my thinking on that correct? Do you know of any places I could go to read up on some good class structure/organization for 2D tile-based games?

Thanks so much for your help and patience jpetrie. I hope I didn't make you pull all your hair out!

Jeff

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement