Crash w środku warunku

0

Otóż mam taki problem. Robię grę z użyciem biblioteki SFML. Poniższa funkcja ma za zadanie sprawdzać położenie pola na mapie względem innych pól tego typu, w celu zastosowania odpowiedniej tekstury.

int tilePosType(TileMap mapa, sf::Vector2f pos)
{
    int type;
    // 0 1-2-3
    //
    // 4 5-6-7
    // | | | |
    // 8 9-a-b
    // | | | |
    // c d-e-f

    if((!sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
       (!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 0;

    else if((!sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 1;

    else if((sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 2;

    else if((sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 3;

    else if((!sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 4;

    else if((!sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 5;

    else if((sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 6;

    else if((sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 7;

    else if((!sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 8;

    else if((!sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 9;

    else if((sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 10;

    else if((sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 11;

    else if((!sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 12;

    else if((!sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 13;

    else if((sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 14;

    else if((sameTile(mapa, pos, sf::Vector2f(pos.x-1, pos.y)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x+1, pos.y)))&&
             (sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y-1)))&&(!sameTile(mapa, pos, sf::Vector2f(pos.x, pos.y+1)))) type = 15;

    else type = 0;

    return type;
}

bool sameTile(TileMap mapa, sf::Vector2f pos1, sf::Vector2f pos2)
{
    std::cout<<"raz ";

    bool same = true;

    if((pos1.x<0)||(pos1.x>=mapa.getSize().x)||(pos1.y<0)||(pos1.y>=mapa.getSize().y)||
       (pos2.x<0)||(pos2.x>=mapa.getSize().x)||(pos2.y<0)||(pos2.y>=mapa.getSize().y)) gszyp = false;

    else if(mapa.getTile(pos1).typeNr!=mapa.getTile(pos2).typeNr) gszyp = false;

    std::cout<<"dwa"<<std::endl;
    return same;
}

Widoczne w funkcji sameTile() couty dodałem, żeby znaleźć miejsce crasha, no i właśnie.
Wyjście wygląda tak:

raz dwa
raz dwa

Po tym następuje crash.
Widać więc, że ta funkcja jest wywoływana dwa razy i wykonuje się w całości, a za to trzeci raz nawet nie zostaje wywołana. Odkryłem też, że sytuacja wygląda tak samo niezależnie od tego, co wstawię w trzeci warunek w pierwszym ifie. Próbowałem nawet dawać tam funkcję która nie robi nic poza wyświetleniem tekstu na ekranie i zwróceniem prawdy, tekst nie wyświetlił się.
Za to kiedy wywaliłem wywołanie sameTile() funkcji z jednego z dwóch pierwszych warunków (obojętnie którego) to crash nastąpił dopiero po trzecim wykonaniu sameTile().
Problem nie leży też w tym, że zapisałem te ify w dwóch linijkach, kiedy wszystko jest w jednej, jest tak samo. (A robię tak bo kod jest dla mnie czytelniejszy kiedy nie muszę go przewijać na boki)

8

Ja rozumiem, że pan Zelent poleca programowanie przez kopiuj i wklej, ale to jest bardzo zła praktyka. Wywal cały ten kod i napisz go w prostszy i czytelniejszy sposób. No i spróbuj użyć debuggera.

5

Niestety twój kod nadaje się tylko do przepisania :(

Przepisz ten kod, błądzenie i próbowanie żeby działo to nie wyjście. Za chwilę w 10 ifie od dołu będzie błąd, poza tmy nikt ci n,eei pomoże z obecnym kodem, bo to masakra.

0

Nie bardzo wiem jak miałbym to przepisać, żadnej zależności pozwalającej na zrobienie tego w pętli nie zauważyłem. Może po prostu jestem na to zbyt tępy. Nie wiem.
A jak uruchomiłem ten program przez debugger CodeBlocksa to pokazało mi segmentation fault w funkcji getSize() klasy Image (z SFML), której tutaj nawet nie wywołuję nigdzie...

1

na pewno zamiast magicznych liczb użyj typu wyliczeniowego (enum)

0

sprawdzasz wszyskie kombinacje wiec możesz zrobić np. tak

           
            int wynik = 0;
            for (int i = 0; i < 4; i++)
            {
                if (i % 2 ==0)
                    offset = 1;
                else
                    offset = -1;

                if (0==(i >> 1)%2)
                {
                    if (tenSamTytul(x + offset, y + 0))
                        wynik |= (1 << i);
                }
                else
                {
                    if (tenSamTytul(x + 0, y + offset))
                        wynik |= (1 << i);
                }
            }

z tym że wybieranie przesunięcia powinno mieć własna funkcje, zamiast brzydkich if'ów, i o trzymasz coś takiego(jak coś to jest pseudo kod)

 
     int Sprawdz(int x, int y)
      {
            int wynik =0;
            for (int i = 0; i < 4; i++)
            {
                if (tenSamTytul(GetDoSprawdzenia(x, y, i)))
                    wynik |= (1 << i);
             }
             return wynik;
       }
        GetDoSprawdzenia(int x, int y, int i)
        {
            vektor wynik = null;
            switch (i)
            {
                case 0:
                    wynik = new vektor (x + 1, y + 0); break;  
                case 1:
                    wynik = new vektor (x - 1, y + 0); break;
                case 2:
                    wynik = new vektor (x + 0, y + 1); break;
                case 3:
                    wynik = new vektor (x + 0, y - 1); break;
                default:
                    break;
                    //blad;
            }
            return wynik;
         }

im więcej masz ifów tym bardziej kod robi się (nie potrzebnie)skomplikowany, wiec należy ich unikać.

0

No nie wiedziałem za dużo o działaniach na bitach, acz poczytałem trochę na internecie i stwierdziłem że chyba rozumiem. Następnie spróbowałem zrozumieć, co dzieje się w twoim kodzie i w trakcie tego zauważyłem, że o tych bitach jednak nie całkiem zrozumiałem, więc poczytałem jeszcze raz i teraz rozumiem jeszcze mniej niż przedtem.
No w każdym razie nie jestem w stanie zrozumieć co dokładnie robi twój kod.

EDIT
Mimo tego że nie bardzo rozumiem co się tam dzieje w operacjach na bitach to spróbowałem jednak zaimplementować ten kod, zrobiłem to w ten sposób: (sprawdzające couty w sameTile() zostawiłem)

int tilePosType(TileMap mapa, sf::Vector2f pos)
{
    int type = 0;
    // 0 1-2-3
    //
    // 4 5-6-7
    // | | | |
    // 8 9-a-b
    // | | | |
    // c d-e-f

    for(int i=0; i<4; i++)
    {
        if(sameTile(mapa, pos, getDoSprawdzenia(pos, i))) type |= (1<<i);
    }

    return type;
}

sf::Vector2f getDoSprawdzenia(sf::Vector2f pos, int i)
{
    sf::Vector2f wynik;

    switch(i)
    {
        case 0:
            wynik = sf::Vector2f(pos.x+1, pos.y); break;
        case 1:
            wynik = sf::Vector2f(pos.x-1, pos.y); break;
        case 2:
            wynik = sf::Vector2f(pos.x, pos.y+1); break;
        case 3:
            wynik = sf::Vector2f(pos.x, pos.y-1); break;
        default: break;
    }

    return wynik;
}

bool sameTile(TileMap mapa, sf::Vector2f pos1, sf::Vector2f pos2)
{
    std::cout<<"raz ";

    bool same = true;

    if((pos1.x<0)||(pos1.x>=mapa.getSize().x)||(pos1.y<0)||(pos1.y>=mapa.getSize().y)||
       (pos2.x<0)||(pos2.x>=mapa.getSize().x)||(pos2.y<0)||(pos2.y>=mapa.getSize().y)) same = false;

    else if(mapa.getTile(pos1).typeNr!=mapa.getTile(pos2).typeNr) same = false;

    std::cout<<"dwa"<<std::endl;
    return same;
}

Wszystko ładnie się kompiluje, acz nadal mam ten sam problem co wcześniej.
Program crashuje się przez segmentation fault, a callstack jako ostatnią funkcję podaje sf::getSize(), której tu nawet nie wywołuję.
I zauważyłem coś na co nie zwróciłem uwagi wcześniej, podczas zwykłego uruchomienia sameTile() wykonuje się dwa razy, a w debuggerze cztery.

Może powinienem napisać na forum SFML?

1
 bez code post wybucha :)
Liczba int to int składa się z 4 bajtów, a każdy bajt z 8 bitów dla uproszczenia będę pisał tylko ostatni bajt np.  11 = 0x0B = 0000 1011. 
     To co robisz w swoim kodzie to sprawdzasz górna pozycja jest/ nie jest taka sama i czy dolna pozycja jest/ nie jest taka sama i czy lewa pozycja jest/ nie jest taka sama i czy prawa jest / nie jest taka sama.Wszystkie 16 kombinacji.
       Ja robię coś takiego sprawdzam czy lewa jest taka sama i jeśli jest wynik zapisuje w bicie nr 0 int'a wynik |= 1<<0;, w kolejnym obrocie pętli sprawdzam czy prawa jest taka sama i jeśli jest zapisuje w bicie nr 1 int'a wynik|= 1 << 1; w kolejnym sprawdzam górę i zapisuje w bicie 3  wynik |= 1 << 2  a w następnym zapisuje to czy dół jest taki sam w bicie 3 wynik |= 1 << 3;

Teraz pytanie co robi operacja wynik |= 1 << i.
 Jeden binarnie wygląda tak  0000 0001 .oprerator "<<" przesuwa reprezentacje binarną w lewo o x bitów czyli  1 << 2 = 0000 0001 << 2 = 0000 0100 .Chyba widamo o co chodzi.  dla i = 0 mamy: 0000 0001, dla i = 1: 000 0010, dla 2: 0000 0100, dla 3: 0000 1000.
                                     Teraz najtrudniejsze operator "|"  przepisuje wszystkie 1 z jednej liczby binarnej do drugiej.   np 0000 | 0101 = 0101; 1001 | 0011 = 1011; operator |= to jest to samo co += dla +.
Tutaj pisałem tylko 4 najmniej znaczace bity
Na początku mamy wynik = 0 czy 0000 jeśli pierwszy warunek to wynik = 0000 | 0001 = 0001 , jeśli drugi  wynik = 0001 | 0010 = 0011; jeśli 3 nie jest spełnimy nic nie robimy, a jeśli 4 jest to wynik = 0011 | 1000 = 1011; Czyli tak jak pisałem wyżej sprawdzam wynik porównania i zapisuje go na stosownym bicie.jako wynik o trzymasz jedną z 16 liczb między < 0 - 15 >, dlaczego tak to zadanie domowe:).

Żeby połapać się w tych operacjach potrzeba jednego wieczoru, liczenia aż do skutku.ale watro bo się przydaje.

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