• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

poprawienie wydajności prostej konsolowej gierki w c++

Object Storage Arubacloud
0 głosów
722 wizyt
pytanie zadane 10 marca 2017 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)

Hej ,ostatnio zabrałem się za pisanie swojej pierwszej banalnej gry w c++ , jest bardzo prosta ,polega tylko na omijaniu spadających obiektów . Na początek (w trakcie tworzenia gry) nie przejmowałem się zbytnio migającym ekranem konsoli . Teraz jednak chciał bym się skupić na poprawie wydajności gry . Słyszałem o podwójnym buforowaniu , jednak nie wiem jak się za to zabrać . Dziękuje za wszelką pomoc i komentarze laugh na dole podałem kod gry , wiem jest fatalny :) 

 

#include <iostream>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>

using namespace std;

void fail(int p)
{
    system("cls");
    cout<<"koniec gry ,no niestety ):"<<endl;
    cout<<"suma zdobytych ponktow : "<<p<<endl;
    cout<<"ale dobrze ci szlo (:";
    getch();
    getch();
    exit(0);
}

void game_end(int px,int py,int mx,int my,int mx2,int my2,int mx3,int my3,int p)  //sprawdzenie czy meteoryty nie sa rowne graczowi
{
    if((px==mx||px==mx2||px==mx3)&&(py==my||py==my2||py==my3))
    {
        fail(p);
    }
}

void terrain_generator(int player_x,int player_y,int monster_x,int monster_y,int monster_x2,int monster_y2, int monster_x3,int monster_y3)
{
    int z = 20;                 //generowanie planszy (tablic)
    char pole[z][z];

    char player_intervace = 30;
    char monster_intervace = 254;

    for(int i=0; i<z; i++)
    {
        for(int j=0; j<z; j++)
        {
            pole[i][j]=' ';
        }
    }

    pole[player_x][player_y]=player_intervace;

    pole[monster_x][monster_y]=monster_intervace;
    pole[monster_x2][monster_y2]=monster_intervace;
    pole[monster_x3][monster_y3]=monster_intervace;

    for(int i=0; i<z; i++)
    {
        for(int j=0; j<z; j++)
        {
            cout<<pole[i][j];
        }
        cout<<endl;
    }
}

void try_only_monster_y_generator(int &monster_x, int &monster_y,int &monster_x2, int &monster_y2, int &monster_x3, int &monster_y3)
{
    srand(time(NULL)); //nadawanie meteorytom losowych wartoœci

    monster_x=0;
    monster_x2=0;
    monster_x3=0;

    monster_y=rand()%20;
    monster_y2=rand()%20;
    monster_y3=rand()%20;

}

void monster_logic(int &monster_x, int &monster_y,int &monster_x2, int &monster_y2,int &monster_x3, int &monster_y3,int player_x,int player_y)
{
    if(monster_x>18 || monster_x2>18 || monster_x3>18) try_only_monster_y_generator(monster_x, monster_y,monster_x2, monster_y2,monster_x3, monster_y3);
    else monster_x++;
    monster_x2++;
    monster_x3++; //ruch meteorytow dopuki nie s¹ na samym dole
}

int render_monsters_for_start()
{
    srand(time(NULL)); //generowanie meteorytow na sam poczatek gry
    int x = rand()%20;
    return x;
}

void gra()
{
    int player_x = 17; //poczatkowe pozycje elementow
    int player_y = 10;

    int monster_x = 0;
    int monster_y = render_monsters_for_start();

    int monster_x2 = 0;
    int monster_y2 = render_monsters_for_start();

    int monster_x3 = 0;
    int monster_y3 = render_monsters_for_start();

    char znak = 0;

    int punkty=0;

    while(true) //gowna petla gry
    {
        system("cls");
        terrain_generator(player_x,player_y,monster_x,monster_y,monster_x2,monster_y2,monster_x3,monster_y3);
        monster_logic(monster_x,monster_y,monster_x2,monster_y2,monster_x3,monster_y3,player_x,player_y); //ruch potworow
        game_end(player_x,player_y,monster_x,monster_y,monster_x2,monster_y2,monster_x3,monster_y3,punkty);

        if (kbhit()==0)   // nie wcisnieto klawisza
        {
            continue;
        }
        znak = getch();

        if(znak=='A') //gdy jest wcisniety caps-lock
        {
            znak='a';
        }
        if(znak=='D')
        {
            znak='d';
        }


        switch(znak) //poruszanie graczem
        {
        case 'a':
        {
            if(player_y>0) player_y--;
            else player_y = 0;
        }
        break;

        case 'd':
        {
            if(player_y<19) player_y++;
            else player_y = 19;
        }
        break;
        }

        punkty++;
    }
}

void menu()
{
    cout<<"######    #######   #######  #  #  #########   ######### "<<endl;
    cout<<"#    #    #     #   #        # #   #               #     "<<endl;
    cout<<"#    #    #     #   #        ##    #               #     "<<endl;
    cout<<"######    #     #   #        #     #########       #     "<<endl;
    cout<<"##        #     #   #        #     #########       #     "<<endl;
    cout<<"# #       #     #   #        ##    #               #     "<<endl;
    cout<<"#  #      #     #   #        # #   #               #     "<<endl;
    cout<<"#   #     #######   #######  #  #  #########       #     "<<endl;
    cout<<endl;
    cout<<endl;

    cout<<"witamy w grze rocket v0.1 (moja pierwsza gra)"<<endl;
    cout<<"celem gry jest unikanie spadajacych meteorytow"<<endl;

    cout<<endl;
    cout<<"kliknij dowolny klawisz aby zaczac : "<<endl;
    getch();
    system("cls");
}

int main()
{
    system("color 0b");
    menu();
    gra();

    return 0;
}

 

2 odpowiedzi

0 głosów
odpowiedź 10 marca 2017 przez tangarr Mędrzec (154,860 p.)
wybrane 10 marca 2017 przez Jakub 0
 
Najlepsza

Przeanalizuj sobie moje rozwiązanie (zrobione tak na szybko).

#include <iostream>
#include <windows.h>
#include <conio.h>

using namespace std;

class Bufor {
public:
    Bufor(int rows, int cols) {
        mHandle = GetStdHandle( STD_OUTPUT_HANDLE );
        CONSOLE_CURSOR_INFO cursorInfo;
        cursorInfo.bVisible = FALSE;
        cursorInfo.dwSize = 100;
        SetConsoleCursorInfo(mHandle, &cursorInfo);
        mRows = rows;
        mCols = cols;
        mBuffor1 = new char*[rows];
        mBuffor2 = new char*[rows];
        for (int i=0; i<rows; i++) {
            mBuffor1[i] = new char[cols];
            mBuffor2[i] = new char[cols];
            for (int j=0;j<cols;j++) {
                mBuffor1[i][j] = ' ';
                mBuffor2[i][j] = '@';
            }
        }
        x=y=0;
    }
    void swap() {
        COORD coord;
        char **tmp = mBuffor1;
        mBuffor1 = mBuffor2;
        mBuffor2 = tmp;
        for (int i=0; i<mRows; i++) {
            for (int j=0; j<mCols; j++) {
                if (mBuffor1[i][j] != mBuffor2[i][j]) {
                    coord.X = j;
                    coord.Y = i;
                    SetConsoleCursorPosition(mHandle, coord);
                    cout << mBuffor1[i][j];
                }
            }
        }
        coord.X = coord.Y = 0;
        SetConsoleCursorPosition(mHandle, coord);
    }
    void clear() {
        for (int i=0; i<mRows; i++) {
            for (int j=0;j<mCols;j++) {
                mBuffor2[i][j] = ' ';
            }
        }
    }
    void gotoXY(int row, int column) {
        if (row >= mRows)
            x = 0;
        else
            x = row;
        if (column >= mCols)
            y = 0;
        else
            y = column;
    }
    bool print(char c) {
        if (x >= mRows || y>=mCols)
            return false;
        mBuffor2[x][y]=c;
        ++y;
        return true;
    }
    bool print(const char* str) {
        const char *c=str;
        while (*c!='\0') {
            if (!print(*c))
                return false;
            ++c;
        }
        return true;
    }

private:
    int mRows;
    int mCols;
    int x, y;
    char **mBuffor1, **mBuffor2;
    HANDLE mHandle;

};

int main()
{
    Bufor b(10, 40);
    int i = 0;
    while (true) {
        b.clear();
        if (i>=10)
            i=0;
        b.gotoXY(i,i);
        ++i;
        b.print("ala ma kota");
        b.swap();
        getch();
    }
    return 0;
}
komentarz 10 marca 2017 przez Jakub 0 Pasjonat (23,120 p.)

dzięki , działa płynnie . Choć muszę go sobie jeszcze ułożyć w głowie bo sposób jest o wiele trudniejszy niż ten który ja zastosowałem wink

+1 głos
odpowiedź 10 marca 2017 przez adrian17 Ekspert (344,860 p.)

Słyszałem o podwójnym buforowaniu , jednak nie wiem jak się za to zabrać . 

...piszesz w konsoli. "Podwójne buforowanie" to termin nie mający żadnego związku z pisaniem w konsoli.

(A sama konsola już buforuje to, co piszesz.)

komentarz 10 marca 2017 przez Jakub 0 Pasjonat (23,120 p.)
nie wiedziałem :) No ale jakiś sposób musi być ...
1
komentarz 10 marca 2017 przez tangarr Mędrzec (154,860 p.)
Termin podwójne buforowanie oznacza pisanie do osobnego "bufora" zamiast do konsoli.
Zamiana buforu polega na przepisaniu całego bufora do konsoli (dla zwiększenia szybkości można użyć dwóch buforów: nowa_klatka, stara_klatka i drukować na konsoli tylko różnice pomiędzy nimi)

Aby stworzyć taki bufor musisz utworzyć macierz o wielkości takiej samej jak konsola.
Musisz stworzyć napisać funkcje do pisania po buforze zamiast po konsoli.
Używając tego podejścia nie czyścisz ekranu, tylko poruszasz się po nim funkcją SetConsoleCursorPosition (windows.h).
komentarz 10 marca 2017 przez Jakub 0 Pasjonat (23,120 p.)
Dzięki za podanie funkcji z biblioteki windows , aczkolwiek mój program działa podobnie , najpierw odpowiednie tablice zyskują jakąś wartość a potem są wypisywane na ekran , nie wiem czy czy da się wykorzystać podwójne buforowanie dla takiego algorytmu poruszania się jaki użyłem w tej grze (tu lin do mojego innego wpisu) : https://forum.pasja-informatyki.pl/233582/nietypowy-sposob-tworzenia-mapy-w-c#a233607
coś popróbuje a najwyżej zastosuje inny algorytm , pozdrawiam i dzięki za pomoc (:
2
komentarz 10 marca 2017 przez adrian17 Ekspert (344,860 p.)
Jak mówiłem, większość terminali juz buforuje tekst (zazwyczaj aż końca linii), więc to duplikowanie wysiłku. Możliwe wręcz, że spamowanie SetConsoleCursorPosition będzie wolniejsze niż jednokrotny skok na górę konsoli i nadpisanie całego tekstu za jednym zamachem.

(sugeruję tylko zastąpić endl przez '\n', żeby nie wymuszać zrzucenia bufora, tylko zostawić decyzję terminalowi. Ogólnie endl jest odradzany.)
1
komentarz 10 marca 2017 przez tangarr Mędrzec (154,860 p.)

Zrobiłem szybki eksperyment.

void swap2() {
        COORD coord;
        char **tmp = mBuffor1;
        mBuffor1 = mBuffor2;
        mBuffor2 = tmp;
        coord.X = coord.Y = 0;
        SetConsoleCursorPosition(mHandle, coord);
        for (int i=0; i<mRows; i++) {
            cout << std::string(mBuffor1[i], mCols) << "\n";
        }
        SetConsoleCursorPosition(mHandle, coord);
    }
    void swap3() {
        COORD coord;
        char **tmp = mBuffor1;
        mBuffor1 = mBuffor2;
        mBuffor2 = tmp;
        coord.X = coord.Y = 0;
        std::string napis;
        SetConsoleCursorPosition(mHandle, coord);
        for (int i=0; i<mRows; i++) {
            napis += std::string(mBuffor1[i], mCols) + "\n";
        }
        cout << napis;
        SetConsoleCursorPosition(mHandle, coord);
    }
    void swap4() {
        COORD coord;
        char **tmp = mBuffor1;
        mBuffor1 = mBuffor2;
        mBuffor2 = tmp;
        coord.X = coord.Y = 0;
        std::string napis;
        SetConsoleCursorPosition(mHandle, coord);
        for (int i=0; i<mRows; i++) {
            napis += std::string(mBuffor1[i], mCols) + "\n";
        }
        printf("%s", napis.c_str());
        SetConsoleCursorPosition(mHandle, coord);
    }

swap2 - wypisywanie linia po linii - wydajność taka sama
swap3 - wypisywanie całego bufora - około 10x wzrost wydajności
swap4 - zamiana cout na printf - największe zaskoczenie - 15x spadek wydajności

Rezultaty warte zapamiętania.

1
komentarz 10 marca 2017 przez adrian17 Ekspert (344,860 p.)
Well, u mnie printf (test4) jest najszybszy...

https://puu.sh/uD9Bl/2ccd8a410e.mp4

Podobne pytania

0 głosów
2 odpowiedzi 250 wizyt
pytanie zadane 11 maja 2016 w Nasze projekty przez swetroniusz Użytkownik (540 p.)
+2 głosów
1 odpowiedź 397 wizyt
pytanie zadane 24 września 2016 w C i C++ przez MultiGumis Początkujący (330 p.)
0 głosów
1 odpowiedź 299 wizyt
pytanie zadane 23 listopada 2020 w C i C++ przez amr323 Nowicjusz (120 p.)

92,579 zapytań

141,432 odpowiedzi

319,664 komentarzy

61,964 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...