Algorytm Generowania Dachu Budynku

Algorytm Generowania Dachu Budynku
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
0

Witam. Piszę algorytm generujący dach budynku. Mam problem z kafelkami. Dla następujących wartości: tile_width = 16, tile_height = 8,tile_border = 1 algorytm działa poprawnie lecz gdy zmienię te parametry na np. 32,16,1 to już nie. Podejrzewam, że zrobiłem błąd w obliczaniu dy

my_house.pngmy_house_1.png

Kopiuj
void loadTexture(std::ifstream& file) {
    
    
    
    // check the size
    cout << size.x << " " << size.y << "\n";

    short walls_height = 3;

    // create basic image to render house
    sf::Image house_image;
    house_image.create(size.x * 16, (size.y + walls_height*2 + 2) * 16, sf::Color::Transparent);

    // load the wall texture
    sf::Image wall;
    wall.create(32, 32, sf::Color::Transparent);
    wall = getTexture("walls/wooden_wall")->texture->copyToImage();
  
    
    // DRAWING A WALLS
    for (short y = 1; y <= walls_height; y++) {
        for (short x = 0; x < size.x/2; x++) {
            house_image.copy(wall, x*2*16, house_image.getSize().y - y *2*16);
        }
    }

    cout << "\n\n warning! \n";

    // DRAWING A WALLS UNDER THE ROOF
    short height = size.x/4;
    short width = size.x/2;
    short start_x;
    short end_x;

    for (int y = 0; y <= height; y++) {
        start_x = y;
        end_x = width - y - 1;

        for (int x = 0; x < width; x++) {
            if (x >= start_x && x <= end_x) {
                house_image.copy(wall, x * 2 *16, house_image.getSize().y - (y + walls_height + 1) * 2 * 16);
            }
        }
    }

    // DRAWING A ROOF
    sf::Color color = sf::Color(51, 38, 21);

    sf::Vector2f p1(0, walls_height * 2*16);
    sf::Vector2f p2(size.x/2*16, (walls_height+size.x/4) * 2*16);
    sf::Vector2f p3(size.x*16, walls_height * 2*16);
    sf::Vector2f p4(size.x*16, (walls_height +size.y/4 + 1) * 2*16);
    sf::Vector2f p5(size.x / 2 * 16, (walls_height + size.x / 4 + size.y/4 + 1) * 2 * 16);
    sf::Vector2f p6(0, (walls_height + size.y/4 + 1) * 2 * 16);
    
    sf::VertexArray left_quad(sf::Quads, 4);
    left_quad[0].position = p1;
    left_quad[1].position = p2;
    left_quad[2].position = p5;
    left_quad[3].position = p6;
    left_quad[0].color = color;
    left_quad[1].color = color;
    left_quad[2].color = color;
    left_quad[3].color = color;

    sf::VertexArray right_quad(sf::Quads, 4);
    right_quad[0].position = p2;
    right_quad[1].position = p3;
    right_quad[2].position = p4;
    right_quad[3].position = p5;
    right_quad[0].color = color;
    right_quad[1].color = color;
    right_quad[2].color = color;
    right_quad[3].color = color;

    sf::RenderTexture rtex;
    rtex.create(house_image.getSize().x, house_image.getSize().y);
    rtex.draw(left_quad);
    rtex.draw(right_quad);

    // CREATE A TILES

    float tile_width = 16;
    float tile_height = 8;
    float tile_border = 1;

    sf::Color color_outside = sf::Color(51, 38, 21);
    sf::Color color_inside = sf::Color(185, 0, 0);
    
    for (float y = 0; y < (size.y / 2 +2)* 16; y += tile_height) {
        for (float dx = 0; dx < size.x / 2 * 16; dx += tile_width) {

            float len_of_roof = float(size.x / 4) * 2.0f * 16.0f;
            float dy = len_of_roof / tile_height * float(dx) / tile_width;

            // outside of tile
            sf::VertexArray outside(sf::Quads, 4);
            outside[0].position = sf::Vector2f(dx, y + dy + (walls_height) * 2 * 16);
            outside[1].position = sf::Vector2f(dx + tile_width, y + dy + (walls_height) * 2 * 16 + tile_height);
            outside[2].position = sf::Vector2f(dx + tile_width, y + dy + (walls_height) * 2 * 16 + 2*tile_height);
            outside[3].position = sf::Vector2f(dx, y + dy + (walls_height) * 2 * 16 + tile_height);
            outside[0].color = color_outside;
            outside[1].color = color_outside;
            outside[2].color = color_outside;
            outside[3].color = color_outside;
            rtex.draw(outside);

            // inside of tile
            sf::VertexArray inside(sf::Quads, 4);
            inside[0].position = sf::Vector2f(dx + tile_border, y + dy + (walls_height) * 2 * 16 + tile_border);
            inside[1].position = sf::Vector2f(dx + tile_width - tile_border, y + dy + (walls_height) * 2 * 16 + tile_height + tile_border);
            inside[2].position = sf::Vector2f(dx + tile_width - tile_border, y + dy + (walls_height ) * 2 * 16 + 2*tile_height - tile_border);
            inside[3].position = sf::Vector2f(dx + tile_border, y + dy + (walls_height) * 2 * 16 + tile_height - tile_border);
            inside[0].color = color_inside;
            inside[1].color = color_inside;
            inside[2].color = color_inside;
            inside[3].color = color_inside;
            rtex.draw(inside);
        }
    }


    sf::Image roof_image = rtex.getTexture().copyToImage();

    house_image.copy(roof_image, 0, 0 ,sf::IntRect(0,0,0,0),true);

    // create main tex
    sf::Texture* tex = new sf::Texture();
    tex->loadFromImage(house_image);

    // create the sprite
    sprite = sf::Sprite();
    sprite.setTexture(*tex);
    sprite.setOrigin(tex->getSize().x / 2, tex->getSize().y);
    sprite.setPosition(position);

}

W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Tuchów
  • Postów:12163
1

Dach na pierwszym obrazku też zdaje się wyglądać niepoprawnie. Dwa problemy widzę. Pierwszy jest taki, że dachówki nie są równoległe do krawędzi dachu — takl ma być, czy to też bug? A drugi jest taki, że dachówek brakuje u góry, a na dole jest za dużo. To powoduje, że u góry widać ciemnobrązowe tło dachu, a dachówki na dole zdają się lewitować.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
0

W takim razie jak to naprawić?

Zrobiłem coś takiego i teraz oblicza mi rozmiary kafelków ale

Kopiuj
float tiles_rows = 8;
float tiles_columns = 16;

float tile_width = float(size.x/4)*2.0f*16.0f / tiles_columns;
float tile_height = (float(size.x / 4) * 2.0f * 16.0f) / tiles_rows;
float tile_border = 1;

my_house_2.png


W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
edytowany 1x, ostatnio: tBane
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
0

Teraz mam taki kod:
my_house_3.png

Kopiuj
void loadTexture(std::ifstream& file) {
    
    
    
    // check the size
    cout << size.x << " " << size.y << "\n";

    short walls_height = 3;

    // create basic image to render house
    sf::Image house_image;
    house_image.create(size.x * 16, (size.y + walls_height*2 + 2) * 16, sf::Color::Transparent);

    // load the wall texture
    sf::Image wall;
    wall.create(32, 32, sf::Color::Transparent);
    wall = getTexture("walls/wooden_wall")->texture->copyToImage();
  
    
    // DRAWING A WALLS
    for (short y = 1; y <= walls_height; y++) {
        for (short x = 0; x < size.x/2; x++) {
            house_image.copy(wall, x*2*16, house_image.getSize().y - y *2*16);
        }
    }

    cout << "\n\n warning! \n";

    // DRAWING A WALLS UNDER THE ROOF
    short height = size.x/4;
    short width = size.x/2;
    short start_x;
    short end_x;

    for (int y = 0; y <= height; y++) {
        start_x = y;
        end_x = width - y - 1;

        for (int x = 0; x < width; x++) {
            if (x >= start_x && x <= end_x) {
                house_image.copy(wall, x * 2 *16, house_image.getSize().y - (y + walls_height + 1) * 2 * 16);
            }
        }
    }

    // DRAWING A ROOF
    sf::Color color = sf::Color(51, 38, 21);

    sf::Vector2f p1(0, walls_height * 2*16);
    sf::Vector2f p2(size.x/2*16, (walls_height+size.x/4) * 2*16);
    sf::Vector2f p3(size.x*16, walls_height * 2*16);
    sf::Vector2f p4(size.x*16, (walls_height +size.y/4 + 1) * 2*16);
    sf::Vector2f p5(size.x / 2 * 16, (walls_height + size.x / 4 + size.y/4 + 1) * 2 * 16);
    sf::Vector2f p6(0, (walls_height + size.y/4 + 1) * 2 * 16);
    
    sf::VertexArray left_quad(sf::Quads, 4);
    left_quad[0].position = p1;
    left_quad[1].position = p2;
    left_quad[2].position = p5;
    left_quad[3].position = p6;
    left_quad[0].color = color;
    left_quad[1].color = color;
    left_quad[2].color = color;
    left_quad[3].color = color;

    sf::VertexArray right_quad(sf::Quads, 4);
    right_quad[0].position = p2;
    right_quad[1].position = p3;
    right_quad[2].position = p4;
    right_quad[3].position = p5;
    right_quad[0].color = color;
    right_quad[1].color = color;
    right_quad[2].color = color;
    right_quad[3].color = color;

    sf::RenderTexture rtex;
    rtex.create(house_image.getSize().x, house_image.getSize().y);
    rtex.draw(left_quad);
    rtex.draw(right_quad);

    // CREATE A TILES

    float tiles_rows = 8;
    float tiles_columns = 16;

    float tile_width = float(size.x/4)*2.0f*16.0f / tiles_columns;
    float tile_height = float(size.y/2)*2.0f*16.0f / tiles_rows;
    float tile_border = 1;

    sf::Color color_outside = sf::Color(51, 38, 21);
    sf::Color color_inside = sf::Color(185, 0, 0);
    
    for (float y = 0; y < (size.y)* 16; y += tile_height) {
        for (float dx = 0; dx < size.x / 2 * 16; dx += tile_width) {

            float len_of_roof = float(size.x / 4) * 2.0f * 16.0f;
            float dy = len_of_roof / tile_height * float(dx) / tile_width;

            // outside of tile
            sf::VertexArray outside(sf::Quads, 4);
            outside[0].position = sf::Vector2f(dx, y + dy + (walls_height) * 2 * 16);
            outside[1].position = sf::Vector2f(dx + tile_width, y + dy + (walls_height) * 2 * 16 + tile_height/2.0f);
            outside[2].position = sf::Vector2f(dx + tile_width, y + dy + (walls_height) * 2 * 16 + tile_height);
            outside[3].position = sf::Vector2f(dx, y + dy + (walls_height) * 2 * 16 + tile_height/2.0f);
            outside[0].color = color_outside;
            outside[1].color = color_outside;
            outside[2].color = color_outside;
            outside[3].color = color_outside;
            rtex.draw(outside);

            // inside of tile
            sf::VertexArray inside(sf::Quads, 4);
            inside[0].position = sf::Vector2f(dx + tile_border, y + dy + (walls_height) * 2 * 16 + tile_border);
            inside[1].position = sf::Vector2f(dx + tile_width - tile_border, y + dy + (walls_height) * 2 * 16 + tile_height/2.0f + tile_border);
            inside[2].position = sf::Vector2f(dx + tile_width - tile_border, y + dy + (walls_height ) * 2 * 16 + tile_height - tile_border);
            inside[3].position = sf::Vector2f(dx + tile_border, y + dy + (walls_height) * 2 * 16 + tile_height/2.0f - tile_border);
            inside[0].color = color_inside;
            inside[1].color = color_inside;
            inside[2].color = color_inside;
            inside[3].color = color_inside;
            rtex.draw(inside);
        }
    }


    sf::Image roof_image = rtex.getTexture().copyToImage();

    house_image.copy(roof_image, 0, 0 ,sf::IntRect(0,0,0,0),true);

    // create main tex
    sf::Texture* tex = new sf::Texture();
    tex->loadFromImage(house_image);

    // create the sprite
    sprite = sf::Sprite();
    sprite.setTexture(*tex);
    sprite.setOrigin(tex->getSize().x / 2, tex->getSize().y);
    sprite.setPosition(position);

}

W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
0

Już prawie mam
float dy = dx / tile_width * tile_height/2.0f;
my_house_4.png


W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Tuchów
  • Postów:12163
0

Skup się najpierw na tym, aby dachówka renderowana była pod kątem 45°, zgodnie ze spadem dachu.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
Zobacz pozostałe 2 komentarze
flowCRANE
No właśnie na tym zrzucie widać, że nie jest. Jeśli namalujesz linię pod kątem 45°, to jej krawędź będzie ząbkowana — jeden piksel w bok, jeden w górę, jeden w bok, jeden w górę itd. A na tym zrzucie widać, że linia jest załamana centralnie na środku dachówki.
flowCRANE
Najlepiej to widać na dachówkach na samym dole — krawędź dachówki nie jest zgodna z krawędzią tła dachu. Wrzuć sobie ten obrazek do painta i powiększ maksymalnie — wtedy będziesz wyraźnie widział tę niezgodność.
tBane
widocznie to błąd SFML.2 w generowaniu sf::Quad, bo to niemożliwe, żeby było źle renderowane - sprawdź jak są pozycjonowane punkty dachówki
flowCRANE
Jeśli tak, to dorzuć 0.5f do którejś współrzędnej w osi Y. Bez względu na to co jest problemem, tak czy siak trzeba go naprawić, aby ten dach ładnie wyglądał, tak czysto piksel artowo. ;)
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
0

flowCRANE > Jeśli tak, to dorzuć 0.5f do którejś współrzędnej w osi Y. Bez względu na to co jest problemem, tak czy siak trzeba go naprawić, aby ten dach ładnie wyglądał, tak czysto piksel artowo. ;)

to błąd SFML gdyż jak ustawiłem tile_border=0 to zniknęły nierówności

screenshot-20241107135328.png


W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
edytowany 3x, ostatnio: tBane
flowCRANE
Zrobię demówkę — tak będzie łatwiej. C++ to nie moja działka.
tBane
ok. Dzięki :-)
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Tuchów
  • Postów:12163
0
tBane napisał(a):

to błąd SFML gdyż jak ustawiłem tile_border=0 to zniknęły nierówności

Na pewno SFML-a? A nie obliczenia związane właśnie z borderem? ;)


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
FA
  • Rejestracja:około 5 lat
  • Ostatnio:3 dni
  • Lokalizacja:warszawa
  • Postów:301
0

1(Napisz algorytm który generuje kratownice, o określonych wymiarach.
2)Napisz fukcje która robi obrót o n stopni.
3)Oraz drugą funkcje która robi translate(przesuwa o odległośc x y).
4)Zostosuj obrót i translate na kratownicy.

5 dopieść racznie dachówki tak by były coool.

W gratisie dostajesz funkcje matematyczne które sie przydadzą na potem oraz kratownice, oraz fukcje kratownicowa do wykorzystanie później np do budowy dróg lub UI.

edytowany 4x, ostatnio: _flamingAccount
tBane
wolałbym jednak moją metodą wygenerować te dachówki
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Tuchów
  • Postów:12163
2

screenshot-20241107160600.png

Zdaje się działać. Kod odpowiedzialny za renderowanie tego wszystkiego wygląda tak:

Kopiuj
procedure TFormMain.DrawTiles(ACanvas: TCanvas; AOrigin: TPoint; ASizeX, ASizeY, AGapX, AGapY, ACountX, ACountY: Integer);
var
  Tile0: TPoint;
  Tile1: TPoint;
  Tile2: TPoint;
  Tile3: TPoint;
  Index: TPoint;
begin
  ACanvas.Pen.Color   := RGBToColor(185, 0, 0);
  ACanvas.Brush.Color := RGBToColor(185, 0, 0);

  Index.X := 0;
  Index.Y := 0;

  while Index.Y < ACountY do
  begin
    while Index.X < ACountX do
    begin
      Tile0.X := AOrigin.X + Index.X * ASizeX + Index.X * AGapX;
      Tile0.Y := AOrigin.Y + Index.Y * ASizeY + Index.Y * AGapY + Index.X * ASizeX + Index.X * AGapX;
      Tile1.X := Tile0.X + ASizeX - 1;
      Tile1.Y := Tile0.Y + ASizeX - 1;
      Tile2.X := Tile0.X + ASizeX - 1;
      Tile2.Y := Tile0.Y + ASizeX - 1 + ASizeY - 1;
      Tile3.X := Tile0.X;
      Tile3.Y := Tile0.Y + ASizeY - 1;

      ACanvas.Polygon([Tile0, Tile1, Tile2, Tile3]);

      Index.X += 1;
    end;

    Index.X := 0;
    Index.Y += 1;
  end;
end;

Jeśli chodzi o parametry tej metody, to AOrigin to współrzędne lewego górnego rogu, od którego rozpoczyna się renderowanie dachówek. ASizeX i ASizeY to szerokość i wysokość jednej dachówki w pikselach. AGapX i AGapY to rozmiar szczeliny pomiędzy sąsiednimi dachówkami, w poziomie i pionie. ACountX i ACountY to liczba dachówek do namalowania (w poziomie i pionie). ACanvas to płótno, na którym demówka maluje (Ty malujesz za pomocą SFML i jego funkcji, więc ten parametr zignoruj).

Jeśli chodzi o zmienne lokalne, to zmienne od Tile0 do Tile3 zawierają współrzędne wierzchołków aktualnie malowanej dachówki. W przypadku malowania wielokątów (poligonów), pamiętaj, że kolejność podawania wierzchołków ma znaczenie. Natomiast zmienna Index zawiera indeks dachówki do namalowania, w poziomie i pionie.

Funkcja ta renderuje dachówki od lewej do prawej, z góry na dół. Każda dachówka jest renderowana pod kątem 45°, tak jak na zrzutach od Ciebie. W załączniku jest skompilowana apka — możesz się pobawić samodzielnie.

W razie czego, renderowanie lewej strony dachu to ten sam algorytm, tyle że dodawanie należy zamienić na odejmowanie (przy obliczaniu współrzędnych). Całkiem możliwe, że wystarczy skorzystać z dodatkowej zmiennej liczbowej z kierunkiem renderowania (1 to dach w prawo, a -1 to dach w lewo) i używać jej jako mnożnika.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
2

Dzięki @flowCRANE za pomoc :-) Poniżej zamieszczam przepisany kod na c++

screenshot-20241107191413.png

Kopiuj
void loadTexture(std::ifstream& file) {
    // check the size (16x16)
    cout << size.x << " " << size.y << "\n";

    short walls_height = 3;

    // create basic image to render house
    sf::Image house_image;
    house_image.create(size.x * 16, (size.y + walls_height*2 + 2) * 16, sf::Color::Transparent);

    // load the wall texture
    sf::Image wall;
    wall.create(32, 32, sf::Color::Transparent);
    wall = getTexture("walls/wooden_wall")->texture->copyToImage();
  
    
    // DRAWING A WALLS
    for (short y = 1; y <= walls_height; y++) {
        for (short x = 0; x < size.x/2; x++) {
            house_image.copy(wall, x*2*16, house_image.getSize().y - y *2*16);
        }
    }

    cout << "\n\n warning! \n";

    // DRAWING A WALLS UNDER THE ROOF
    short height = size.x/4;
    short width = size.x/2;
    short start_x;
    short end_x;

    for (int y = 0; y <= height; y++) {
        start_x = y;
        end_x = width - y - 1;

        for (int x = 0; x < width; x++) {
            if (x >= start_x && x <= end_x) {
                house_image.copy(wall, x * 2 *16, house_image.getSize().y - (y + walls_height + 1) * 2 * 16);
            }
        }
    }

    // DRAWING A ROOF
    sf::Color color = sf::Color(51, 38, 21);

    sf::Vector2f p1(0, walls_height * 2*16);
    sf::Vector2f p2(size.x/2*16, (walls_height+size.x/4) * 2*16);
    sf::Vector2f p3(size.x*16, walls_height * 2*16);
    sf::Vector2f p4(size.x*16, (walls_height +size.y/4 + 1) * 2*16);
    sf::Vector2f p5(size.x / 2 * 16, (walls_height + size.x / 4 + size.y/4 + 1) * 2 * 16);
    sf::Vector2f p6(0, (walls_height + size.y/4 + 1) * 2 * 16);
    
    sf::VertexArray left_quad(sf::Quads, 4);
    left_quad[0].position = p1;
    left_quad[1].position = p2;
    left_quad[2].position = p5;
    left_quad[3].position = p6;
    left_quad[0].color = color;
    left_quad[1].color = color;
    left_quad[2].color = color;
    left_quad[3].color = color;

    sf::VertexArray right_quad(sf::Quads, 4);
    right_quad[0].position = p2;
    right_quad[1].position = p3;
    right_quad[2].position = p4;
    right_quad[3].position = p5;
    right_quad[0].color = color;
    right_quad[1].color = color;
    right_quad[2].color = color;
    right_quad[3].color = color;

    sf::RenderTexture rtex;
    rtex.create(house_image.getSize().x, house_image.getSize().y);
    rtex.draw(left_quad);
    rtex.draw(right_quad);

    // CREATE A TILES

    float tiles_rows = 8;
    float tiles_columns = 8;

    float tile_width = float(size.x)/4.0f*32.0f / tiles_columns;
    float tile_height = float(size.y/4 +1)*32.0f / tiles_rows;
    float tile_border = 1;

    sf::Color color_outside = sf::Color(51, 38, 21);
    sf::Color color_inside = sf::Color(128, 24, 24);
    
    // LEFT SIDE OF ROOF
    for (float y = 0; y < tiles_rows; y += 1) {
        for (float x = 0; x < tiles_columns; x += 1) {
            sf::Vector2f quad_pos(x * tile_width, walls_height * 32 + y * tile_height + x * tile_width);

            // outside of tile
            sf::VertexArray outside(sf::Quads, 4);
            outside[0].position = sf::Vector2f(quad_pos.x, quad_pos.y);
            outside[1].position = sf::Vector2f(quad_pos.x + tile_width, quad_pos.y + tile_width);
            outside[2].position = sf::Vector2f(quad_pos.x + tile_width, quad_pos.y + tile_width + tile_height);
            outside[3].position = sf::Vector2f(quad_pos.x, quad_pos.y + tile_height);
            outside[0].color = color_outside;
            outside[1].color = color_outside;
            outside[2].color = color_outside;
            outside[3].color = color_outside;
            rtex.draw(outside);
            
            // inside of tile
            sf::VertexArray inside(sf::Quads, 4);
            inside[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_border);
            inside[1].position = sf::Vector2f(quad_pos.x + tile_width-tile_border, quad_pos.y + tile_width + tile_border);
            inside[2].position = sf::Vector2f(quad_pos.x + tile_width-tile_border, quad_pos.y + tile_width + tile_height-tile_border);
            inside[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_height - tile_border);
            inside[0].color = color_inside;
            inside[1].color = color_inside;
            inside[2].color = color_inside;
            inside[3].color = color_inside;
            rtex.draw(inside);
        }
    }

    // RIGHT SIDE OF ROOF
    for (float y = 0; y < tiles_rows; y += 1) {
        for (float x = 0; x < tiles_columns; x += 1) {
            sf::Vector2f quad_pos(size.x*16.0f-tile_width - x * tile_width, walls_height * 32 + y * tile_height + x * tile_width);

            // outside of tile
            sf::VertexArray outside(sf::Quads, 4);
            outside[0].position = sf::Vector2f(quad_pos.x, quad_pos.y + tile_width);
            outside[1].position = sf::Vector2f(quad_pos.x + tile_width, quad_pos.y);
            outside[2].position = sf::Vector2f(quad_pos.x + tile_width, quad_pos.y + tile_height);
            outside[3].position = sf::Vector2f(quad_pos.x, quad_pos.y + tile_width + tile_height);
            outside[0].color = color_outside;
            outside[1].color = color_outside;
            outside[2].color = color_outside;
            outside[3].color = color_outside;
            rtex.draw(outside);

            // inside of tile
            sf::VertexArray inside(sf::Quads, 4);
            inside[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_border);
            inside[1].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_border);
            inside[2].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_height - tile_border);
            inside[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_height - tile_border);
            inside[0].color = color_inside;
            inside[1].color = color_inside;
            inside[2].color = color_inside;
            inside[3].color = color_inside;
            rtex.draw(inside);
        }
    }


    sf::Image roof_image = rtex.getTexture().copyToImage();

    house_image.copy(roof_image, 0, 0 ,sf::IntRect(0,0,0,0),true);

    // create main tex
    sf::Texture* tex = new sf::Texture();
    tex->loadFromImage(house_image);

    // create the sprite
    sprite = sf::Sprite();
    sprite.setTexture(*tex);
    sprite.setOrigin(tex->getSize().x / 2, tex->getSize().y);
    sprite.setPosition(position);

}
}

W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
edytowany 3x, ostatnio: tBane
flowCRANE
Nie wolałbyś renderować o jedną dachówkę więcej w bok, tak aby dach wystawał poza ściany?
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Tuchów
  • Postów:12163
1

IMO ten kod da się zoptymalizować. Z tego co widać, kolor pomiędzy dachówkami jest taki sam na całym dachu, więc zamiast malować go dla każdej dachówki z osobna (jako wielokąt), wystarczy go namalować raz — dla całej strony dachu. Dzięki temu jedna strona dachu wymagać będzie wyrenderowania jednego wielokąta (ciemnobrązowe tło, przebijające pomiędzy dachówkami) oraz zadana liczba dachówek. W ten sposób obniżysz złożoność z 2n do n+1, czyli niemal dwukrotnie, a efekt na ekranie będzie taki sam.

Przykład, który podałem wcześniej (snippet z mojej demówki) też da się zoptymalizować — w końcu obliczanie współrzędnej każdej dachówki nie musi oznaczać każdorazowego mnożenia jej indeksu przez rozmiary i offsety. Wystarczy raz policzyć współrzędne (dla pierwszej dachówki w danym rzędzie), a następnie, na koniec każdej iteracji, po prostu przesunąć wierzchołki dachówki w bok i na dół (o określoną liczbę pikseli). Dla osi Y można zrobić to samo — raz policzyć współrzędną Y (dla pierwszego rzędu), a potem, po wyrenderowaniu całego rzędu, inkrementować tę współrzędną o wysokość dachówki.

Kilka zmiennych więcej trzeba będzie użyć, ale koniec końców znacznie mniej obliczeń trzeba będzie wykonać, a to podniesie ogólną wydajność renderowania dachów.

PS: ustawianie kolorów wierzchołków powinieneś przenieść przed pętle, dlatego że ich kolor się nie zmienia. Obecnie w każdej iteracji pętli ustawiasz dla nich w kółko ten sam kolor, co nie ma za bardzo sensu. Ja wiem, że optymalizator może coś takiego wyciąć (loop invariant code motion), ale to nie oznacza, że nie możesz zrobić tego sam i mieć porządek w kodzie. 😉


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
Zobacz pozostały 1 komentarz
flowCRANE
Powinieneś zrobić refactoring tego kodu, bo liczba jego linijek by zmalała i łatwiej byłoby go zrozumieć. Takie rzeczy powinieneś robić na bieżąco, póki w głowie masz wszystkie szczegóły na temat tego jak działa.
tBane
poprawiłem ustawianie koloru i teraz jest to w pętli robione. Poza tym jeszcze pisać kodu nie skończyłem. Ale do tego jutro wrócę, bo dziś już nie mam sił :D
flowCRANE
Spoko. Ot przypominam, że refactoring na bieżąco to bardzo dobra praktyka — finalnie pozwala oszczędzić czas i nerwy. ;)
FA
+1 z reguły refaktoring zabiera tylko kilka % czasu jaki wymaga wymyslenie dzialajcego rozwiazania. Jezeli jestes w takiej sytaucji to refaktoryzuj jak leci. Czas sie wzroci w czytaniu i debugu, a przy okazji poprawisz sobie skilla.
GO
Można renderować od razu w danym położeniu, albo zwykłą teksturę za pomocą macierzy homograficznej zrzutować na kształt dachu. Tak się robi w przetwarzaniu obrazów, żeby uzyskać augmented reality, czyli dowolny obiekt 3d w dowolnej przestrzeni renderować na dowolnym obiekcie pod dowolnym kątem.
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
0

Zrobiłem przerwę między stronami dachu, aby umiejscowić tam jakąś belkę nośną czy jak to się nazywa oraz dodałem tekstury do tilesów. Zrobiłem też naprzemienne rozłożenie dachówek oraz wystawanie ich z lewej i prawej strony, tak aby dach wyglądał bardziej naturalnie. Niestety gdzieś pogubiłem się w obliczeniach (p1-p6) i źle są renderowane quady lewy i prawy dachu (// DRAWING A ROOF) a na pewno źle obliczam p2 i p5 ...

my_house_8.png

Kopiuj
void loadTexture(std::ifstream& file) {

    // check the size
    cout << size.x << " " << size.y << "\n";

    short walls_height = 3;
    
    float tiles_rows = 8;
    float tiles_columns = 8;

    float tile_width = float(size.x) / 4.0f * 32.0f / tiles_columns;
    float tile_height = float(size.y / 4 + 2) * 32.0f / tiles_rows;
    float tile_border = 1;

    sf::Color color_outside = sf::Color::Black; //sf::Color(51, 38, 21);
    sf::Color color_inside = sf::Color(128, 24, 24);

    // create basic image to render house
    sf::Image house_image;
    house_image.create(size.x * 16 + tile_width, (size.y + walls_height*2 + 2) * 16, sf::Color::Transparent);

    // load the wall texture
    sf::Image wall;
    wall.create(32, 32, sf::Color::Transparent);
    wall = getTexture("walls/wooden_wall")->texture->copyToImage();
  
    
    // DRAWING A WALLS
    for (short y = 1; y <= walls_height; y++) {
        for (short x = 0; x < size.x/2; x++) {
            house_image.copy(wall, x*2*16 + tile_width/2.0f, house_image.getSize().y - y *2*16);
        }
    }

    // DRAWING A WALLS UNDER THE ROOF
    short height = size.x/4;
    short width = size.x/2;
    short start_x;
    short end_x;

    for (int y = 0; y <= height; y++) {
        start_x = y;
        end_x = width - y - 1;

        for (int x = 0; x < width; x++) {
            if (x >= start_x && x <= end_x) {
                house_image.copy(wall, x * 2 *16 + tile_width/2.0f, house_image.getSize().y - (y + walls_height + 1) * 2 * 16);
            }
        }
    }

    // DRAWING A ROOF
    sf::Color color = sf::Color::Black;

    sf::Vector2f p1(0, (walls_height-1.0f) * 2.0f *16.0f);
    sf::Vector2f p2(tile_width/2.0f + size.x/2.0f *16.0f, (walls_height-1.0f+size.x/4.0f) * 32.0f + tile_height/2.0f);
    sf::Vector2f p3(tile_width + size.x*16.0f, (walls_height-1.0f) * 32.0f);
    sf::Vector2f p4(tile_width + size.x*16.0f, (walls_height-1.0f) * 32.0f + tiles_rows*tile_height);
    sf::Vector2f p5(tile_width/2.0f + size.x / 2.0f * 16.0f, (walls_height -1.0f + size.x / 4.0f) * 32.0f + tiles_rows*tile_height + tile_height/2.0f);
    sf::Vector2f p6(0, (walls_height-1.0f) * 32.0f + tiles_rows*tile_height);
    
    sf::VertexArray left_quad(sf::Quads, 4);
    left_quad[0].position = p1;
    left_quad[1].position = p2;
    left_quad[2].position = p5;
    left_quad[3].position = p6;

    for (short i = 0; i < 4; i++)
        left_quad[i].color = color;

    sf::VertexArray right_quad(sf::Quads, 4);
    right_quad[0].position = p2;
    right_quad[1].position = p3;
    right_quad[2].position = p4;
    right_quad[3].position = p5;

    for (short i = 0; i < 4; i++)
        right_quad[i].color = color;

    sf::RenderTexture rtex;
    rtex.create(house_image.getSize().x, house_image.getSize().y);
    rtex.draw(left_quad);
    rtex.draw(right_quad);

    // CREATE A TILES
    sf::RenderStates rstate(getTexture("tiles/tile_5_highlands")->texture);

    // LEFT SIDE OF ROOF - EVEN TILES
    for (float x = 0; x < tiles_columns; x += 2) {
        for (float y = 0; y < tiles_rows; y += 1) {

            sf::Vector2f quad_pos(x * tile_width, (walls_height-1.0f) * 32.0f + y * tile_height + x * tile_width);
            
            sf::VertexArray tile(sf::Quads, 4);
            tile[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_border);
            tile[1].position = sf::Vector2f(quad_pos.x + tile_width-tile_border, quad_pos.y + tile_width + tile_border);
            tile[2].position = sf::Vector2f(quad_pos.x + tile_width-tile_border, quad_pos.y + tile_width + tile_height-tile_border);
            tile[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_height - tile_border);
            
            tile[0].texCoords = sf::Vector2f(0, 0);
            tile[1].texCoords = sf::Vector2f(tile_width, 0);
            tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
            tile[3].texCoords = sf::Vector2f(0, tile_height);

            rtex.draw(tile,rstate);
        }
    }

    // LEFT SIDE OF ROOF - ODD TILES
    for (float x = 1; x < tiles_columns; x += 2) {
        
        // bottom tile
        sf::Vector2f bottom_pos(x * tile_width, (walls_height-1.0f) * 32.0f + x * tile_width + tile_height/2.0f);
        sf::VertexArray bottom_tile(sf::Quads, 4);
        bottom_tile[0].position = sf::Vector2f(bottom_pos.x + tile_border, bottom_pos.y - tile_height/2.0f + tile_border);
        bottom_tile[1].position = sf::Vector2f(bottom_pos.x + tile_width - tile_border, bottom_pos.y + tile_width - tile_height/2.0f+tile_border);
        bottom_tile[2].position = sf::Vector2f(bottom_pos.x + tile_width - tile_border, bottom_pos.y + tile_width - tile_border);
        bottom_tile[3].position = sf::Vector2f(bottom_pos.x + tile_border, bottom_pos.y - tile_border);

        bottom_tile[0].texCoords = sf::Vector2f(0, 0);
        bottom_tile[1].texCoords = sf::Vector2f(tile_width, 0);
        bottom_tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
        bottom_tile[3].texCoords = sf::Vector2f(0, tile_height);

        rtex.draw(bottom_tile, rstate);

        // center tiles
        for (float y = 0; y < tiles_rows-1; y += 1) {
        
            sf::Vector2f quad_pos(x * tile_width, (walls_height-1.0f) * 32.0f + y * tile_height + x * tile_width + tile_height/2.0f);

            sf::VertexArray tile(sf::Quads, 4);
            tile[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_border);
            tile[1].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_width + tile_border);
            tile[2].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_width + tile_height - tile_border);
            tile[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_height - tile_border);

            tile[0].texCoords = sf::Vector2f(0, 0);
            tile[1].texCoords = sf::Vector2f(tile_width, 0);
            tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
            tile[3].texCoords = sf::Vector2f(0, tile_height);

            rtex.draw(tile, rstate);
        }

        // top tile
        sf::Vector2f top_pos(x * tile_width, (walls_height-1.0f) * 32.0f + (tiles_rows) * tile_height + x * tile_width - tile_height/2.0f);
        sf::VertexArray top_tile(sf::Quads, 4);
        top_tile[0].position = sf::Vector2f(top_pos.x + tile_border, top_pos.y + tile_border);
        top_tile[1].position = sf::Vector2f(top_pos.x + tile_width-tile_border, top_pos.y + tile_width +tile_border);
        top_tile[2].position = sf::Vector2f(top_pos.x + tile_width-tile_border, top_pos.y + tile_width+tile_height/2.0f-tile_border);
        top_tile[3].position = sf::Vector2f(top_pos.x + tile_border, top_pos.y+tile_height/2.0f-tile_border);

        top_tile[0].texCoords = sf::Vector2f(0, 0);
        top_tile[1].texCoords = sf::Vector2f(tile_width, 0);
        top_tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
        top_tile[3].texCoords = sf::Vector2f(0, tile_height);

        rtex.draw(top_tile, rstate);
    }


    // RIGHT SIDE OF ROOF - EVEN TILES
    for (float x = 0; x < tiles_columns; x += 2) {
        for (float y = 0; y < tiles_rows; y += 1) {
        
            sf::Vector2f quad_pos(size.x*16.0f - x * tile_width, (walls_height-1.0f) * 32.0f + y * tile_height + x * tile_width);
            sf::VertexArray tile(sf::Quads, 4);
            tile[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_border);
            tile[1].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_border);
            tile[2].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_height - tile_border);
            tile[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_height - tile_border);
            
            tile[0].texCoords = sf::Vector2f(0, 0);
            tile[1].texCoords = sf::Vector2f(tile_width, 0);
            tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
            tile[3].texCoords = sf::Vector2f(0, tile_height);

            sf::RenderStates rstate(getTexture("tiles/tile_5_highlands")->texture);
            rtex.draw(tile, rstate);
        }
    }

    // RIGHT SIDE OF ROOF - ODD TILES
    for (float x = 1; x < tiles_columns; x += 2) {

        // bottom tile
        sf::Vector2f bottom_pos(size.x/2.0f*16.0f + x * tile_width, (walls_height - 1.0f + size.x/4.0f) * 32.0f - x * tile_width - tile_height/2.0f);
        sf::VertexArray bottom_tile(sf::Quads, 4);
        bottom_tile[0].position = sf::Vector2f(bottom_pos.x + tile_border, bottom_pos.y + tile_width + tile_border + tile_height/2.0f);
        bottom_tile[1].position = sf::Vector2f(bottom_pos.x + tile_width - tile_border, bottom_pos.y + tile_border + tile_height/2.0f);
        bottom_tile[2].position = sf::Vector2f(bottom_pos.x + tile_width - tile_border, bottom_pos.y + tile_height - tile_border);
        bottom_tile[3].position = sf::Vector2f(bottom_pos.x + tile_border, bottom_pos.y + tile_width + tile_height - tile_border);

        bottom_tile[0].texCoords = sf::Vector2f(0, 0);
        bottom_tile[1].texCoords = sf::Vector2f(tile_width, 0);
        bottom_tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
        bottom_tile[3].texCoords = sf::Vector2f(0, tile_height);

        rtex.draw(bottom_tile, rstate);

        // center tiles
        for (float y = 0; y < tiles_rows - 1; y += 1) {

            sf::Vector2f quad_pos(size.x * 16.0f - x * tile_width, (walls_height-1.0f) * 32.0f + y * tile_height + x * tile_width + tile_height/2.0f);

            sf::VertexArray tile(sf::Quads, 4);
            tile[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_border);
            tile[1].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_border);
            tile[2].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_height - tile_border);
            tile[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_height - tile_border);

            tile[0].texCoords = sf::Vector2f(0, 0);
            tile[1].texCoords = sf::Vector2f(tile_width, 0);
            tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
            tile[3].texCoords = sf::Vector2f(0, tile_height);

            rtex.draw(tile, rstate);
        }

        // top tile
        sf::Vector2f top_pos(size.x / 2.0f * 16.0f + x * tile_width, (walls_height-1.0f+size.x/4.0f)*32.0f + tiles_rows*tile_height - x * tile_width - tile_height/2.0f);
        sf::VertexArray top_tile(sf::Quads, 4);
        top_tile[0].position = sf::Vector2f(top_pos.x + tile_border, top_pos.y + tile_width + tile_border);
        top_tile[1].position = sf::Vector2f(top_pos.x + tile_width - tile_border, top_pos.y + tile_border);
        top_tile[2].position = sf::Vector2f(top_pos.x + tile_width - tile_border, top_pos.y + tile_height/2.0f - tile_border);
        top_tile[3].position = sf::Vector2f(top_pos.x + tile_border, top_pos.y + tile_width + tile_height/2.0f  - tile_border);

        top_tile[0].texCoords = sf::Vector2f(0, 0);
        top_tile[1].texCoords = sf::Vector2f(tile_width, 0);
        top_tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
        top_tile[3].texCoords = sf::Vector2f(0, tile_height);

        rtex.draw(top_tile, rstate);
    }


    sf::Image roof_image = rtex.getTexture().copyToImage();

    house_image.copy(roof_image, 0, 0 ,sf::IntRect(0,0,0,0),true);

    // create main tex
    sf::Texture* tex = new sf::Texture();
    tex->loadFromImage(house_image);

    // create the sprite
    sprite = sf::Sprite();
    sprite.setTexture(*tex);
    sprite.setOrigin(tex->getSize().x / 2, tex->getSize().y);
    sprite.setPosition(position);

}

W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
edytowany 2x, ostatnio: tBane
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Tuchów
  • Postów:12163
1

Wiem, że temat dotyczy algorytmu renderującego dach w sposób dynamiczny, ale może warto zapytać inaczej — czemu dach renderujesz za pomocą wielokątów (każdą dachówkę z osobna), zamiast używać do tego prostokątnych tekstur, czyli tak jak robi się to w tego typu dwuwymiarowych grach a pixelartową oprawą?

Obecnie masz masę obliczeń do wykonania, a do tego jeśli zechcesz, aby dach wyglądał inaczej, to całe te obliczenia trzeba modyfikować. Zamiast tego, powinieneś mieć kafle zawierające dachówki namalowane już pod zadanym kątem i renderować je w formie normalnych prostokątów, tak jakbyś renderował szachownicę. Wystarczy kilka typów kafli, aby wszystko wyrenderować. Jeśli chcesz mieć dodatkowe dekoracje np. na głównej belce, to wystarczy dodać kilka nowych kafli.

W ten sposób dach nie tylko łatwiej byłoby renderować (dwie pętle, łącznie kilka linijek kodu), ale też miałbyś możliwość wygodnego dodania nowego zestawu kafli z dachówkami wyglądającymi inaczej (np. gont bitumiczny zamiast klasycznej dachówki ceramicznej), dachy mógłbyś wyklikać w edytorze, tak jak wszystko inne, dach danego rodzaju mógłby mieć dowolny kolor (ot uzyskany za pomocą modulacji koloru), a do tego w wybranych miejscach mógłby posiadać dekoracje (np. pęknięta dachówka albo dziura w dachu jako osobne kafle). Miałbyś wygodę i elastyczność, a do tego kilka linijek kodu renderującego dowolną kompozycję.

Ogólnie rzecz biorąc, wszystko powinno być renderowane za pomocą kafli (ot prostokątnych tekstur), cały teren i wszystkie obiekty na nim się znajdujące (budynki, drzewa, aktorzy itd.), a to czego nie da się kaflami wyrenderować, powinno być zaimplementowane osobno.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
1

Nie wiem. Po prostu tak zrobiłem i już nie chcę tego zmieniać, bo działa. Najważniejsze jest to, że ten dach jest generowany dynamicznie :-)
Jeszcze pozostało dodać belki. Nie wiem jakie wpisać współrzędne tekstury.

screenshot-20241109150513.png

Kopiuj
// WOODEN BEAMS
// main wooden beam
sf::VertexArray beam(sf::Quads, 4);
sf::Vector2f pos;
sf::Color beam_color = sf::Color(100, 55, 30);
sf::RenderStates rstate2;
rstate2.texture = getTexture("tiles/tile_6")->texture;

pos.x = size.x / 2.f * 16.0f + tile_width/2.0f;
pos.y = (walls_height - 1.0f + size.x / 4.0f) * 32.0f;
beam[0].position = sf::Vector2f(pos.x-tile_width/2.0f, pos.y);
beam[1].position = sf::Vector2f(pos.x+tile_width/2.0f, pos.y);
beam[2].position = sf::Vector2f(pos.x+tile_width/2.0f, pos.y+tiles_rows*tile_height);
beam[3].position = sf::Vector2f(pos.x-tile_width/2.0f, pos.y+tiles_rows*tile_height);

//beam[0].texCoords = ??? ;
//beam[1].texCoords = ??? ;
//beam[2].texCoords = ??? ;
//beam[3].texCoords = ??? ;

rtex.draw(beam, rstate2);

W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
edytowany 2x, ostatnio: tBane
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
1

Dobra. Udało mi się zrobić automatyczne generowanie dachów i działa dla różnych rozmiarów. Załączam dodatkowo kod, może kiedyś komuś się przyda :-)
screenshot-20241109181456.png

Kopiuj
void loadTexture(std::ifstream& file) {

    // check the size
    cout << size.x << " " << size.y << "\n";

    short walls_height = 3;

    float tiles_rows = 16; //size.y / 2;
    float tiles_columns = 16; // size.x / 2;

    float tile_width = float(size.x)/4.0f*32.0f/tiles_columns;
    float tile_height = float(size.y)/2.0f*32.0f/tiles_rows;
    float tile_border = 1;

    sf::Color color_outside = sf::Color::Black; //sf::Color(51, 38, 21);
    sf::Color color_inside = sf::Color(128, 24, 24);

    // create basic image to render house
    sf::Image house_image;
    house_image.create(size.x*16+tile_width, (walls_height+size.x/2.0f)*16.0f+tiles_rows*tile_height+tile_height, sf::Color::Transparent);

    // load the wall texture
    sf::Image wall;
    wall.create(32, 32, sf::Color::Transparent);
    wall = getTexture("walls/wooden_wall")->texture->copyToImage();


    // DRAWING A WALLS
    for (short y = 1; y <= walls_height; y++) {
        for (short x = 0; x < size.x / 2; x++) {
            house_image.copy(wall, x * 2 * 16 + tile_width / 2.0f, house_image.getSize().y - y * 2 * 16);
        }
    }

    // DRAWING A WALLS UNDER THE ROOF
    short height = size.x / 4;
    short width = size.x / 2;
    short start_x;
    short end_x;

    for (int y = 0; y <= height; y++) {
        start_x = y;
        end_x = width - y - 1;

        for (int x = 0; x < width; x++) {
            if (x >= start_x && x <= end_x) {
                house_image.copy(wall, x * 2 * 16 + tile_width / 2.0f, house_image.getSize().y - (y + walls_height + 1) * 2 * 16);
            }
        }
    }

    // DRAWING A ROOF
    sf::Color color = sf::Color::Black;

    sf::Vector2f p1(0, (walls_height - 1.0f) * 2.0f * 16.0f);
    sf::Vector2f p2(tile_width / 2.0f + size.x / 2.0f * 16.0f, (walls_height - 1.0f + size.x / 4.0f) * 32.0f + tile_height / 4.0f);
    sf::Vector2f p3(tile_width + size.x * 16.0f, (walls_height - 1.0f) * 32.0f);
    sf::Vector2f p4(tile_width + size.x * 16.0f, (walls_height - 1.0f) * 32.0f + tiles_rows * tile_height);
    sf::Vector2f p5(tile_width / 2.0f + size.x / 2.0f * 16.0f, (walls_height - 1.0f + size.x / 4.0f) * 32.0f + tiles_rows * tile_height + tile_height / 4.0f);
    sf::Vector2f p6(0, (walls_height - 1.0f) * 32.0f + tiles_rows * tile_height);

    sf::VertexArray left_quad(sf::Quads, 4);
    left_quad[0].position = p1;
    left_quad[1].position = p2;
    left_quad[2].position = p5;
    left_quad[3].position = p6;

    for (short i = 0; i < 4; i++)
        left_quad[i].color = color;

    sf::VertexArray right_quad(sf::Quads, 4);
    right_quad[0].position = p2;
    right_quad[1].position = p3;
    right_quad[2].position = p4;
    right_quad[3].position = p5;

    for (short i = 0; i < 4; i++)
        right_quad[i].color = color;

    sf::RenderTexture rtex;
    rtex.create(house_image.getSize().x, house_image.getSize().y);
    rtex.draw(left_quad);
    rtex.draw(right_quad);

    // CREATE A TILES
    sf::RenderStates rstate(getTexture("tiles/tile_5_highlands")->texture);

    // LEFT SIDE OF ROOF - EVEN TILES
    for (float x = 0; x < tiles_columns; x += 2) {
        for (float y = 0; y < tiles_rows; y += 1) {

            sf::Vector2f quad_pos(x * tile_width, (walls_height - 1.0f) * 32.0f + y * tile_height + x * tile_width);

            sf::VertexArray tile(sf::Quads, 4);
            tile[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_border);
            tile[1].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_width + tile_border);
            tile[2].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_width + tile_height - tile_border);
            tile[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_height - tile_border);

            tile[0].texCoords = sf::Vector2f(0, 0);
            tile[1].texCoords = sf::Vector2f(tile_width, 0);
            tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
            tile[3].texCoords = sf::Vector2f(0, tile_height);

            rtex.draw(tile, rstate);
        }
    }

    // LEFT SIDE OF ROOF - ODD TILES
    for (float x = 1; x < tiles_columns; x += 2) {

        // bottom tile
        sf::Vector2f bottom_pos(x * tile_width, (walls_height - 1.0f) * 32.0f + x * tile_width + tile_height / 2.0f);
        sf::VertexArray bottom_tile(sf::Quads, 4);
        bottom_tile[0].position = sf::Vector2f(bottom_pos.x + tile_border, bottom_pos.y - tile_height / 2.0f + tile_border);
        bottom_tile[1].position = sf::Vector2f(bottom_pos.x + tile_width - tile_border, bottom_pos.y + tile_width - tile_height / 2.0f + tile_border);
        bottom_tile[2].position = sf::Vector2f(bottom_pos.x + tile_width - tile_border, bottom_pos.y + tile_width - tile_border);
        bottom_tile[3].position = sf::Vector2f(bottom_pos.x + tile_border, bottom_pos.y - tile_border);

        bottom_tile[0].texCoords = sf::Vector2f(0, 0);
        bottom_tile[1].texCoords = sf::Vector2f(tile_width, 0);
        bottom_tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
        bottom_tile[3].texCoords = sf::Vector2f(0, tile_height);

        rtex.draw(bottom_tile, rstate);

        // center tiles
        for (float y = 0; y < tiles_rows - 1; y += 1) {

            sf::Vector2f quad_pos(x * tile_width, (walls_height - 1.0f) * 32.0f + y * tile_height + x * tile_width + tile_height / 2.0f);

            sf::VertexArray tile(sf::Quads, 4);
            tile[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_border);
            tile[1].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_width + tile_border);
            tile[2].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_width + tile_height - tile_border);
            tile[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_height - tile_border);

            tile[0].texCoords = sf::Vector2f(0, 0);
            tile[1].texCoords = sf::Vector2f(tile_width, 0);
            tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
            tile[3].texCoords = sf::Vector2f(0, tile_height);

            rtex.draw(tile, rstate);
        }

        // top tile
        sf::Vector2f top_pos(x * tile_width, (walls_height - 1.0f) * 32.0f + tiles_rows * tile_height + x * tile_width - tile_height / 2.0f);
        sf::VertexArray top_tile(sf::Quads, 4);
        top_tile[0].position = sf::Vector2f(top_pos.x + tile_border, top_pos.y + tile_border);
        top_tile[1].position = sf::Vector2f(top_pos.x + tile_width - tile_border, top_pos.y + tile_width + tile_border);
        top_tile[2].position = sf::Vector2f(top_pos.x + tile_width - tile_border, top_pos.y + tile_width + tile_height / 2.0f - tile_border);
        top_tile[3].position = sf::Vector2f(top_pos.x + tile_border, top_pos.y + tile_height / 2.0f - tile_border);

        top_tile[0].texCoords = sf::Vector2f(0, 0);
        top_tile[1].texCoords = sf::Vector2f(tile_width, 0);
        top_tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
        top_tile[3].texCoords = sf::Vector2f(0, tile_height);

        rtex.draw(top_tile, rstate);
    }


    // RIGHT SIDE OF ROOF - EVEN TILES
    for (float x = 0; x < tiles_columns; x += 2) {
        for (float y = 0; y < tiles_rows; y += 1) {

            sf::Vector2f quad_pos(size.x * 16.0f - x * tile_width, (walls_height - 1.0f) * 32.0f + y * tile_height + x * tile_width);
            sf::VertexArray tile(sf::Quads, 4);
            tile[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_border);
            tile[1].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_border);
            tile[2].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_height - tile_border);
            tile[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_height - tile_border);

            tile[0].texCoords = sf::Vector2f(0, 0);
            tile[1].texCoords = sf::Vector2f(tile_width, 0);
            tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
            tile[3].texCoords = sf::Vector2f(0, tile_height);

            sf::RenderStates rstate(getTexture("tiles/tile_5_highlands")->texture);
            rtex.draw(tile, rstate);
        }
    }

    // RIGHT SIDE OF ROOF - ODD TILES
    for (float x = 1; x < tiles_columns; x += 2) {

        // bottom tile
        sf::Vector2f bottom_pos(size.x / 2.0f * 16.0f + x * tile_width, (walls_height - 1.0f + size.x / 4.0f) * 32.0f - x * tile_width - tile_height / 2.0f);
        sf::VertexArray bottom_tile(sf::Quads, 4);
        bottom_tile[0].position = sf::Vector2f(bottom_pos.x + tile_border, bottom_pos.y + tile_width + tile_border + tile_height / 2.0f);
        bottom_tile[1].position = sf::Vector2f(bottom_pos.x + tile_width - tile_border, bottom_pos.y + tile_border + tile_height / 2.0f);
        bottom_tile[2].position = sf::Vector2f(bottom_pos.x + tile_width - tile_border, bottom_pos.y + tile_height - tile_border);
        bottom_tile[3].position = sf::Vector2f(bottom_pos.x + tile_border, bottom_pos.y + tile_width + tile_height - tile_border);

        bottom_tile[0].texCoords = sf::Vector2f(0, 0);
        bottom_tile[1].texCoords = sf::Vector2f(tile_width, 0);
        bottom_tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
        bottom_tile[3].texCoords = sf::Vector2f(0, tile_height);

        rtex.draw(bottom_tile, rstate);

        // center tiles
        for (float y = 0; y < tiles_rows - 1; y += 1) {

            sf::Vector2f quad_pos(size.x * 16.0f - x * tile_width, (walls_height - 1.0f) * 32.0f + y * tile_height + x * tile_width + tile_height / 2.0f);

            sf::VertexArray tile(sf::Quads, 4);
            tile[0].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_border);
            tile[1].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_border);
            tile[2].position = sf::Vector2f(quad_pos.x + tile_width - tile_border, quad_pos.y + tile_height - tile_border);
            tile[3].position = sf::Vector2f(quad_pos.x + tile_border, quad_pos.y + tile_width + tile_height - tile_border);

            tile[0].texCoords = sf::Vector2f(0, 0);
            tile[1].texCoords = sf::Vector2f(tile_width, 0);
            tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
            tile[3].texCoords = sf::Vector2f(0, tile_height);

            rtex.draw(tile, rstate);
        }

        // top tile
        sf::Vector2f top_pos(size.x / 2.0f * 16.0f + x * tile_width, (walls_height - 1.0f + size.x / 4.0f) * 32.0f + tiles_rows * tile_height - x * tile_width - tile_height / 2.0f);
        sf::VertexArray top_tile(sf::Quads, 4);
        top_tile[0].position = sf::Vector2f(top_pos.x + tile_border, top_pos.y + tile_width + tile_border);
        top_tile[1].position = sf::Vector2f(top_pos.x + tile_width - tile_border, top_pos.y + tile_border);
        top_tile[2].position = sf::Vector2f(top_pos.x + tile_width - tile_border, top_pos.y + tile_height / 2.0f - tile_border);
        top_tile[3].position = sf::Vector2f(top_pos.x + tile_border, top_pos.y + tile_width + tile_height / 2.0f - tile_border);

        top_tile[0].texCoords = sf::Vector2f(0, 0);
        top_tile[1].texCoords = sf::Vector2f(tile_width, 0);
        top_tile[2].texCoords = sf::Vector2f(tile_width, tile_height);
        top_tile[3].texCoords = sf::Vector2f(0, tile_height);

        rtex.draw(top_tile, rstate);
    }

    // WOODEN BEAMS
    // main wooden beam
    sf::VertexArray beam(sf::Quads, 4);
    sf::Vector2f pos;

    pos.x = size.x / 2.f * 16.0f + tile_width/2.0f;
    pos.y = (walls_height - 1.0f + size.x / 4.0f) * 32.0f;
    beam[0].position = sf::Vector2f(pos.x-tile_width/2.0f, pos.y);
    beam[1].position = sf::Vector2f(pos.x+tile_width/2.0f, pos.y);
    beam[2].position = sf::Vector2f(pos.x+tile_width/2.0f, pos.y+tiles_rows*tile_height);
    beam[3].position = sf::Vector2f(pos.x-tile_width/2.0f, pos.y+tiles_rows*tile_height);
    
    for (short i = 0; i < 4; i++)
        beam[i].color = sf::Color::Black;

    rtex.draw(beam);

    for (float y = 0; y < tiles_rows; y+=1) {
        sf::VertexArray tile(sf::Quads, 4);
        tile[0].position = sf::Vector2f(size.x/2.0f*16.0f+tile_border, (walls_height-1.0f+size.x/4.0f)*32.0f+y*tile_height+tile_border);
        tile[1].position = sf::Vector2f(size.x/2.0f*16.0f+tile_width-tile_border, (walls_height-1.0f+size.x/4.0f)*32.0f+y*tile_height+tile_border);
        tile[2].position = sf::Vector2f(size.x/2.0f*16.0f+tile_width-tile_border, (walls_height-1.0f+size.x/4.0f)*32.0f+y*tile_height+tile_height-tile_border);
        tile[3].position = sf::Vector2f(size.x/2.0f*16.0f+tile_border, (walls_height-1.0f+size.x/4.0f)*32.0f+y*tile_height+tile_height-tile_border);
        
        for (short i = 0; i < 4; i++)
            tile[i].texCoords = beam[i].position;

        rtex.draw(tile, rstate);
    }

    // top-center quad
    beam[0].position = sf::Vector2f(pos.x-tile_width/2.0f, pos.y-tile_height/4.0f);
    beam[1].position = sf::Vector2f(pos.x+tile_width/2.0f, pos.y-tile_height/4.0f);
    beam[2].position = sf::Vector2f(pos.x+tile_width/2.0f, pos.y);
    beam[3].position = sf::Vector2f(pos.x-tile_width/2.0f, pos.y);

    for (short i = 0; i < 4; i++)
        beam[i].texCoords = beam[i].position;

    rtex.draw(beam, rstate);

    // top-left beam
    beam[0].position = sf::Vector2f(pos.x-tile_width/2.0f-tiles_columns*tile_width, pos.y-tile_height/4.0f-size.x/4.0f*32.0f);
    beam[1].position = sf::Vector2f(pos.x-tile_width/2.0f, pos.y-tile_height/4.0f);
    beam[2].position = sf::Vector2f(pos.x-tile_width/2.0f, pos.y);
    beam[3].position = sf::Vector2f(pos.x-tile_width/2.0f-tiles_columns*tile_width, pos.y-size.x/4.0f*32.0f);
    
    for (short i = 0; i < 4; i++)
        beam[i].texCoords = beam[i].position;

    rtex.draw(beam, rstate);

    // top-right beam
    beam[0].position = sf::Vector2f(pos.x+tile_width/2.0f+tiles_columns*tile_width, pos.y-tile_height/4.0f-size.x/4.0f*32.0f);
    beam[1].position = sf::Vector2f(pos.x+tile_width/2.0f, pos.y-tile_height/4.0f);
    beam[2].position = sf::Vector2f(pos.x+tile_width/2.0f, pos.y);
    beam[3].position = sf::Vector2f(pos.x+tile_width/2.0f+tiles_columns*tile_width, pos.y-size.x/4.0f*32.0f);
    
    for (short i = 0; i < 4; i++)
        beam[i].texCoords = beam[i].position;

    rtex.draw(beam, rstate);

    sf::Image roof_image = rtex.getTexture().copyToImage();

    house_image.copy(roof_image, 0, 0, sf::IntRect(0, 0, 0, 0), true);

    // create main tex
    sf::Texture* tex = new sf::Texture();
    tex->loadFromImage(house_image);

    // create the sprite
    sprite = sf::Sprite();
    sprite.setTexture(*tex);
    sprite.setOrigin(tex->getSize().x / 2, tex->getSize().y);
    sprite.setPosition(position);

}

W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
edytowany 1x, ostatnio: tBane
flowCRANE
Obecny wygląd dachu jest zdecydowanie lepszy niż ten na początku. Na początku dach wyglądał super prymitywnie i w ogóle dachu nie przypominał. Teraz wygląda profesjonalnie! ;)
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
0

Edytowałem generowanie dachu w taki sposób, że teraz dach jest dwukrotnie niższy oraz środkowe dachówki zaczynają się od niepełnej .. dachówki.
Mój problem polega na tym, że generowane dachy budynków w mojej grze wyglądają nienaturalnie. Nie jestem artystą i za bardzo nie jestem w stanie dostrzec błędu w swoim rozumowaniu stąd moje pytanie. Co w tym dachu jest złego i jak to naprawić ?

sss.png

  • sss.png (45 KB) - ściągnięć: 2

W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
Zobacz pozostałe 4 komentarze
FA
Dach ma zerowa grubość. I nie wystaje przed budynek a zboktów wystaje, brak perspektywy z tym zwaizanej
FA
nawet nie chodzi(głownie)o dachówki tylko o obrys dachu
FA
Tu masz taka sama konstrukcje jak towja ale perspektywe zapeniano cienowaniem: https://tiny.pl/f9f19-s7
WhiteLightning
dach wyglada jakby byl szerszy z tylu
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Tuchów
  • Postów:12163
0

Nie ma nic złego w tym dachu — wygląda prawidłowo, zgodnie z przyjętą perspektywą. Tzn. z jej brakiem, ale mowa o rzucie ortograficznym, pod kątem 45°. Po prostu przy takich parametrach kamery, dachy powinny wyglądać tak jak na pokazanym zrzucie.

Jeśli używasz kafli kwadratowych, to budynek o kwadratowej podstawie będzie miał kształt kwadratu na ekranie. Dach będzie zgodny z nim, więc będzie przykrywał tę kwadratową powierzchnię, przez co będzie wyglądał na nienaturalnie długi (w głąb ekranu). Matematycznie wszystko się zgadza, ale patrząc na ekran mózg sam siebie oszukuje, bo próbuje zastosować perspektywę i szuka głębi, mimo, że ta nie jest używana.

Jeśli nie podoba Ci się obecny efekt, to zamiast kwadratowych kafli, zastosuj prostokątne (niższe niż szersze), a ich zawartość namaluj w taki sposób, aby udawały, że kamera nie patrzy na nie pod kątem 45°, a mniejszym (tak jakby była niżej gruntu). W ten sposób dach na ekranie będzie miał taką samą szerokość jak obecnie, ale mniejszą wysokość, co będzie wyglądać bardziej naturalnie.

Tutaj masz przykład tego o czym piszę:

https://www.pinterest.com/pin/stoneshard-stoneshard-on-x--365354588532159360/
screenshot-20241122135132.png

Zwróć uwagę na skrzydła pionowe — wyglądają naturalnie, jako wyobrażane w głowie bryły sprawiają wrażenie wysokich i długich, ale nie nienaturalnie głębokich. Wszystko dlatego, że namalowane są w taki sposób, jakby kamera patrzyła na nie pod kątem ~30°, a nie 45°.

W razie gdybyś chciał zmienić kształt kafli z kwadratowych na prostokątne, to pamiętaj, że będziesz musiał odpowiednio przystosować do tego logikę sterowania postacią i potworkami. Wszystko co będzie się poruszać w pionie na ekranie, musi się przesuwać o mniejszy offset niż w poziomie. Dla przykładu, jeśli użyjesz kafli prostokątnych w rozmiarze 2n x n (dwukrotnie szersze niż wysokość), kamera będzie udawać że jest połową 45° (czyli 22.5°, dwa razy bliżej gruntu), a ruch gracza na pełnej prędkości w górę musi być dzielony przez pół. Czyli jeśli np. szybkość gracza wynosi 10px na klatkę, to kiedy idzie w bok, dodajesz/odejmujesz jego pozycji 10px, natomiast jeśli idzie w górę/dół, to tylko 5px. Taki dzielnik/mnożnik możesz ustalić z góry i sobie hardkodować.

Przy okazji tutaj masz ilustrację tego, co proponowałem Ci jakiś czas temu w tym wątku, czyli porzucenie renderowania dachówek z osobna na rzecz tekstur i renderowania ich w formie prostej macierzy na ekranie, zamiast przy użyciu rozciągania tekstur. Nie dość, że prześliczne te budynki, to w dodatku łatwo można zrobić tego typu zestaw kafli i wyrenderować to wszystko, bez żadnego rozciągania.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
WhiteLightning
dokladnie, doklada sobie niepotrzebnej roboty
flowCRANE
Ale za to przynajmniej posprawdza sobie różne rzeczy i to jak wyglądają na ekranie, a nie tylko w głowie. ;)
GO
W sumie to ładnie wygląda też bym nic nie zmieniał, gierki 2d tak wyglądają i tyle.
flowCRANE
Światłocień by się przydał, żeby wyglądały bardziej naturalnie.
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:2 dni
0

Co tu się w tym temacie odwala, chcesz żeby te kafelki się oddzielnie animowały albo np psuły od tornada czy coś? Bo nie widzę sensu w tworzeniu każdej dachówki jako osobnego elementu. Czemu po prostu nie zrobisz powtarzalnej tekstury dachu? Teraz masz mnóstwo zbędnego kodu, brzydszy efekt i gorszy performance.


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 1x, ostatnio: obscurity
tBane
Tester Beta
  • Rejestracja:ponad rok
  • Ostatnio:około godziny
  • Postów:288
0

@obscurity Bo nie umiem. Z resztą już prawie zrobiłem generowanie dachu więc nie widzę sensu poprawiać kod, który wywoływany jest tylko raz :-)
Dodałem cieniowanie tak jak mi doradzano.

RPG2D 184.png


W wolnych chwilach od codzienności programuję hobbystycznie Edytor gier RPG 2D.
Technologie, z których korzystam to C++ oraz SFML 2.X.
obscurity
no ty wywołujesz kod raz, ale komputer musi przetwarzać te obiekty w pętli z osobna w każdej klatce, kilkadziesiąt razy na sekunde. To raczej pestka dla współczesnych CPU i GPU zwłaszcza jak na ekranie masz tylko dwa takie dachy, ale jak zaczniesz w ten sposób generować źdźbła trawy to już może być problem
tBane
Jakbyś przeczytał kod, który wrzuciłem, to wiedziałbyś, że ja generuje tekstury budynków. Każda tekstura jest generowana tylko raz w konstruktorze i przypisywana do sprajta, co jest optymalne. Program nie zacina i nie będzie zacinał w trakcie pracy.
FA
Wyglada duzo lepiej. Ogolnie jak robisz oswietlenie to musisz zakdowac sobie w głowie gdzie jest zrodło swiatla a potem konsekwetnie site tego trzymac. W tym wypadku jezeli cieniujesz dach lewo prawo, to cien z przodu budnku jest zły. tez powinien róznic sie lewo prawo. Na przykładzie ktory podawałem mozesz zauwazyc ze lewo okno i prawe okno maja inne odcienie niebieskiego co przypadkiem lub nie uzpełnie informacje o oswietleniu i perspektywie. Nie masz tez cienia pod budynkiem. https://i.pinimg.com/originals/a3/4e/af/a34eafc89dab99ff6e5fbd08152969ed.jpg
obscurity
to nie kumam czego nie umiesz? Nie umiesz nałożyć gotowej tekstury a umiesz ją wygenerować i nałożyć dynamicznie? Jakbyś ją zrobił w programie graficznym to by lepiej wyglądało bo mógłbyś dodać jakieś niedoskonałości itp, najgorzej wyglądają takie powtarzające się patterny. furious wyżej wrzucił przykłady fajnie wyglądających dachów
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Tuchów
  • Postów:12163
1

Ocieniowany dach wygląda dużo lepiej. Ale jest jeden problem — dach zdaje się być oświetlony z prawej strony, ale cień rzucany przez dach na jego ścianę pokazuje, że jednak źródło światła jest nad nim, a nie z boku. To samo jeśli chodzi o cienie rzucane przez inne obiekty, takie jak choćby wcześniej omawiane drzewa i potworki, których cienie rzucane są prosto w górę (na ekranie), a więc tak jakby źródło światła było nad nimi.

Światłocień dodaje realizmu i jak najbardziej jest wartością dodaną, ale musisz dbać o to, aby był spójny.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
Spine
  • Rejestracja:prawie 22 lata
  • Ostatnio:17 minut
  • Postów:6626
0
tBane napisał(a):

Dobra. Udało mi się zrobić automatyczne generowanie dachów i działa dla różnych rozmiarów. Załączam dodatkowo kod, może kiedyś komuś się przyda :-)
screenshot-20241109181456.png

Kopiuj
//...

Gdybyś teksturował płaszczyznę w Blenderze, uniknąłbyś pisania tony kodu dla takich rzeczy.

Wystarczyłoby Ci, gdybyś zaimplementował obsługę plików Wavefront OBJ - najprostszy w implementacji tekstowy format modeli 3D. Wystarczy parsować od jakiej literki zaczynają się linie i wczytać dane do odpowiednich tablic.
Blender ma eksporter tego formatu. Tak wygląda wyeksportowany obiekt (przed eksportem quady zamieniłem na trójkąty):

Kopiuj
# Blender 4.0.1
# www.blender.org
mtllib dachowka.mtl
o Dach.001
v -2.500000 1.500000 0.000000
v -2.500000 -0.500000 0.000000
v -2.000000 0.000000 0.000000
v -3.000000 -1.000000 0.000000
v -2.000000 2.000000 0.000000
v -3.000000 1.000000 0.000000
v -2.250000 -0.250000 0.000000
v -2.750000 -0.750000 0.000000
v -2.250000 1.750000 0.000000
v -2.750000 1.250000 0.000000
v -2.375000 -0.375000 0.000000
v -2.875000 -0.875000 0.000000
v -2.125000 1.875000 0.000000
v -2.625000 1.375000 0.000000
v -2.125000 -0.125000 0.000000
v -2.625000 -0.625000 0.000000
v -2.375000 1.625000 0.000000
v -2.875000 1.125000 0.000000
v -3.500000 1.500000 0.000000
v -3.500000 -0.500000 0.000000
v -4.000000 0.000000 0.000000
v -4.000000 2.000000 0.000000
v -3.750000 -0.250000 0.000000
v -3.250000 -0.750000 0.000000
v -3.750000 1.750000 0.000000
v -3.250000 1.250000 0.000000
v -3.625000 -0.375000 0.000000
v -3.125000 -0.875000 0.000000
v -3.875000 1.875000 0.000000
v -3.375000 1.375000 0.000000
v -3.875000 -0.125000 0.000000
v -3.375000 -0.625000 0.000000
v -3.625000 1.625000 0.000000
v -3.125000 1.125000 0.000000
vn -0.0000 -0.0000 1.0000
vt 1.000000 -3.500000
vt 0.000000 4.500000
vt 0.000000 -3.500000
vt 1.000000 -4.000000
vt 0.000000 4.000000
vt 0.000000 -4.000000
vt 1.000000 4.500000
vt 1.000000 4.000000
s 0
usemtl DachMaterial
f 3/1/1 13/2/1 15/3/1
f 2/1/1 14/2/1 16/3/1
f 8/1/1 18/2/1 12/3/1
f 7/1/1 17/2/1 11/3/1
f 11/4/1 1/5/1 2/6/1
f 12/4/1 6/5/1 4/6/1
f 16/4/1 10/5/1 8/6/1
f 15/4/1 9/5/1 7/6/1
f 3/1/1 5/7/1 13/2/1
f 2/1/1 1/7/1 14/2/1
f 8/1/1 10/7/1 18/2/1
f 7/1/1 9/7/1 17/2/1
f 11/4/1 17/8/1 1/5/1
f 12/4/1 18/8/1 6/5/1
f 16/4/1 14/8/1 10/5/1
f 15/4/1 13/8/1 9/5/1
f 21/1/1 31/3/1 29/2/1
f 20/1/1 32/3/1 30/2/1
f 24/1/1 28/3/1 34/2/1
f 23/1/1 27/3/1 33/2/1
f 27/4/1 20/6/1 19/5/1
f 28/4/1 4/6/1 6/5/1
f 32/4/1 24/6/1 26/5/1
f 31/4/1 23/6/1 25/5/1
f 21/1/1 29/2/1 22/7/1
f 20/1/1 30/2/1 19/7/1
f 24/1/1 34/2/1 26/7/1
f 23/1/1 33/2/1 25/7/1
f 27/4/1 19/5/1 33/8/1
f 28/4/1 6/5/1 34/8/1
f 32/4/1 26/5/1 30/8/1
f 31/4/1 25/5/1 29/8/1

Twoja tekstura musiałaby być załadowana z wrap mode nie jako CLAMP, tylko REPEAT i wtedy teksturką jednej dachówki łatwo obskoczysz cały dach ustawiając UV face'ów na wartości większe niż 1.

Zrobiłem w Blenderze 4.0 przykład:
screenshot-20241123011001.png

screenshot-20241123011121.png

screenshot-20241123011206.png

screenshot-20241123011248.png

Plik *.blend: dachowka.zip
Tekstura dachówki:
dachowka.png


🕹️⌨️🖥️🖱️🎮
edytowany 2x, ostatnio: Spine
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)