1

I'm creating a 2D game using the Qt Framework. Although I do have some experience in some other languages, C++ is a kind of new language for me.

My first question is about the monsters. How should I initialize(and store them) ? Every level of my game has a different number of mobs. At this moment I initialize them in this way:

    Monster *mobs;
    mobs = new Monster[mobsQuantity];

But I am not sure this is the best way to do it. Also, every second, every mob positioned on the map must move by 1 position. This is the function that should move the mobs.

void MainWindow::moveMobs(){

int random[mobsQuantity]; // Different random position move for each monster.

for(int a = 0; a < mobsQuantity; a++){
    random[a] = qrand() % 5; // Initialize the moves
}

for(int a = 0; a < mobsQuantity; a++){
    int x = mobs[a].x(); 
    int y = mobs[a].y(); // Take the position for each different mob

    switch(random[a]){
    case NORTH:
        // Collision detection and movement
    break;
    case SOUTH:
        // Collision detection and movement
    break;
    case WEST:
        // Collision detection and movement
    break;
    case EAST:
        // Collision detection and movement
    break;
        }
    }
}

Is there any better way to do this?

My 2nd problem is passing the Monster class to a function. Monster is derived from QGraphicsItem. I have a function in the Main Window which sets the right position for each mob and then add it to the QGraphicsScene. My code looks like this:

void MainWindow::createMobs(){
for(int a = 0; a < mobsQuantity; a++){
    mobs[a].setPos(/* X pos */ , /* Y pos */);

    scene->addItem(mobs[a]);
}

}

The error comes from adding the item to the scene. How should I properly pass an element of a dinamically allocated array as a pointer ?

 error: no matching function for call to 'QGraphicsScene::addItem(Monster&)'

I tried adding it like this:

   scene->addItem(&mobs[a]);

But my program crashes.

Thanks for everyone who will try to help me.

Andre Popa
  • 63
  • 1
  • 1
  • 3

2 Answers2

1

@Austin is right in that using a vector or list would be much better for you to use than a plain array, though I'd use a QVector rather than std::vector if you're using Qt. Both work, but that's my preference.

Also, games in C++ often use an architecture of objects updating themselves in an update loop. So you'd have a main game loop that just calls an update function for the Monsters. Something like this skeleton code: -

class Monster : public QGraphicsObject // note QGraphicsObject instead of Item so we have signals and slots too!
{
    void Update()
    {
         // move the monster according to rules
         // check for colliding objects
    }
};

Then in your main game loop

QList<QMonster*> pMonsterList = GetMonsters(); // from CLevel shown by @Austin
QMonster* pMonster;
foreach(pMonster, monsterList)
{
    pMonster->Update();
}

Now, if you create a base class, let's call it GameObject which is derived from QGraphicsObject you can then have all moveable objects run with the same architecture.

class GameObject : public QGraphicsObject
{
    virtual void Update() = 0; // move object
};

class Monster : public GameObject
{
    void Update();
};

So you'd now just update all objects from the level with something like this: -

CLevel::Update()
{
    QList<GameObject*> gameObjectList = GetGameObjects();
    GameObject* pGameObj;
    foreach(pGameObj, gameObjectList)
    {
        pGameObj->Update();
    }
}
TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • Hi, thanks for the help ! I'll try using the architecture you gave me. But where can I find that foreach() function ? std::for_each() is a bit different. – Andre Popa Jul 25 '13 at 02:39
  • It's part of Qt and listed in the help on Container classes, though maybe it's just Qt5. Alternatively you could just use a for loop to run through all the objects. – TheDarkKnight Jul 25 '13 at 07:53
  • Instead of raw pointers I'd recommend using smart pointers. I'm not 100% sure but I guss what holds true to std::vecotr also goes for QVector: Always prefer vector over every other collection if you don't have a good reason to use something else. std::vector has a way better performance than std::list. In most cases a vector is pretty fine. – Skalli Jul 25 '13 at 09:03
  • @Skalli, you're probably right as far as std is concerned, though Qt has an object hierarchy which pretty much takes care of management of pointers to its objects, so reduces the need for smart pointers. As for list vs vector, I've read that QList is the preferred container in Qt. If you're interested, the top answer to this question explains more about Qt containers: http://stackoverflow.com/questions/6602036/qvector-vs-qlist – TheDarkKnight Jul 25 '13 at 09:06
  • I suppose you are right, I haven't dug that deep in Qt. It was just an assumption and meant as a hint in case he decides to use std::vector. Still, it's interesting that QList is the prefered container in Qt. Is there any source for this? (Not that I don't believe you, I do, but I want to extend my knowledge and the reasons.) ;) – Skalli Jul 25 '13 at 09:12
  • If you Google for QList vs QVector there's quite a lot of discussion about it. Also, in Qt docs for QList it makes the following 2 statements: "For most purposes, QList is the right class to use. Its index-based API is more convenient than QLinkedList's iterator-based API, and it is usually faster than QVector because of the way it stores its items in memory. It also expands to less code in your executable...If you want the items to occupy adjacent memory positions, use QVector." – TheDarkKnight Jul 25 '13 at 09:38
  • I tried this architecture and seems my Monster class is not aware of the Map class, in which I'm storing the map, so I couldn't do the collision detection, lol. – Andre Popa Jul 26 '13 at 14:56
  • What is the map that you're storing for collision detection? This just sounds like you need to think more about the design of your classes. Can the Map class be a singleton? If not, then I'm sure you can find a way of making it available for the Monster class. – TheDarkKnight Jul 26 '13 at 14:59
0

Seems like using std::vector<Monster*> or qvector<Monster*> is the best bet. Example:

 //header example for CLevel
 class CLevel:
      CLevel();
      std::vector<Monster*> *GetMonsters() {return &mMonsterVector;}
      void CreateMonsters(int NumberOfMonsters);

 private:
      std::vector<Monster*> mMonsterVector;

 };

 //cpp file
 void CLevel::CreateMonsters(int NumberOfMonsters){
       //make this a method in the level class

      for(int i = 0; i < NumberOfMonsters; i++){
           Monster *newMob = new Monster;
           //Fill in the monster properties
           newMob->FillProperties();
           //end monster properties
           mMonsterVector.push_back(newMob);
      }
 }

For the 2nd question, it is hard to diagnose without seeing all the code, but if the code is crashing after passing a pointer (which &array[a] is), then the pointer doesn't exist or hasn't been initialized or has been de-initialized. Perhaps the array was allocated in a function that has been de-allocated after the function is called since the compiler cleaned it up.

Austin
  • 1,018
  • 9
  • 20