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.
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:
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).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.std::unique_ptr
. This should alleviate the need for raw new
/delete
instructions.Hope this helps,