TImage nie znika po ustawieniu Visible

0

Wszystkie pliki, screeny z debuggera, film z problemem na dysku gogle
Witam
Tworzę w builderze arkanoida, na początku tworzy obiekt figure i tworzy za pomocą jego metod taką odwróconą piramidkę z bloczków które mamy trafić.
W timerze mam pętlę która sprawdza po kolei wszystkie bloki (wskaźniki do TImage zawarte w vectorze utworzonym wraz z obiektem figure) czy ich Visible==true, potem czy piłka się od któregoś odbije, a następnie jeśli piłka dotknęła którejś ściany bloku to ustawia jego Visible na false (funkcja collReflex używa funkcji wallcheck, więc jeśli jedna się "uaktywni" to druga na pewno też, sprawdzałem to).
Gdy uruchamiam grę (żadnych warningów ani errorów od kompilatora) wszystko jest dobrze, piłka spada, przegrywam, uruchamia się funkcja reset() i gram od nowa.
Za drugim razem czasami (na oko w 70% przypadków) trafiam jakiś blok, piłka się odbija,** jego Visible ustawiane jest na false a blok nie znika.**
Następnie gdy piłka "wleci" w ten blok to przeleci pod nim bez odbicia i trafi następne bloki które zachowają się tak samo.
Blok nie znika pomimo, że na pewno ma ustawione Visible na false, po linijce która to ustawiała wstawiłem ifa który to potwierdził
if(figure->blocks[i]->Visible==false) { Label2->Caption=i;}
oraz sprawdziłem w debuggerze (screeny załączę, w okienku do poglądania zmiennych widać że block[9] visible=false) oraz, żeby było ciekawiej, dla tego bloku wykonuje się później warunek
if(figure->blocks[i]->Visible==true jednak mimo to piłka od tego bloku widmo się nie odbija choć jest wystarczająco blisko.
Nie mam pojęcia o co chodzi, poniżej fragmenty kodu z paroma objaśnieniami

Fragment z timera w głównym pliku, timer porusza obiektem ball i sprawdza kolizje z blokami

void __fastcall TForm1::ruchTimer(TObject *Sender)
{
//    [CODE]

for(unsigned int i=0;i<figure->num_blocks();i++)
{

if(figure->blocks[i]->Visible==true)                            //ten warunek czasami potrafi się wykonać nawet na bloku którego visible==false
{
        collReflex(figure->blocks[i],ball,x,y,0,wallcheck::out);          // "sprawdź czy blocks[i] jest blisko, sprawdź z której strony bloku i w odpowiedni sposób go odbij"

        if(wallCheck(figure->blocks[i],ball,0,wallcheck::out)!=wallcheck::none)       //jeśli ball nie nie dotyka żadnej ściany blocks[i] (ściana != none) to:
        {
                figure->blocks[i]->Visible=false;                                 //za każdym razem gdy powinien, warunek przepuszcza tutaj kompilator, visible jest zmieniane na false 
                got_hit++;                                                                  //ilość trafionych bloków
                if(figure->blocks[i]->Visible==false)                           //ten warunek zawsze się spełnia wtedy kiedy powinien (bo blok faktycznie został trafiony), jednak ja nadal widzę ten blok
                {Label1->Caption="true"; Label2->Caption=i;}         //drugi caption widać na filmie który też wrzucę tu gdzieś, aby mieć pewność że o ten blok chodzi
                break;
        }
}
}
if(got_hit==figure->num_blocks())
win();
}

Funkcja restart()( która może mieć znaczenie bo przed jej drugim wywołaniem działa poprawnie, pierwsze wywołanie w konstruktorze TForm1, drugie po pierwszej przegranej )

void restart()
{  delete figure;                                             //ustawione na wszelki wypadek, bo naprawdę już nie wiem co robię źle
   figure=new Figure(Form1,BRICKBMP);      // w pliku nagłówkowym głównego pliku znajduje się deklaracja   Figure * figure;   oraz  #include "SetFigure.h" który załączę poniżej
   figure->set_figure(Form1,Figure::pyramid,3);       //utwórz odwróconą piramidę która ma 3 piętra w Form1 

  //[CODE]  bez znaczenia, ustawianie pozycji ball i paddle
   got_hit=0;

}

SetFigure.h - plik nagłówkowy klasy Figure, załączę kod w całości

class Figure
{
private:
String BLOCKBMP;               //set_bmp_file(String)
TForm* parent_form;
unsigned int numBlocks;        //num_blocks()
unsigned int levels;                //get_lvls()
unsigned int bmp_width;        //get_bmp_width()
unsigned int bmp_height;      //get_bmp_height()
bool defPosChanged;           //control
bool bmp_changed;             //control
int startTop;                          //
int startLeft;                          //
int between_hor;                 //get_between_hor()
int between_ver;            //get_between_ver()


public:
std::vector <TImage*> blocks;      //vector contains all the blocks in figure

enum choose {pyramid=0 };

//constructor:

Figure(TForm*,String);

//public methods:

unsigned int num_blocks();     //returning number of blocks in figure

unsigned int get_lvls();

unsigned int get_between_hor();

unsigned int get_between_ver();

unsigned int get_bmp_width();

unsigned int get_bmp_height();

void set_bmp_file(String);

void set_block(TImage *,TForm*);

void create_inv_pyr(TForm*);

void set_figure(TForm*,enum choose=pyramid,unsigned int=3);  



};

Plik źródłowy klasy Figure (cały oprócz prostych metod, typu get_jakaśwartość)

//contructor:
Figure::Figure(TForm* parent,String bmpfile)
{
 this->parent_form=parent;
 set_bmp_file(bmpfile);
 defPosChanged=false;
 bmp_changed=true;

}

void Figure::set_bmp_file(String path)
{
 BLOCKBMP=path;
 bmp_changed=true;
}

void Figure::set_block(TImage * block,TForm* parent_form)          //funkcja pomocnicza, ustawia podstawowe parametry każdego bloku z osobna, pozycja jest ustalana później
{


    block->Parent=parent_form;
    block->Picture->LoadFromFile(BLOCKBMP);
    block->Visible=true;
    block->AutoSize=true;
    block->Transparent=true;
    block->Enabled=true;

}


void Figure::create_inv_pyr(TForm* parent_form)   // lvls- levels of pyramid
{

 numBlocks=(levels*(levels+1));
 blocks.reserve(num_blocks());


 for(unsigned int i=0;i<num_blocks();i++)
 {
        blocks.insert(blocks.begin()+i,new TImage(parent_form));
        set_block(blocks[i],parent_form);
 }

 unsigned int num=0;
 
 for(unsigned int i=get_lvls();i>0;i--)    //ustawianie pozycji bloków, funkcja notmin() to zwraca po prostu wartość bezwględną, static cast ze względu na unsigned int
 {                                                         // tak, wiem że wystarczyłoby notmin<int>() ale to chyba rzutowanie niejawne a to podobno nieładnie
        for(unsigned int j=(i*2);j>0;j--)                                                
                {
                 blocks[num]->Top=startTop+(get_between_ver()+get_bmp_height())*somth::notmin<int>(static_cast<unsigned int>(i)-static_cast<unsigned int>(get_lvls()));
                 blocks[num]->Left=startLeft+(get_between_hor()+get_bmp_width())*somth::notmin<int>(static_cast<unsigned int>(j)-static_cast<unsigned int>(i)*2)+get_bmp_width()*somth::notmin<int>(static_cast<unsigned int>(i)-static_cast<unsigned int>(get_lvls()));
                 num++;
                }

 }

}


void Figure::set_figure(TForm* parent_form, enum choose choice,unsigned int lvls)              //w tej funkcji wybierasz jedną z figur, na razie jest tylko piramida
{
 levels=lvls;

     if(bmp_changed==true)              //jeśli wywołasz funkcję  set_bmp_file() (czyli zmienisz podaną w konstruktorze ścieżke do grafiki) to zmierz jej wielkość na nowo
    {
    TImage * block=new TImage(parent_form);
    block->Parent=parent_form;
    block->Picture->LoadFromFile(BLOCKBMP);
    block->AutoSize=true;
    
    bmp_width=block->Width;
    bmp_height=block->Height;
    bmp_changed=false;
    delete block;
    }

 switch(choice)
 {
 case 0:                                      //pyramid

         if(defPosChanged==false)
         {                                 //setting defaults                    jeśli ustawisz jakieś  swoje wartości to raczej nie chcesz aby funkcja ponownie ustawiła ci defaultowe, po to jest ten if
                between_hor=5;
                between_ver=5;
                startTop=parent_form->Height/16;
                startLeft=parent_form->Width/2-get_lvls()*get_bmp_width()-get_between_hor()*get_lvls()+get_between_hor()/2;
                defPosChanged=true;
                
         }
         create_inv_pyr(parent_form);
         break;
 default:
         ShowMessage("Error in choosing right figure");
         break;

 }
}

1
  1. Nie piszę w C++
  2. Bez analizy kodu po odpaleniu gierki widać że wszystko działa w sensie znika co ma znikać. Po restarcie natomiast nie usuwasz pozostałych bloków tylko nadpisujesz nowe. Daje to efekt jakby cześć bloków nie znikała.
  3. Po analizie kodu (nie piszę w C++) block->Parent=parent_form; dla bloku ustalasz rodzica jako formatkę. Jeśli kasujesz delete figure; to dla mnie nie usuwa to pozostałych bloków. Żeby to potwierdzić możesz po restarcie nadać nowym blokom inny kolor (np. załadować inną bitmapę albo jakoś je wyróżnić). Trzeba pewnie pousuwać bloki w pętli po restarcie albo przypisać jako rodzica figure i wtedy przy zwalnianiu może tez pousuwa bloki.
0

@Clarc: Parent może być tylko TFormem, bo nie chciało mi działać jak podmieniłem, ale faktycznie miałeś rację z tym co się dzieje. Napisałem destruktor dla Figure z pętlą usuwającą wszystkie elementy vectora z TImage od bloków i teraz wszystko śmiga, zapomniałem o nim wcześniej, miałem przeświadczenie że delete samo usunie wszystko co z obiektem związane. Dzięki za pomoc

1 użytkowników online, w tym zalogowanych: 0, gości: 1