Home > Net >  Delete an instantiation of a class inside of the class itself once a condition is met
Delete an instantiation of a class inside of the class itself once a condition is met

Time:01-14

I am making an infinite runner game on a 16x2 LCD display in Arduino.

The enemies crawl to the left across the screen and when they reach the end I want the instance of the enemy class to be deleted but I don't know how. I want it to delete itself inside of the update function once the x position gets to zero.

Anyway heres my code:

The class:

class Enemy {
private:
  int xPos, yPos;
public:
  Enemy::Enemy(int xPos, int yPos) {
    this->xPos = xPos;
    this->yPos = yPos;
  }

  draw() {
    lcd.setCursor(xPos, yPos);
    lcd.print("E");
  }

  move() {
    //erase enemy at last position
    lcd.setCursor(xPos, yPos);
    lcd.print(" ");
    //move enemy
    xPos--;
    if(xPos == 0){
      delete(this);
    }
  }
};

and here's the rest:

#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 7, en = 8, d4 = 9, d5 = 10, d6 = 11, d7 = 12, buttonPin = 2;
LiquidCrystal lcd = LiquidCrystal(rs, en, d4, d5, d6, d7);
unsigned int playerYPos = 1, buttonPrevious;
const long playerUpdateInterval = 32, enemyMoveInterval = 500;
unsigned long lastUpdatedPlayerMillis = 0, lastMovedEnemiesMillis;



class Enemy {
private:
  int xPos, yPos;
public:
  Enemy::Enemy(int xPos, int yPos) {
    this->xPos = xPos;
    this->yPos = yPos;
  }

  draw() {
    lcd.setCursor(xPos, yPos);
    lcd.print("E");
  }

  move() {
    //erase enemy at last position
    lcd.setCursor(xPos, yPos);
    lcd.print(" ");
    //move enemy
    xPos--;
    if(xPos == 0){
      delete(this);
    }
  }
};

Enemy e(15, 1);

void drawPlayer() {
  lcd.setCursor(1, playerYPos);
  lcd.print("P");
}



void updatePlayer() {
  uint8_t button = digitalRead(buttonPin);
  //check if button is pressed
  if (button == LOW && buttonPrevious == HIGH) {
    //erase player at last position
    lcd.setCursor(1, playerYPos);
    lcd.print(" ");
    //move player
    playerYPos = 1 - playerYPos;
  }
  buttonPrevious = digitalRead(buttonPin);
}

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  //initialize the pushbutton pin
  pinMode(buttonPin, INPUT_PULLUP);
  buttonPrevious = digitalRead(buttonPin);
  Serial.begin(9600);
}

void loop() {

  unsigned long currentMillis = millis();
  //update player 30 times a second
  if (currentMillis - lastUpdatedPlayerMillis >= playerUpdateInterval) {
    //reset counter since last updated
    lastUpdatedPlayerMillis = currentMillis;
    updatePlayer();
  };
  //move enemies ??? times a second
  if(currentMillis - lastMovedEnemiesMillis >= enemyMoveInterval) {
    lastMovedEnemiesMillis = currentMillis;
    e.move();
  }
  drawPlayer();
  e.draw();
}

I've tried using the delete() function and looking up things along the lines of "how to delete an instance of a class or object inside itself" on google.

Currently, it acts just fine until its x position hits zero and then it declines to delete itself and, despite the xPos values being negative, the enemy kinda glitches out on screen and walks left but re-spawns semi-randomly in the middle of the display.

CodePudding user response:

Invoking the destructor of a class from one of its methods is not a good idea. delete() will invoke class deallocator, and is meant to destroy a class instance that was created using the new expression. You don't know, in general, how this class instance was created; it could have been allocated on the stack, in which case the result is unpredictable.

In your case, a global instance of your class is instantiated, which must not be deallocated using delete at all.

A few suggestions for your code:

  • keep a global pointer to your class instance(s). Have your setup() to spawn your class instance(s) and keep track of it using your pointer(s), and loop() to delete instances when needed (and potentially respawn new instances).
  • Inside your Enemy class, maintain a status that can be consumed from loop() via a method, so you can identify when the class instance is ready be deleted.
  • When implementing your pointers, check if the Arduino SDK supports std::unique_ptr. This should alleviate the need for raw new/delete instructions.

Hope this helps,

  • Related