deleting user define qGraphicItems after detecting collision - c++

I have a bullet class that I want to delete upon hitting anything but if it hits an enemy, I want it to delete the enemy as well. It was working on my desktop but upon switching to my laptop, it starts crashing whenever it removes. Currently my scene is outside in a different class in Dialog.cpp
here's my code:
bullet.cpp
void bullet::DoCollision()
{
QList<QGraphicsItem *> list = collidingItems() ;
foreach(QGraphicsItem * i , list)
{
if (i->type() == 3)
{
QGraphicsItem * item= i;
delete item;
qDebug() << "bye";
}
}
m_FireTimer->stop();
delete this;
}

You should use QGraphicsScene::removeItem(QGraphicsItem * item) which removes the item and all its children from the scene. You should hold a pointer to your scene in a variable like myScene.
Your code should be like:
void bullet::DoCollision()
{
QList<QGraphicsItem *> list = collidingItems() ;
foreach(QGraphicsItem * i , list)
{
if (i->type() == 3)
{
QGraphicsItem * item= i;
myScene->removeItem(item);
delete item;
qDebug() << "bye";
}
}
m_FireTimer->stop();
delete this;
}

Related

Having problems moving Snake in Qt

I am doing my very first snake game with Qt creator and I have been stuck for a long time in one single problem. I am using QGraphicsPixmapItem in QGraphicsScene.
Snake head should be different than other body. Now I need to delete all items from scene to draw snake new position to get it work, but I think it's not right way to code it.
How I suppose to update the snake without need delete QGraphicsPixmapItems all the time?
header
struct Point{
int x;
int y;
};
std::vector<Point> snakecore_;
QGraphicsPixmapItem* head_ = nullptr;
QGraphicsPixmapItem* core_ = nullptr;
cpp
delete head_
for(unsigned int i = 0; i < snakecore_.size(); ++i){
if(i == 0){
head_ = scene_.addPixmap(red_);
head_->setPos(snakecore_[i].x, snakecore_[i].y);
}
//Add rest of the snake
}
Moving a snake is quite simple: move the head in the desired direction. Then, move each part to the position of the previous part.
Use a QGraphicsGroupItem to create your snake, it will be simpler to handle the parts.
For example:
class Snake: public QGraphicsItemGroup
{
public:
enum Direction
{
Left,
Right
};
Snake(QGraphicsItem* parent=nullptr): QGraphicsItemGroup(parent), partCount(10)
{
int const partCount = 10;
for( int i = 0; i != partCount; ++i)
{
QGraphicsRectItem* part = new QGraphicsRectItem(QRectF(0, 0, 10, 10), this);
part->setPos((partCount - i) * 10, 0); // Create a snake from left to right
parts << part;
}
}
void move(Direction direction)
{
QPointF const offset = getOffset(direction);
QPointF previousPartPosition = parts.first()->pos();
parts.first()->setPos(parts.first()->pos() + offset);
for( int i = 1; i != partCount; ++i)
{
QGraphicsRectItem* part = parts.at(i);
QPointF const partPosition = part->pos();
part->setPos(previousPartPosition);
previousPartPosition = partPosition;
}
}
QPointF getOffset(Direction direction)
{
switch (direction) {
case Right:
return QPointF(10, 0);
case Left:
return QPointF(-10, 0);
}
}
private:
QList<QGraphicsRectItem*> parts;
int partCount;
};
Your question isn't completely clear, but you don't need to remove the item(s) from the scene to move a graphic item. Just set a new position on each item. They'll move and redraw in their new locations automatically.
Create the head and the body items initially (which you must already be doing), and then you don't need the "delete head_", nor the addPixmap. Just set the positions.

Using delete on pointers in a a vector

I am a hobby coder who is learning by trying to make a text-RPG game on the console. I am just trying to think about how to design my code right now, and I'm getting stuck on how the items and inventory classes will work together. I have the inventory class defined like so:
class Inventory {
private:
vector<Item*> items;
public:
Inventory() {
items.resize(10);
for (int i = 0; i < 10; ++i) {
items[i] = nullptr;//so I can still display an empty inventory
}
};
~Inventory() {
for (int i = 0; i < 10; ++i) {
delete items[i];
}
}
void AddItem(Item* item) {
for (int i = 0; i < items.size(); ++i) {
if (items[i] == nullptr) {//if the slot is empty
items[i] = item;
break;
}
}
}
void Show() const {
for (int i = 0; i < items.size(); ++i) {
cout << "Slot " << i + 1 << ": ";
if (items[i] == nullptr) {
cout << "<Empty Slot>" << endl;
} else {
cout << "<" << items[i]->GetName() << ">" << endl;
}
}
}
};
Eventually I'm planning on having enemies dropping loot when they die, so I'll need to create items using new and then transfer them into the player's inventory. My question is, should I just learn about smart pointers and use them, or is the way I've called delete here okay or completely stupid? Or should I be thinking about this code structure differently? Thanks for answering, if you do! I really appreciate it.
The correct method would be to use iterators. Don't pass pointer of 'Item' in
void AddItem(Item* item) method.
You should create an iterator of 'Item' class and pass this iterator to "AddItem" method. Similarly create another method "RemoveItem" that returns an iterator of 'Item' that can be sent to Player's "CollectMoney" method.
If you don't want to use iterators, you can use "Item * item" as well but you have to call a method "RemoveItem" to get the reference of the "Item" so you can pass it to Player. Since the Items are not created inside the class, they should not be deleted in the class so remove the destructor.
PS use this constructor -> Inventory() {items.resize(10,nullptr);}

Memory in use issue using marmalade SDK

I have a bullet class. and I try to instantiate it by the following code:
I always get an assertion that there is a memory that is in use.. why?
In another class called ship:
if (g_Input.isKeyDown(s3eKeySpace))// && Canfire)
{
Bullet *bullet = new Bullet();
bullet->Init(SHIP_BULLET);
bullet->setPosition(Position.x, Position.y - 20);
Bullets->push_back(bullet);
Canfire = false;
}
This is called each frame which causes memory still in usage:
for (list<Bullet*>::iterator it = Bullets->begin(); it != Bullets->end();)
{
(*it)->Update(dt);
if ((*it)->IsDestroyed)
{
Canfire = true;
it = Bullets->erase(it);
}
else
{
it++;
Canfire = false;
}
}
the destructor of the Ship class
Ship::~Ship()
{
for (std::list<Bullet*>::iterator it = Bullets->begin(); it != Bullets->end(); ++it)
delete *it;
delete Bullets;
}
class Bullet
{
public:
Bullet();
~Bullet();
public:
void Init(BulletTypes bulletType);
void Update(float dt);
void Render();
CIw2DImage* Image; // curr image
}
void Bullet::Init(BulletTypes bulletType)
{
BulletType = bulletType;
if (BulletType == SHIP_BULLET)
{
Image = Iw2DCreateImage("textures/ship_bullet.png");
if (Image == nullptr)
return;
}
}
Bullet::~Bullet()
{
delete Image;
}
Executing this code causes the leak:
for (list<Bullet*>::iterator it = Bullets->begin(); it != Bullets->end();)
{
(*it)->Update(dt);
if ((*it)->IsDestroyed)
{
Canfire = true;
it = Bullets->erase(it);
}
else
{
it++;
Canfire = false;
}
}
What is going on is basically you removing a dynamically allocated element from a container, losing any reference to it thus you cannot free its memory anymore. Calling Ship destructor only frees the elements that are currently in the list, excluding the ones removed in the iteration, obviously.
I suggest this as a fix:
for (list<Bullet*>::iterator it = Bullets->begin(); it != Bullets->end();)
{
(*it)->Update(dt);
if ((*it)->IsDestroyed)
{
Canfire = true;
delete *it; // it now points to invalid address
it = Bullets->erase(it);
}
else
{
it++;
Canfire = false;
}
}
Another option would be to store all removed bullets in some other container in class Ship in case that a Bullet can be referenced after it was destroyed. Problem with this idea is that you have alot of destroyed bullets taking up memory and have to come up with a solution on how to remove them once they really prove useless.
If you get stuck with that, using std::shared_ptrs instead of raw pointers in the list could solve your issue (for slight performance penalty).

C++ How to enumerate QGraphicsItem's?

Using this function, I can delete selected QGraphicsItem's from a QGraphicsView.
How can I get my ellipses enumerated in order to receive a notification like "Deleted ellipse n°...".
void MainWindow::deleteItem()
{
foreach (QGraphicsItem *item, scene->selectedItems()) {
if (item->type() == ellipse->Type) {
scene->removeItem(item);
delete item;
QMessageBox::information(this,"Notification", "Deleted");
}
}
}
A few ways
Assuming you only care about that iteration:
int ix = 0; // add this
foreach (QGraphicsItem *item, scene->selectedItems()) {
if (item->type() == ellipse->Type) {
scene->removeItem(item);
delete item;
std::cout << "Deleted ellipse number " << ix++ << std::endl; // and add this
QMessageBox::information(this,"Notification", "Deleted");
}
}
The above only works if your ordering only corresponds to that foreach() loop. If your items are in some arbitrary order:
std::unordered_map<QGraphicsItem*, int> mGraphicsItems;
That's assuming you can populate it, of course. If you can, do a lookup before calling delete(), to get the value which is the enumeration. Not very elegant though, and adds space.
Other way is to subclass QGraphicsItem [Untested code but you get the idea]
class MyGraphicsItem : public QGraphicsItem
{
Q_OBJECT
public:
// snip
int index() const { return mIndex; }
void setIndex( int i ) { mIndex = i; }
private:
int mIndex;
};
Just set the index in whatever way you want when the QGraphicsItem is created, and before calling delete, print out (or do whatever) with item->index();

C++ pointer linked list

So I am new to c++ sorry if this is not to clear.
I have a class:
class Item
{
int noItem;
int qItem;
public:
Item(int noItem, int qItem)
{
this->noItem = noItem;
this->qItem = qItem;
}
int getNoItem()
{
return noItem;
}
int getQntItem()
{
return qItem;
}
};
Then the following class:
class Element
{
public:
Element()
{
data = NULL;
}
//to set and access data hold in node
void setElement(Item *data)
{
this->data = data;
}
Item* getElement(void)
{
return(data);
}
private:
Item *data;
};
This one also:
class ListeChainee
{
public:
ListeChainee()
{
courant = NULL;
}
void ajoutListe(Item *data)
{
Element *newData;
//set data
newData->setElement(data);
//check if list is empty
if( courant == NULL)
{
//set current pointer
courant = newData;
}
}
//get data from element pointed at by current pointer
Item* elementCourant(void)
{
if(courant != NULL)
{
return courant->getElement();
}
else
{
return NULL;
}
}
private:
//data members
Element *courant; //pointer to current element in list
};
The code is missing some stuff for other things, but my problem is this:
int main(int argc, char* argv[])
{
ListeChainee listeCH;
Item i1(123,456);
listeCH.ajoutListe(&i1);
cout << listeCH.elementCourant()->getNoItem();
system("pause");
return 0;
}
I expect 123 to be outputted, but I see some other number. Not sure why.
Thanks.
Your Element *newData doesn't have an instance of Element class, so it will crash when you try to access the instance pointed by newData.
Try to change Element *newData; to Element *newData = new Element;.
ps.: Don't forget to delete it when you don't need the instance any more.
This method is writing to uninitialized memory:
void ajoutListe(Item *data)
{
Element *new;
//set data
new->setElement(data); // Right here, "new" is an uninitialized pointer
//check if list is empty
if( courant == NULL)
{
//set current pointer
courant = new;
}
}
I'm surprised this compiles (does it?). This code should also crash.
The strange number you're getting is surely some random part of memory. You may want to think more about memory management -- there are numerous problems here. When ajoutListe is called, why does the courant member only get set if it's NULL? Do we just leak the new Element? How do we actually traverse this list?