M5Stack Core2 C＋＋学習　オブジェクトの生成と破棄


<iframe width="560" height="315" src="https://www.youtube.com/embed/aXqz_IG8GI8?si=Qb9YSJIoOflp8xmQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

乱数を使用して座標と寿命を設定します。life値が大きいと半径も大きくなります。四方の壁に当たると、半径が減衰していきます。半径が５ピクセルになったら、デストラクタで消滅します。

```CPP:generations.h
#ifndef __GENERATIONS_HPP_
#define __GENERATIONS_HPP_

#include <M5Core2.h>

namespace generations
{
    //跳ね返りの壁
    #define WALL_LIMIT_LEFT 0
    #define WALL_LIMIT_RIGHT 319
    #define WALL_LIMIT_TOP 0
    #define WALL_LIMIT_BOTTOM 194

    /// @brief 座標
    class Point
    {
        public:            
            Point(int _x, int _y);
            inline Point& operator=(const Point& _pt){x=_pt.x; y=_pt.y; return *this;};
        public:
            int x; 
            int y;
    };

    //移動ベクトル
    class Vector
    {
        public:
            Vector(int _dx, int _dy){dx=_dx; dy=_dy;};
        public:
            int dx;
            int dy;
    };

    /// @brief 移動方向
    class Direction
    {
        public:
            Direction(int _xdir, int _ydir){x=_xdir; y=_ydir;};
        public:
            int x;
            int y;
    };

    //描画オブジェクトクラス
    class GTUnit
    {
        public:            
            GTUnit();
            ~GTUnit();
            bool operator==(const GTUnit& gt);
            void draw();
            void getMoveTo();//移動座標計算
            void checkCollision();//壁の当たり判定
            bool checkCollisionTimes();//壁に当たった回数で消去。
            static uint getSize();//instancesのサイズ
        public:
            static std::vector<GTUnit*> instances;
            static int total;//コンストラクタ起動回数
            static int totalDelete;//デストラクタ起動回数
            static uint16_t colorFormat[18];
            Point ptNow={0,0};//現在位置(非静的メンバー変数の初期化子)
            Point ptPast{0,0};//過去位置(Non Static Data Member Initializer)
            Vector v={0,0};//移動ベクトル
            Direction dir{1,1};//移動方向
            uint radiusNow;//半径現在
            uint radiusPast;//半径過去
            uint life;//総当たり回数（文字通りLIFE)
            uint lifeLimit;//消滅限界数
            uint8_t colorNum=0;//色番号
            uint16_t color;//TFT色値
            uint collisionTimes;//衝突回数カウンタ
    };
};

#endif
```

```CPP:generations.cpp
#include "generations.hpp"
#include "mydisplay.hpp"

namespace generations
{
    /*static*/
    std::vector<GTUnit*> GTUnit::instances;
    int GTUnit::total=0;
    int GTUnit::totalDelete=0;
    uint16_t GTUnit::colorFormat[18]
        ={NAVY,DARKGREEN,DARKCYAN,MAROON,PURPLE,OLIVE,LIGHTGREY,DARKGREY,
          BLUE,GREEN,CYAN,RED,MAGENTA,YELLOW,WHITE,ORANGE,GREENYELLOW,PINK};

    //Pointクラスコンストラクタ
    Point::Point(int _x, int _y)
    {
        x = _x;
        y = _y;
    }

    //GTUnitクラスコンストラクタ
    GTUnit::GTUnit()
    {
        int32_t c,c1; 
#if 0     
        __asm__ __volatile("rsr %0, ccount":"=r"(c));
        ptNow.x = c%320;
        ptNow.y = c%240;
        __asm__ __volatile("rsr %0, ccount":"=r"(c1));
#endif 
        c = (int32_t)rand();//乱数取得
        c1 = (int32_t)rand();
        //initial Position
        ptNow.x = c%320;
        ptNow.y = c1%240;
        //set moving vector
        v.dx = c%5+3;
        v.dy = c1%5+3;
        //set moving direction
        dir.x = (c%2==0)? 1:-1;
        dir.y = (c1%2==0)? 1:-1;
        //set collision values
        life = c % 10+10;
        lifeLimit = life-5;
        //initial radius
        radiusNow=life;
        radiusPast=life;
        //set color 
        colorNum=c%18;
        color=colorFormat[colorNum];
        //initialize collision counter
        collisionTimes=0;
        total++;
        //instance push
        instances.push_back(this);
        /*Serial.printf("(%d,%d) ", ptNow.x,ptNow.y);
        Serial.printf("V(%d,%d) ", dir.x*v.dx,  dir.y*v.dy);
        Serial.printf("c:%x t:%d\r",color,collisionTimes);*/
        draw();//描画
    }

    //GTUnitクラス　デストラクタ
    GTUnit::~GTUnit()
    {
        for(int i=0; i<instances.size(); i++)
        {
            if(instances[i] == this)
            {
                totalDelete++;
                LCD.canvas2.fillCircle(ptPast.x,ptPast.y,radiusPast,BLACK);
                instances.erase(instances.begin()+i);
                //Serial.printf("Delete[%d]\r",i);
            }
        }
    }

    //GTUnit　== 比較演算子のオーバーロード
    bool GTUnit::operator==(const GTUnit& gt){ return (this==&gt); }

    /// @brief オブジェクトユニット描画
    void GTUnit::draw()
    {
        LCD.canvas2.fillCircle(ptPast.x,ptPast.y,radiusPast,BLACK);
        LCD.canvas2.fillCircle(ptNow.x, ptNow.y,radiusNow, color);  
        if(radiusPast!=radiusNow)
            radiusPast = radiusNow;      
    }

    /// @brief 座標移動計算
    void GTUnit::getMoveTo()
    {
        ptPast = ptNow;
        ptNow.x += dir.x*v.dx;
        ptNow.y += dir.y*v.dy;
        checkCollision();//衝突チェック
        if(checkCollisionTimes())//衝突回数到達チェック
        {
            delete this;
        }
    }
    
    /// @brief 衝突チェック　方向転換
    void GTUnit::checkCollision()
    {
        bool is=false;
        int r = radiusNow;
        //Top Wall collision check
        if(ptNow.y <= WALL_LIMIT_TOP+r)
        {
            ptNow.y = WALL_LIMIT_TOP+r;
            dir.y = (dir.y==1)? -1:1;
            is=true;
        }
        //Bottom Wall collision check
        if(ptNow.y >= WALL_LIMIT_BOTTOM-r)
        {
            ptNow.y = WALL_LIMIT_BOTTOM-r;
            dir.y =(dir.y==1)? -1:1;
             is=true;
        }
        //Left Wall collision check
        if(ptNow.x <= WALL_LIMIT_LEFT+r)
        {
            ptNow.x = WALL_LIMIT_LEFT+r;
            dir.x = (dir.x==1)? -1:1;
             is=true;
        }
        //Right Wall collision check
        if(ptNow.x >= WALL_LIMIT_RIGHT-r)
        {
            ptNow.x = WALL_LIMIT_RIGHT-r;
            dir.x = (dir.x==1)? -1:1;
             is=true;
        }
        if(is)
        {
            collisionTimes++;
            radiusNow-=1;
        }
    }

    /// @brief 衝突回数到達チェック
    /// @return 1:到達 0:未達
    bool GTUnit::checkCollisionTimes()
    {
        if(collisionTimes==lifeLimit)
            return true;
        else
            return false;
    }

    /// @brief GTUnitクラスインスタンスのサイズ
    /// @return 登録ベクタサイズ
    uint GTUnit::getSize(){ return instances.size(); }
}
```

```CPP:mydisplay.hpp
#ifndef __MYDISPLAY_HPP__
#define __MYDISPLAY_HPP__

#include <M5Core2.h>

namespace generations
{
    #define LCD_WIDTH 320
    #define LCD_HEIGHT 195

    class display
    {
        public:
        display();
        
        public:
        TFT_eSprite canvas1 = TFT_eSprite(&M5.Lcd);
        TFT_eSprite canvas2 = TFT_eSprite(&M5.Lcd);
        
    }; 

    extern display LCD;
}


#endif
```

```CPP:mydisplay.cpp
#include "mydisplay.hpp"

namespace generations
{
    display LCD;
    
    display::display()
    {
    }
}
```

```CPP:main.cpp
#include <M5Core2.h>
#include "generations.hpp"
#include "mydisplay.hpp"

using namespace generations;

void setup()
{
  M5.begin();
  LCD.canvas1.createSprite(LCD_WIDTH,45);
  LCD.canvas2.createSprite(LCD_WIDTH,LCD_HEIGHT);

  //スプライト１描画
  LCD.canvas1.setFreeFont(&FreeSans12pt7b);
  LCD.canvas1.fillRect(0,0,320,44,DARKGREY);
  LCD.canvas1.setCursor(0,20);
  LCD.canvas1.setTextColor(BLUE,CYAN);
  LCD.canvas1.printf("M5Stack Core2");
  LCD.canvas1.setCursor(220,40);
  LCD.canvas1.setTextColor(ORANGE);
  LCD.canvas1.printf("Now:%2d",0);
  LCD.canvas1.setCursor(0,40);
  LCD.canvas1.setTextColor(WHITE);
  LCD.canvas1.printf("Total:%2d ",0);
  LCD.canvas1.setTextColor(WHITE);
  LCD.canvas1.printf("Delete:%2d",0);
  LCD.canvas1.pushSprite(0,0);

}

void loop(void)
{
  static int num;//インスタンスの数

  M5.update();
  if(M5.BtnA.wasPressed())
  {
    new GTUnit();//オブジェクトの生成、追加。
    num = GTUnit::getSize();//インスタンス数
  }
  
  //オブジェクトの描画
  if(num>0)
  {
   
    for(int i=0; i<num; i++)
    {
      GTUnit::instances[i]->draw();//オブジェクト描画
      GTUnit::instances[i]->getMoveTo();//オブジェクト移動、消去
    }
    LCD.canvas2.pushSprite(0,45);
    
    //スプライト２　オブジェクト描画エリア
    num = GTUnit::getSize();
    LCD.canvas1.setFreeFont(&FreeSans12pt7b);
    LCD.canvas1.fillRect(0,0,320,44,DARKGREY);
    LCD.canvas1.setCursor(0,20);
    LCD.canvas1.setTextColor(BLUE);
    LCD.canvas1.printf("M5Stack Core2");
    LCD.canvas1.setCursor(220,40);
    LCD.canvas1.setTextColor(ORANGE);
    LCD.canvas1.printf("Now:%2d",num);
    LCD.canvas1.setCursor(0,40);
    LCD.canvas1.setTextColor(WHITE);
    LCD.canvas1.printf("Total:%2d   ",GTUnit::total);
    LCD.canvas1.setTextColor(WHITE);
    LCD.canvas1.printf("Delete:%2d",GTUnit::totalDelete);
    LCD.canvas1.pushSprite(0,0);
  }
  delay(5);
}


```