Массив получает два одинаковых значения - PullRequest
0 голосов
/ 19 февраля 2020

Извините, если код неаккуратный, я работаю с QT только последние пару недель. Во время учебы я работаю над небольшой игрой, и сейчас я работаю над тем, когда игрок покупает предмет из магазина, он помещает его в сумку для персонажа.

Проблема в том, что когда я покупаю товар один раз, он работает нормально. Но если я удаляю элемент после покупки, затем выкупаю тот же элемент снова, он помещает два одинаковых элемента в массив, даже если я приобрел один.

У меня есть 3 файла, использованных для этого. Inventory.cpp, GameScreen.cpp, Shops.cpp.

GameScreen.cpp - это основной файл. Здесь я просто все инициализирую.

void GameScreen::initGame(QString &characterName, QString &characterProfession){
    //PASS CHARACTERNAME AND CHARACTERPROFESSION INTO INVENTORY
    inv.initCharacter(characterName, characterProfession);
    //INIT BAG
    inv.initBag();
    //INIT MONEY
    inv.initMoney();
    //SHOPS INITS
    mos.initShop();
    mos.passMoneyToShop(inv.gold, inv.silver, inv.copper);
}

Откроется окно магазина. Подключение предмета является частью моей проблемы.

void GameScreen::on_mapOneShopB_clicked()
{
    mos.setModal(true);

    //SEND THE ITEM INTO BAG
    connect(&mos, SIGNAL(getItemFromMapOneShop(const QString&)), &inv, SLOT(bagAddElement(const QString&)));

    mos.show();
    mos.exec();
}

Переезд в Shops.cpp. Я использую полиморфизм в этом файле, и именно поэтому вы видите MapOneShop:: вместо Shops::. Извините за путаницу. Но, двигаясь дальше, я нажимаю кнопку, и она вычитает цену предмета из моего количества золота.

void MapOneShop::on_buyB_clicked()
{
    //ONLY WORKS IF I HIT THE ITEM NAME COLUMN THEN HIT BUY
    gold -= itemPrice[ui->treeWidget->currentColumn()];

    //UPDATE INFORMATION
    updateInformationVAndMoneyAfterBuy();

}

Затем он переходит в updateInformationVAndMoneyAfterBuy();, который проверяет, что я потратил деньги, и, если я это сделаю, выдаст нужный мне предмет. Я просто излучаю обратно в GameScreen.cpp внутри void GameScreen::on_mapOneShopB_clicked() и передаю их в Inventory.cpp.

void MapOneShop::updateInformationVAndMoneyAfterBuy()
{
    //UPDATE INFORMATIONV FIRST TO CHECK MONEY CHANGES

    if(goldCheck != gold)
    {
        emit getUpdatedMoneyFromShop(gold, silver, copper);

        //ITEM NAME IS WHERE I STORE THE NAMES OF THE ITEMS
        emit getItemFromMapOneShop(this->itemName[ui->treeWidget->currentColumn()]);
    }
}

Теперь перехожу в Inventory.cpp. Когда элемент передается в bagAddElement после удаления, а затем выкупа, я получаю два одинаковых элемента, даже если нужно передать только 1. Для этого я использую динамический массив c. Ниже я также покажу функции void Inventory::on_deleteB_clicked, void Inventory::bagDeleteAt, а также void Inventory::bagLWPrint. Значение items - это мой массив, содержащий строки shopItem.

void Inventory::bagAddElement(const QString& shopItem)
{
    //I USE THIS TO CHECK THE VALUE shopItem.
    qDebug()<<"bagAddElement: " << shopItem;

    //IF THE CURRENT POSITION IN THE BAG
    //IS BIGGER THAN THE CURRENT SIZE
    //IT WILL INCREASE THE BAG FOR US
    if(nrOfEl >= bagSize)
    {
        bagExpand();
    }

    //CHECK FOR VALUES INSIDE ARRAY AND CHECK IF THEY ARE NULL
    //IF SO, IT WILL ADD THE ITEM INTO THE NULL POSITION
    for(int i = 0; i < bagSize; i++)
    {
        if(items[i] == nullptr)
        {
            nrOfEl = i;
            items[nrOfEl++] = shopItem;
            break;
        }
    }

    //UPDATE WIDGET LIST
    bagLWPrint();
}

Здесь я передаю текущее выбранное значение строки внутри bagLW и передаю его в void Inventory::bagDeleteAt.

void Inventory::on_deleteB_clicked()
{
    //BagLW IS A LIST WIDGET
    bagDeleteAt(bagLW->currentRow());
}

Теперь мы ищем что внутри items[row] и устанавливаем его в nullptr. Затем мы go в void Inventory::bagLWPrint.

void Inventory::bagDeleteAt(int row)
{
    if(items[row] == nullptr)
    {
        //IF THE ITEM IS ALREADY NULL WILL PRINT A MESSAGE
        QMessageBox::information(this,"Bag","No item in that slot");
    }
    else
    {
        //SET CURRENTLY SELECTED ITEM TO NULL
        items[row] = nullptr;
        bagLWPrint();
    }
}

Я очищаю bagLW и пополняю его обновленным массивом.

void Inventory::bagLWPrint()
{
    bagLW->clear();
    for(int i = 0; i < bagSize; i++)
    {
        if(items[i] != nullptr)
        {
            bagLW->addItem(items[i]);
        }
        if(items[i] == nullptr)
        {
            bagLW->addItem(items[i]);
        }
    }
}

Другие примечания.
- Элемент удваивается только при вставке в void Inventory::bagAddElement.
- Я пытался добавить еще один элемент внутри void GameScreen::initGame, и он не удваивался после удаления и повторного ввода.

Извините за такой длинный вопрос. И любая помощь будет очень, очень ценится.

void Inventory::bagExpand()
{
    //1: INCREASE BAGSPACE
    bagSize *= 2;
    //2: CREATE TEMP ARRAY
    QString *tempItems = new QString[bagSize];
    //3: COPY OVER VALID VALUES FROM OLD ARRAY
    for(int i = 0; i < nrOfEl; i++)
    {
       tempItems[i] = items[i];
    }
    //4: DELETE OLD ARRAY MEMORY
    delete[] items;
    //5: POINT OLD ARRAY POINTER TO NEW ARRAY LOCATION
    items = tempItems;
    //PRINT BAGLW - (UDPATE)
    bagLWPrint();
    qDebug()<<"Bag has increased";
}

1 Ответ

2 голосов
/ 19 февраля 2020

Проблема в том, что вы подключаете и повторно подключаете сигнал getItemFromMapOneShop при каждом нажатии кнопки. Это означает, что при первом нажатии вы добавляете его один раз (сигнал срабатывает, 1 слот подключен). При втором щелчке вы добавляете его дважды (сработал сигнал, подключено 2 слота). И так далее.

QObject s управляет списком всех подключенных слотов для каждого сигнала и вызывает каждый из них. Соединение слота несколько раз вызовет его так много раз

Вы должны подключить сингал только один раз, например, в конструкторе; или отключите сигнал, когда он больше не используется

Как заметил @ Andéon Evain, вы также можете использовать Qt::UniqueConnection. Это не добавит дублирующееся соединение, если оно уже существует (с учетом отправителя, сигнала, получателя, слота). Это может быть полезно в тех случаях, когда оно неизвестно, если оно уже подключено; не в вашем простом случае

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...