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), andloop()
to delete instances when needed (and potentially respawn new instances). - Inside your
Enemy
class, maintain a status that can be consumed fromloop()
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 rawnew
/delete
instructions.
Hope this helps,