Gra wąż

Odpowiedz Nowy wątek
2020-09-16 17:09

Rejestracja: 1 rok temu

Ostatnio: 1 dzień temu

Lokalizacja: Polska

0

Witajcie

Ostatnio zrobiłem popularną grę węża :).

Pozdrawiam

Ps. Proszę o opinie i komentarze. Czy wam się podoba czy też nie :).


Nieoszlifowany diament
W czym to kompilowałeś? Lazarus czy Delphi i w jakich wersjach ? - katakrowa 2020-09-16 19:13

Pozostało 580 znaków

2020-09-16 17:45

Rejestracja: 4 lata temu

Ostatnio: 1 godzina temu

Lokalizacja: Futurama

2

Wrzuć kod na jakiegoś vcsa, ja w żadnym wypadku nie ściągnął bym nic wrzuconego w archiwum


Bite my shiny metal ass!
Life throws you an error code like that, you don't have the luxury of a ~ZnVja2luZw==~ pop-up explanation

http://burdzi0.best
Nie przesadzaj, źródła spokojnie można opakować w zwykły .zip i udostępnić – to w sumie standardowa procedura dzielenia się projektami na oficjalnym forum Free Pascala. No chyba że pakuje się do niego pliki wykonywalne, to wtedy lekko cuchnie podstępem. ;) - furious programming 2020-09-18 22:32
@furious programming: być może, jestem nieufny, to już nie ten internet co kiedyś - Burdzi0 2020-09-18 22:58

Pozostało 580 znaków

tsz
2020-09-16 17:54
tsz

Rejestracja: 2 miesiące temu

Ostatnio: 2 minuty temu

1

Pascal i wcięcia na 5 spacji? Nonkonformista.

Nie na pięć spacji. Zauważ jaki jest wzór – wcięcie jest wyrównane do słowa kluczowego z poprzedniej linijki. Im dłuższe słowo, tym większe wcięcie. Ochydne formatowanie, fuj… :/ - furious programming 2020-09-16 18:05
@furious programming: W każdym razie trochę mindfuck. - PerlMonk wczoraj, 09:12
Dla mnie spory mindfuck. - furious programming wczoraj, 17:01

Pozostało 580 znaków

2020-09-16 17:57

Rejestracja: 1 rok temu

Ostatnio: 3 minuty temu

Lokalizacja: Silesia

1
procedure DrawingSnakeAndFood(wsp_x,wsp_y: integer);
var
   wi,wj: byte;
   point_x1,point_y1,point_x2,point_y2: integer;
   wl,wk: integer;
begin
     point_x1 := 0; point_y1 := 0;
     for wi := 1 to 10 do
        begin
             for wj := 1 to 10 do
                begin
                     point_y1 := wsp_y * (wi - 1);
                     point_y2 := point_y1 + wsp_y;
                     if wi in [2..3] then
                       begin
                            point_y2 := point_y2 - 1;
                            if wi = 3 then
                              point_y1 := point_y1 - 1
                       end
                     else
                         if wi in [4..6] then
                           begin
                                point_y1 := point_y1 - 1;
                                point_y2 := point_y2 - 1;
                                if wi = 6 then
                                  point_y2 := point_y2 - 1
                           end
                         else
                             if wi = 10 then
                               point_y1 := point_y1 - 3
                             else
                                 if wi in [7..9] then
                                   begin
                                        point_y1 := point_y1 - 2;
                                        point_y2 := point_y2 - 2;
                                        if wi = 9 then
                                          point_y2 := point_y2 - 1
                                   end;

                     point_x1 := wsp_x * (wj - 1);
                     point_x2 := point_x1 + wsp_x;

                     if wj in [6..10] then
                       begin
                            if wj = 6 then
                              point_x2 := point_x2 - 1
                            else
                                begin
                                     point_x1 := point_x1 - 1;
                                     point_x2 := point_x2 - 1
                                end
                       end;

                    if board[wi,wj] = 'X' then
                      begin
                           setcolor(4);
                           rectangle(point_x1,point_y1,point_x2,point_y2);
                           setcolor(10);
                           circle(point_x1 + (wsp_x div 2),point_y1 + (wsp_y div 2),wsp_y div 2);
                           putpixel(point_x1 + (wsp_x div 2),point_y1 + (wsp_y div 2),12)
                      end
                    else
                        if board[wi,wj] = '0' then
                          begin
                               setcolor(2);
                               rectangle(point_x1,point_y1,point_x2,point_y2);
                               setcolor(13);
                               circle(point_x1 + (wsp_x div 2),point_y1 + (wsp_y div 2),wsp_y div 2);
                               putpixel(point_x1 + (wsp_x div 2),point_y1 + (wsp_y div 2),11)
                          end
                end
        end
end;

Podoba mi się, Takie nieoczywiste


Pozostało 580 znaków

2020-09-16 18:26

Rejestracja: 5 lat temu

Ostatnio: 4 godziny temu

Lokalizacja: Chorzów

4

Działa ale ...

  1. Strasznie miga. Niepotrzebnie przerysowujesz cały ekran. Czyścisz i rysujesz na nowo. Tak można robić ale tylko gdy grafikę buforujesz.
  2. Procedura rysowania planszy jest "kosmiczna". Widać, że to efekt końcowy zgadywania tak długo aż zadziała a nie przemyśleń jak ma to działać. Wystarczyła pojedyncza pętla bez wszelkich ifów ... rysująca węża na podstawie tablicy i 1 linijka rysująca jedzenie ( wywołanie procedury rys. jedzenie ). ( przecież i tak kasujesz obraz op każdym kroku ). Co jakby plansza była 1000x1000 wykonywałbyś te operacje if'y, pypisania itp ... milion razy na każdą klatkę?

Skoro już to napisałeś i działa to teraz przemyśl cały algorytm jeszcze raz i napisz ponownie ale tym razem poprawnie. Brawo za dobre chęci ale obecna wersja niestety nie zasługuje na pochwałę od strony planowania i samego kodu.
Jeśli będziesz miał pytania to pomogę.


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.

Pozostało 580 znaków

2020-09-16 18:40
Moderator Delphi/Pascal

Rejestracja: 8 lat temu

Ostatnio: 1 minuta temu

Lokalizacja: Tuchów

3

Przy rysowaniu węża istotne jest odmalowywanie tylko tych fragmentów, które uległy zmianie – dotyczy to zarówno węża, jak i interfejsu (punktów, długości itp.). W przypadku konsolowych aplikacji jest to banalne, bo skasowanie bieżącego znaku i namalowanie nowego to po prostu namalowanie nowego – stary znika. Jeśli chodzi o węża, to przemalowuje się go tylko wtedy, gdy się poruszył, a jeśli się poruszył, to zamalowujesz jego ogon i malujesz głowę w nowym miejscu.

To tak w skrócie. I popraw te wcięcia, bo kod wygląda z nimi tragicznie! W Pascalu używa się wcięć dwuznakowych, we wszystkich konstrukcjach kodu. Są wyjątki, ale póki nie potrafisz formatować zwyczajnego kodu w praktycznie w ogóle, to zostawmy temat wyjątków na kiedyś indziej.


edytowany 2x, ostatnio: furious programming, 2020-09-16 18:40
Odmalowywanie tylko miejsc, które się zmieniły jest problematyczne. Jak bawiłem się w pisanie gierek w WinAPI to szybko zacząłem stosować double-buffering. Efekt ten sam, tylko zużycie procesora skacze z 1% do 2%, ale co z tego :D - tsz 2020-09-16 18:43
Nie jest problematyczne – przynajmniej nie w przypadku węża. Wiem coś o tym, bo kilka lat temu takiego pisałem – co prawda w wersji znakowej (normalnie w konsoli), ale to wiele nie zmienia. :P - furious programming 2020-09-17 00:04

Pozostało 580 znaków

2020-09-16 19:08

Rejestracja: 5 lat temu

Ostatnio: 4 godziny temu

Lokalizacja: Chorzów

2

Generalnie stosując pascal'ową bibliotekę graph / BGI tak należałoby zrobić ( rysowaćtylko zmiany ) bo w sumie nie ma innej możliwości - ale to z wielu powodów problematyczna metoda.. Z tego co pamiętam to w Graph.pas nie było obsługi buforowania aczkolwiek tego typu sztuczek już od lat się nie stosuje bo przekopiowanie bufora do pamięci 20 razy na sek. to czas właściwie pomijalny a metoda taka rozwiązuje wszelkie problemy z nachodzeniem się obiektów, kolorowym tłem ( np. obrazek ) i wiele innych...
Najbardziej podstawowe funkcje do rysowania wykorzystywane w WinApi to SetDIBitsToDevice + GetDC jak o nich poczytasz to będziesz miał solidną bazę do dalszych zabaw.
Funkcje wstępnie wyglądają strasznie ale w praktyce nie jest trudno.

W sumie całość sprowadza się do ( delphi / lazarus ):


procedure Rysuj();
const

  maxBufferX = 1920 ;
  maxBufferY = 1080 ;

Type

  // Twój bufor ekranu jeden typ liniowy, drugi z dostępem do poszczególnych składowych kolorów.
  //
  TScreen = array [ 0 .. maxBufferX*maxBufferY ] of Dword ; // planujemy układ kolorów RGBA
  TScreenRGBA = Array [ 0 .. maxBufferX*maxBufferY ] of record 
    R, G, B, A :byte ;
  end ;

Var

  canvasHandle : HWND ;
  _bmpinf:TbitmapInfoHeader;
  _bmpin:TBITMAPINFO;
  _rgbq:array [0..0]of TRGBQUAD;

  Screen : TScreen ;
  ScreenRGBA : TScreenRGBA absolute Screen ; // absolute rzutuje obszar pamięci na Screen  

  x, y : integer ;

begin

  //
  // Inicjujemy niezbędne struktury opisujące parametry bufora obrazu
  //

  canvasHandle := [HWND] ; // Tu przypisać HWND okna w którym rysujemy.

  _bmpinf.bisize:=sizeof(_bmpinf);
  _bmpinf.biwidth:=MaxX;
  _bmpinf.biheight:=MaxY;
  _bmpinf.biplanes:=1;
  _bmpinf.bibitcount:=32;
  _bmpinf.bicompression:=0;
  _bmpinf.bisizeimage:=0;
  _bmpinf.biXpelspermeter:=0;
  _bmpinf.biYpelspermeter:=0;
  _bmpinf.biclrused:=0;
  _bmpinf.biclrimportant:=0;
  _rgbq[0].rgbblue:=1;
  _rgbq[0].rgbgreen:=2;
  _rgbq[0].rgbred:=3;
  _rgbq[0].rgbreserved:=0;
  _bmpin.bmiheader:=_bmpinf;
  _bmpin.bmicolors[0]:=_rgbq[0];

  // 
  // Tutaj rysujesz cokolwiek w bufrze ...
  // np. wypełnienie losowymi odcieniami czerwonego
  //

  for x := 0 to maxBufferX - 1 do  
  for y := 0 to maxBufferY - 1 do
  begin
    ScreenRGBA [ x + maxBufferX * Y ].R = random(255) ;
  end;

  //
  // Wyrzucasz na ekran / do okna.
  //

  SetDIBitsToDevice( GetDc ( canvasHandle ), 0, 0 ,maxBufferX, maxBufferY, 0, 0, 0, maxBufferY, @Screen[0], _bmpin,DIB_RGB_COLORS ) ;

end;

czyli właśnie kopiowanie zawartości bufora na ekran ... Niestety wszystko rysować trzeba samemu lub użyć jakiejś biblioteki.


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.
edytowany 4x, ostatnio: furious programming, 2020-09-17 00:05

Pozostało 580 znaków

2020-09-16 19:56

Rejestracja: 5 lat temu

Ostatnio: 4 godziny temu

Lokalizacja: Chorzów

0

W załączniku przygotowałem Ci przykładowy program gotowy do kompilacji w Lazarus.

screenshot-20200916200129.png


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.
edytowany 1x, ostatnio: katakrowa, 2020-09-16 20:01

Pozostało 580 znaków

2020-09-17 00:14
Moderator Delphi/Pascal

Rejestracja: 8 lat temu

Ostatnio: 1 minuta temu

Lokalizacja: Tuchów

0

Standardowe wykorzysta tylnego bufora to nie jest jedyny sposób na przyspieszenie renderowania. W poważniejszych projektach bazujących na FCL i LCL (np. mój Deep Platformer lub ostatnio Richtris), można spokojnie korzystać z natywnego GDI+ i wydajność jest całkiem niezła (tym bardziej w porównaniu do Linuchów) i tam bitmapy jako bufory sprawdzają się super.

Tutaj problemem jest to, że rysowanie odbywa się bezpośrednio na docelowym płótnie (obojętne na którym). Ten problem można rozwiązać poprzez zamalowanie ”nieważnego” kafla zwykłym Rectangle i namalowanie go od nowa. Taki sposób i tak znacząco przyspieszy proces renderowania, dzięki czemu nic nie będzie migać. Oczywiście o ile gra bazuje na tabelarycznie zbudowanej planszy i wężu przesuwającym się o cały kafel (a nie o piksel/kilka pikseli w każdej klatce).

W każdym razie zawsze da się zrobić lepiej niż malować wszystko od nowa. ;)


edytowany 2x, ostatnio: furious programming, 2020-09-17 00:15

Pozostało 580 znaków

2020-09-18 22:10

Rejestracja: 1 rok temu

Ostatnio: 1 dzień temu

Lokalizacja: Polska

0

Poprawiłem zgodnie z sugestiami :).


Nieoszlifowany diament
Program napisany i skompilowany w Free Pascalu. - Adept123 2020-09-18 22:12
Plik rar zawiera plik wykonywalny exe w celu pokazania efektu końcowego. gdyż nie każdy ma kompilator free pascala i tym samym nie może zboczyć wyniku. - Adept123 wczoraj, 09:10

Pozostało 580 znaków

Odpowiedz

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